I'm trying to follow Sebastian Lague's Fluid simulation video in c++ and OpenGL. I'm at the point where we calculate a propertyGradient
value (timestamp is 14:15).
I'll try to provide all the code that is relevant further down below.
float CalculatePropertyGradient(Vector2 samplePoint, const std::vector<Vector2>& positions, const std::vector<float>& particleProperties, float smoothingRadius, float mass)
{
float propertyGradient = 0.0f;
DensityCalculator calculator(positions, smoothingRadius);
for (int i = 0; i < positions.size(); i++)
{
float dst = (positions[i] - samplePoint).magnitude();
Vector2 dir = (positions[i] - samplePoint) / dst;
float slope = SmoothingKernelDerivative(dst, smoothingRadius);
float density = calculator.CalculateDensity(positions[i]);
Vector2 scaledDir = dir * particleProperties[i];
propertyGradient += -(scaledDir) * slope * mass / density;
}
return propertyGradient;
}
But I'm getting a syntax error in the line:
propertyGradient += -(scaledDir) * slope * mass / density;
under += operator that my Vector2 class doesn't support this operation involving float and vector2
My vector2 class:
class Vector2 {
public:
float X;
float Y;
Vector2(float x, float y) : X(x), Y(y) {}
float magnitude() const {
return sqrt(X * X + Y * Y);
}
Vector2 operator-(const Vector2& other) const {
return Vector2(X - other.X, Y - other.Y);
}
Vector2 operator/(const float& scalar) const {
return Vector2(X / scalar, Y / scalar);
}
Vector2 operator*(const float& right) const {
return Vector2(X * right, Y * right);
}
Vector2 operator-(const float& scalar) const {
return Vector2(X - scalar, Y - scalar);
}
Vector2 operator*(const Vector2& other) const {
return Vector2(X * other.X, Y * other.Y);
}
Vector2 Zero() {
return Vector2(0.0f, 0.0f);
}
Vector2 operator-() const {
return Vector2(-X, -Y);
}
Vector2& operator+=(const float& scalar) {
X += scalar;
Y += scalar;
return *this;
}
};
My density class:
class DensityCalculator {
private:
std::vector<float> densities;
std::vector<Vector2> positions;
float smoothingRadius;
public:
DensityCalculator(const std::vector<Vector2>& positions, float smoothingRadius)
: positions(positions), smoothingRadius(smoothingRadius) {}
void PreCalculateDensities() {
densities.clear();
for (const auto& position : positions) {
densities.push_back(CalculateDensity(position));
}
}
float CalculateDensity(Vector2 position) const {
float density = 0;
const float mass = 1;
for (const auto& p : positions) {
float dst = (p - position).magnitude();
if (dst <= smoothingRadius) {
float influence = SmoothingKernel(smoothingRadius, dst);
density += mass * influence;
}
}
return density;
}
float GetDensity(int index) const {
return densities[index];
}
};
SmoothingKernel and SmoothingKernelDerivative functions:
float SmoothingKernel(float radius, float dst)
{
if (dst < radius)
{
float volume = M_PI * pow(radius, 8) / 4;
float v = std::max(radius * radius - dst * dst, 0.0f);
return ((v * v * v) / volume);
}
else
{
return 0;
}
}
static float SmoothingKernelDerivative(float dst, float radius)
{
if (dst >= radius)
return 0;
float f = radius * radius - dst * dst;
float scale = -24 / (M_PI * pow(radius, 8));
return scale * dst * f * f;
}
Here's the function call in my main function:
for (int i = 0; i < rows; ++i)
{
for (int j = 0; j < cols; ++j) {
float x = distX(mt);
float y = distY(mt);
balls.emplace_back(x, y, 0.0, 0.0, radius);
// Calculate the value of ExampleFunction at the particle's location and store it in particleProperties
float propertyValue = ExampleFunction(Vector2(x, y));
particleProperties.push_back(propertyValue);
}
}
Where ExampleFunction is just
static float ExampleFunction(Vector2(pos))
{
return cos(pos.Y - 3 + sin(pos.X));
}
I've tried declaring the operator += of vector2 as acting on a const object as suggested by another post but i get an error that X and Y must be a modifiable value.
The problem is that currently the overloaded operator+=(const float&)
that you've provided takes the right hand operand which is a float
instead of Vector2
.
Now, the expression scaledDir * mass
is of type Vector2
which means that you're trying to use operator+=
with right hand operand of type Vector2
. But since you haven't provided any such opertor+=
that takes right hand operand of type Vector2
, you get the mentioned error.
To solve this, just provide an overload that takes an operand of type Vector2
. One way of doing this is as shown below:
//----------------------------vvvvvvv---------->changed float to Vector2
Vector2& operator+=(const Vector2& vec) {
X += vec.X;
Y += vec.Y;
return *this;
}