ProtoTracer  1.0
Real-time 3D rendering and animation engine
Loading...
Searching...
No Matches
VectorField2D.cpp
Go to the documentation of this file.
1#include "VectorField2D.h"
2
3VectorField2D::VectorField2D(uint16_t x, uint16_t y)
4 : countX(x), countY(y) {
5 this->vecXP = new int8_t[x * y];
6 this->vecYP = new int8_t[x * y];
7 this->vecDP = new int8_t[x * y];
8 this->vecX = new int8_t[x * y];
9 this->vecY = new int8_t[x * y];
10 this->vecD = new int8_t[x * y];
11}
12
14 delete vecXP;
15 delete vecYP;
16 delete vecDP;
17 delete vecX;
18 delete vecY;
19 delete vecD;
20}
21
23 // Handle edges
24}
25
26void VectorField2D::Diffuse(float viscosity, float dt) {
27 float a = dt * viscosity * (float)countX * (float)countY;
28 float aS = 1.0f + (4.0f * a);
29
30 for (uint32_t i = 0; i < countX * countY; i++) {
31 vecDP[i] = Mathematics::Constrain(vecD[i] - 1, 0, 127);
32 }
33
34 for (int x = 1; x < countX - 1; x++) {
35 for (int y = 1; y < countY - 1; y++) {
36 uint32_t index = x + countX * y;
37 uint32_t top = x + countX * (y - 1);
38 uint32_t bot = x + countX * (y + 1);
39 uint32_t rgt = index + 1;
40 uint32_t lft = index - 1;
41
42 float value = ((float)vecDP[index] + a * ((float)vecD[top] + (float)vecD[bot] + (float)vecD[rgt] + (float)vecD[lft])) / aS;
43
44 vecD[index] = value;
45 }
46 }
47
48 // Boundary();
49}
50
51void VectorField2D::Advect(float dt) {
52 int x0, x1, y0, y1;
53 float s0, s1, t0, t1;
54
55 float dtX = dt * (float)countX;
56 float dtY = dt * (float)countY;
57
58 for (int x = 1; x < countX - 1; x++) {
59 for (int y = 1; y < countY - 1; y++) {
60 uint32_t index = x + countX * y;
61 float xA = (float)x - dtX * (float)vecX[index];
62 float yA = (float)y - dtY * (float)vecY[index];
63
64 if (xA < 0.5f) xA = 0.5f;
65 if (xA > countX + 0.5f) xA = countX + 0.5f;
66 x0 = (int)xA;
67 x1 = x0 + 1;
68
69 if (yA < 0.5f) yA = 0.5f;
70 if (yA > countY + 0.5f) yA = countY + 0.5f;
71 y0 = (int)yA;
72 y1 = y0 + 1;
73
74 s1 = xA - x0;
75 s0 = 1.0f - s1;
76 t1 = yA - y0;
77 t0 = 1.0f - t1;
78
79 float td00 = t0 * (float)vecDP[Mathematics::Constrain(uint32_t(x0 + countX * y0), uint32_t(0), index)];
80 float td01 = t1 * (float)vecDP[Mathematics::Constrain(uint32_t(x0 + countX * y1), uint32_t(0), index)];
81 float td10 = t0 * (float)vecDP[Mathematics::Constrain(uint32_t(x1 + countX * y0), uint32_t(0), index)];
82 float td11 = t1 * (float)vecDP[Mathematics::Constrain(uint32_t(x1 + countX * y1), uint32_t(0), index)];
83
84 float value = s0 * (td00 + td01) + s1 * (td10 + td11);
85
86 vecD[index] = value;
87 }
88 }
89
90 // Boundary();
91}
92
93void VectorField2D::SineField(float ratio, float period, float amplitude) {
94 for (int x = 0; x < countX; x++) {
95 for (int y = 0; y < countY; y++) {
96 float posX = (((float)x) / ((float)countX) - 0.5f) * 2.0f * size.X;
97 float posY = (((float)y) / ((float)countY) - 0.5f) * 2.0f * size.Y;
98
99 uint32_t index = x + countX * y;
100
101 vecX[index] = Mathematics::Constrain(sinf((posX + posY) / (period * 6.28f * 1000.0f) + ratio * 6.28f) * amplitude, -1.0f, 1.0f) * 127.0f;
102 vecY[index] = Mathematics::Constrain(cosf((posX - posY) / (period * 6.28f * 1000.0f) + ratio * 6.28f) * amplitude, -1.0f, 1.0f) * 127.0f;
103 vecD[index] = Mathematics::Constrain((sinf((posX + posY) / (period * 6.28f * 50.0f)) + cosf((posX - posY) / (period * 6.28f * 50.0f))) * amplitude, -1.0f, 1.0f) * 127.0f;
104 }
105 }
106}
107
108void VectorField2D::StepField(float ratio, float period, float intensity) {
109 float offsetX = sinf(ratio * 2.0f * Mathematics::MPI * 2.0f) * period;
110 float offsetY = cosf(ratio * 2.0f * Mathematics::MPI * 2.0f) * period;
111
112 for (int x = 0; x < countX; x++) {
113 for (int y = 0; y < countY; y++) {
114 float posX = (((float)x) / ((float)countX) - 0.5f) * 2.0f * size.X + offsetX;
115 float posY = (((float)y) / ((float)countY) - 0.5f) * 2.0f * size.Y + offsetY;
116
117 uint32_t index = x + countX * y;
118
119 bool xOdd = (int)(posX * 0.3f / (10.0f / period)) % 2;
120 bool yOdd = (int)(posY * 0.3f / (10.0f / period)) % 2;
121
122 vecX[index] = xOdd ? 127 : -128;
123 vecY[index] = yOdd ? 127 : -128;
124 if (xOdd != yOdd) vecD[index] = Mathematics::Constrain(int8_t(vecD[index] + intensity), int8_t(0), int8_t(127));
125 }
126 }
127}
128
129void VectorField2D::MovingSquareField(float ratio, float period, float intensity) {
130 float offsetX = sinf(ratio * 2.0f * Mathematics::MPI * 2.0f) * period;
131 float offsetY = cosf(ratio * 2.0f * Mathematics::MPI * 2.0f) * period;
132
133 for (int x = 0; x < countX; x++) {
134 for (int y = 0; y < countY; y++) {
135 float posX = (((float)x) / ((float)countX) - 0.5f) * 2.0f * size.X + offsetX;
136 float posY = (((float)y) / ((float)countY) - 0.5f) * 2.0f * size.Y + offsetY;
137
138 uint32_t index = x + countX * y;
139
140 if (posX < period / 2.0f && posX > -period / 2.0f && posY < period / 2.0f && posY > -period / 2.0f) {
141 vecD[index] = Mathematics::Constrain(int8_t(vecD[index] + intensity), int8_t(0), int8_t(127));
142 } else {
143 // vecX[index] = -intensity;
144 // vecY[index] = -128;
145 // vecD[index] = 0;
146 }
147 }
148 }
149}
150
151void VectorField2D::SpiralField(float ratio, float period, float amplitude){
152 for(int x = 0; x < countX; x++){
153 for(int y = 0; y < countY; y++){
154 float posX = (((float)x) / ((float)countX) - 0.5f) * 2.0f * size.X;
155 float posY = (((float)y) / ((float)countY) - 0.5f) * 2.0f * size.Y;
156
157 float magn = powf(posX * posX + posY * posY, 0.5f);
158
159 uint32_t index = x + countX * y;
160
161 vecX[index] = Mathematics::Constrain((posX * cosf(2.0f * magn * period / 40.0f)) * 0.01f * amplitude, -1.0f, 1.0f) * 127.0f;
162 vecY[index] = Mathematics::Constrain((posY * sinf(2.0f * magn * period / 40.0f)) * 0.01f * amplitude, -1.0f, 1.0f) * 127.0f;
163 }
164 }
165}
166
167void VectorField2D::ObjectField(Object3D* object, float intensity) {
168 int numTriangles = object->GetTriangleGroup()->GetTriangleCount();
169 Triangle2D** triangles = new Triangle2D*[numTriangles];
170
171 //for each triangle in object, project onto 2d surface, but pass material
172 for (int i = 0; i < numTriangles; i++) {
173 triangles[i] = new Triangle2D(&object->GetTriangleGroup()->GetTriangles()[i]);
174 }
175
176 //create current and next vector fields for advection simulation
177 //do not use pixel groups, use vectors
178
179 for(int x = 0; x < countX; x++){
180 for(int y = 0; y < countY; y++){
181 float posX = (((float)x) / ((float)countX) - 0.5f) * 2.0f * size.X;
182 float posY = (((float)y) / ((float)countY) - 0.5f) * 2.0f * size.Y;
183
184 uint32_t index = x + countX * y;
185
186 float u = 0.0f, v = 0.0f, w = 0.0f;
187 bool didIntersect = false;
188
189 for (int t = 0; t < numTriangles; t++) {
190 if (triangles[t]->DidIntersect(posX, posY, u, v, w)){
191 didIntersect = true;
192
193 break;
194 }
195 }
196
197 if (didIntersect){
198 vecX[index] = 127;
199 vecY[index] = 127;
200 vecD[index] = Mathematics::Constrain(int8_t(vecD[index] + intensity), int8_t(0), int8_t(127));
201 }
202 else{
203 vecX[index] = 0;
204 vecY[index] = 0;
205 vecD[index] = 0;
206 }
207 }
208 }
209
210 for (int i = 0; i < numTriangles; i++){
211 delete triangles[i];
212 }
213
214 delete[] triangles;
215}
216
218 return countX;
219}
220
222 return countY;
223}
224
226 this->density = true;
227}
228
230 this->density = false;
231}
232
233void VectorField2D::SetSize(float sizeX, float sizeY){
234 this->size.X = sizeX;
235 this->size.Y = sizeY;
236}
237
238void VectorField2D::SetPosition(float posX, float posY){
239 this->position.X = posX;
240 this->position.Y = posY;
241}
242
243void VectorField2D::SetRotation(float rotation){
244 this->rotation = rotation;
245}
246
247uint32_t VectorField2D::GetVectorAtPosition(float x, float y, bool &inBounds){
248 Vector2D input = Vector2D(x, y);
249
250 input = input - position + size / 2.0f;
251
252 //rotate input coordinate to local coordinate
253 if (!Mathematics::IsClose(rotation, 0.0f, 0.001f)){
254 input = input.Rotate(rotation, size / 2.0f);//rotate by center coordinate
255 }
256
257 inBounds = input.X > 0 && input.X < size.X &&
258 input.Y > 0 && input.Y < size.Y;
259
260 if (inBounds){
261 float scaleX = Mathematics::Map(input.X, 0.0f, size.X, 0.0f, countX - 1.0f);
262 float scaleY = Mathematics::Map(input.Y, 0.0f, size.Y, 0.0f, countY - 1.0f);
263 uint16_t colX = (uint16_t)floorf(scaleX);
264 uint16_t rowY = (uint16_t)floorf(scaleY);
265
266 //Vector corners
267 uint32_t q11 = rowY * countX + colX;
268 uint32_t q12 = rowY * countX + (colX + 1);
269 uint32_t q21 = (rowY + 1) * countX + colX;
270 uint32_t q22 = (rowY + 1) * countX + (colX + 1);
271
272 //Bilinear interpolation
273 float x1 = colX * (size.X / (float)(countX - 1));
274 float x2 = (colX + 1) * (size.X / (float)(countX - 1));
275 float y1 = rowY * (size.Y / (float)(countY - 1));
276 float y2 = (rowY + 1) * (size.Y / (float)(countY - 1));
277
278 float v11 = vecD[q11];
279 float v12 = vecD[q12];
280 float v21 = vecD[q21];
281 float v22 = vecD[q22];
282
283 float value = Mathematics::BilinearInterpolation(scaleX, scaleY, x1, y1, x2, y2, v11, v12, v21, v22);
284
285 return (uint32_t)value;
286 }
287
288 return 0;
289}
290
291RGBColor VectorField2D::GetRGB(const Vector3D& position, const Vector3D& normal, const Vector3D& uvw){
292 float x = uvw.X * size.X;
293 float y = uvw.Y * size.Y;
294 bool inBounds;
295 uint32_t densityValue = GetVectorAtPosition(x, y, inBounds);
296
297 if (inBounds){
298 float red = (float)densityValue / 127.0f;
299 float green = 0.0f;
300 float blue = 1.0f - (float)densityValue / 127.0f;
301
302 return RGBColor(red, green, blue);
303 }
304
305 return RGBColor(0.0f, 0.0f, 0.0f);
306}
Represents a 2D vector field with various dynamic field effects and rendering capabilities.
virtual Triangle3D * GetTriangles()=0
Retrieves the array of Triangle3D objects representing the triangles.
static float BilinearInterpolation(float scaleX, float scaleY, float x1, float y1, float x2, float y2, float v11, float v12, float v21, float v22)
Performs a bilinear interpolation on a 2D grid.
static const float MPI
Mathematical constant (3.14159265358979323846...).
Definition Mathematics.h:42
static bool IsClose(float v1, float v2, float epsilon)
Checks if two values are close within a specified epsilon.
static T Map(T value, T inLow, T inMax, T outMin, T outMax)
Maps a value from one range to another.
static T Constrain(T value, T minimum, T maximum)
Constrains a value between minimum and maximum.
Represents a 3D object with geometry, material, and transformation data.
Definition Object3D.h:28
ITriangleGroup * GetTriangleGroup()
Retrieves the modifiable geometry of the object.
Definition Object3D.cpp:72
Represents an RGB color and provides methods for manipulation.
Definition RGBColor.h:23
Represents a 2D triangle with support for UV mapping, depth, and intersection testing.
Definition Triangle2D.h:25
Represents a 2D vector (X, Y) and provides methods for vector arithmetic.
Definition Vector2D.h:27
Vector2D Rotate(const float &angle, const Vector2D &offset) const
Rotates this vector by a specified angle (in degrees or radians) around a given offset.
Definition Vector2D.cpp:124
float X
The X-component of the 2D vector.
Definition Vector2D.h:29
float Y
The Y-component of the 2D vector.
Definition Vector2D.h:30
Represents a 3D vector (X, Y, Z) and provides methods for vector arithmetic.
Definition Vector3D.h:26
float X
The X-component of the 3D vector.
Definition Vector3D.h:28
float Y
The Y-component of the 3D vector.
Definition Vector3D.h:29
uint16_t GetCountX()
Retrieves the number of vectors along the X-axis.
int8_t * vecD
Density of current vectors.
int8_t * vecY
Y-component of current vectors.
VectorField2D(uint16_t x, uint16_t y)
Constructs a 2D vector field with specified dimensions.
float rotation
Rotation of the field in degrees.
void RenderVector()
Renders the vector field as arrows.
~VectorField2D()
Destructor for the VectorField2D class.
Vector2D position
Position of the vector field.
void SetRotation(float rotation)
Sets the rotation of the vector field.
void RenderDensity()
Renders the density values of the vector field.
int8_t * vecX
X-component of current vectors.
bool density
Indicates if the field should render density values.
uint16_t GetCountY()
Retrieves the number of vectors along the Y-axis.
int8_t * vecDP
Density of previous vectors.
void SineField(float ratio, float period, float amplitude)
Creates a sine wave effect in the vector field.
void StepField(float ratio, float period, float intensity)
Creates a stepped pattern effect in the vector field.
void Advect(float dt)
Advances the vector field using advection.
uint32_t GetVectorAtPosition(float x, float y, bool &inBounds)
Retrieves the vector at a specific position in the field.
void SetPosition(float posX, float posY)
Sets the position of the vector field.
RGBColor GetRGB(const Vector3D &position, const Vector3D &normal, const Vector3D &uvw) override
Retrieves the RGB color corresponding to a position in the field.
const uint16_t countY
Number of vectors along the Y-axis.
const uint16_t countX
Number of vectors along the X-axis.
int8_t * vecXP
X-component of previous vectors.
void ObjectField(Object3D *object, float intensity)
Generates a field effect based on a 3D object's position and shape.
void MovingSquareField(float ratio, float period, float intensity)
Creates a moving square pattern in the vector field.
void Boundary()
Applies boundary conditions to the vector field.
void SpiralField(float ratio, float period, float amplitude)
Creates a spiral pattern in the vector field.
void Diffuse(float viscosity, float dt)
Performs diffusion on the vector field.
void SetSize(float sizeX, float sizeY)
Sets the size of the vector field.
Vector2D size
Size of the vector field.
int8_t * vecYP
Y-component of previous vectors.