1 | /*
|
---|
2 | -----------------------------------------------------------------------------
|
---|
3 | This source file is part of OGRE
|
---|
4 | (Object-oriented Graphics Rendering Engine)
|
---|
5 | For the latest info, see http://www.ogre3d.org/
|
---|
6 |
|
---|
7 | Copyright (c) 2000-2005 The OGRE Team
|
---|
8 | Also see acknowledgements in Readme.html
|
---|
9 |
|
---|
10 | You may use this sample code for anything you like, it is not covered by the
|
---|
11 | LGPL like the rest of the engine.
|
---|
12 | -----------------------------------------------------------------------------
|
---|
13 | */
|
---|
14 |
|
---|
15 |
|
---|
16 | #include "WaterMesh.h"
|
---|
17 |
|
---|
18 | #define ANIMATIONS_PER_SECOND 100.0f
|
---|
19 |
|
---|
20 | WaterMesh::WaterMesh(const String& meshName, Real planeSize, int complexity)
|
---|
21 | {
|
---|
22 | int x,y,b; // I prefer to initialize for() variables inside it, but VC doesn't like it ;(
|
---|
23 |
|
---|
24 | this->meshName = meshName ;
|
---|
25 | this->complexity = complexity ;
|
---|
26 | numFaces = 2 * complexity * complexity;
|
---|
27 | numVertices = (complexity + 1) * (complexity + 1) ;
|
---|
28 | lastTimeStamp = 0 ;
|
---|
29 | lastAnimationTimeStamp = 0;
|
---|
30 | lastFrameTime = 0 ;
|
---|
31 |
|
---|
32 | // initialize algorithm parameters
|
---|
33 | PARAM_C = 0.3f ; // ripple speed
|
---|
34 | PARAM_D = 0.4f ; // distance
|
---|
35 | PARAM_U = 0.05f ; // viscosity
|
---|
36 | PARAM_T = 0.13f ; // time
|
---|
37 | useFakeNormals = false ;
|
---|
38 |
|
---|
39 | // allocate space for normal calculation
|
---|
40 | vNormals = new Vector3[numVertices];
|
---|
41 |
|
---|
42 | // create mesh and submesh
|
---|
43 | mesh = MeshManager::getSingleton().createManual(meshName,
|
---|
44 | ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
|
---|
45 | subMesh = mesh->createSubMesh();
|
---|
46 | subMesh->useSharedVertices=false;
|
---|
47 |
|
---|
48 | // Vertex buffers
|
---|
49 | subMesh->vertexData = new VertexData();
|
---|
50 | subMesh->vertexData->vertexStart = 0;
|
---|
51 | subMesh->vertexData->vertexCount = numVertices;
|
---|
52 |
|
---|
53 | VertexDeclaration* vdecl = subMesh->vertexData->vertexDeclaration;
|
---|
54 | VertexBufferBinding* vbind = subMesh->vertexData->vertexBufferBinding;
|
---|
55 |
|
---|
56 |
|
---|
57 | vdecl->addElement(0, 0, VET_FLOAT3, VES_POSITION);
|
---|
58 | vdecl->addElement(1, 0, VET_FLOAT3, VES_NORMAL);
|
---|
59 | vdecl->addElement(2, 0, VET_FLOAT2, VES_TEXTURE_COORDINATES);
|
---|
60 |
|
---|
61 | // Prepare buffer for positions - todo: first attempt, slow
|
---|
62 | posVertexBuffer =
|
---|
63 | HardwareBufferManager::getSingleton().createVertexBuffer(
|
---|
64 | 3*sizeof(float),
|
---|
65 | numVertices,
|
---|
66 | HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE);
|
---|
67 | vbind->setBinding(0, posVertexBuffer);
|
---|
68 |
|
---|
69 | // Prepare buffer for normals - write only
|
---|
70 | normVertexBuffer =
|
---|
71 | HardwareBufferManager::getSingleton().createVertexBuffer(
|
---|
72 | 3*sizeof(float),
|
---|
73 | numVertices,
|
---|
74 | HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE);
|
---|
75 | vbind->setBinding(1, normVertexBuffer);
|
---|
76 |
|
---|
77 | // Prepare texture coords buffer - static one
|
---|
78 | // todo: optimize to write directly into buffer
|
---|
79 | float *texcoordsBufData = new float[numVertices*2];
|
---|
80 | for(y=0;y<=complexity;y++) {
|
---|
81 | for(x=0;x<=complexity;x++) {
|
---|
82 | texcoordsBufData[2*(y*(complexity+1)+x)+0] = (float)x / complexity ;
|
---|
83 | texcoordsBufData[2*(y*(complexity+1)+x)+1] = 1.0f - ((float)y / (complexity)) ;
|
---|
84 | }
|
---|
85 | }
|
---|
86 | texcoordsVertexBuffer =
|
---|
87 | HardwareBufferManager::getSingleton().createVertexBuffer(
|
---|
88 | 2*sizeof(float),
|
---|
89 | numVertices,
|
---|
90 | HardwareBuffer::HBU_STATIC_WRITE_ONLY);
|
---|
91 | texcoordsVertexBuffer->writeData(0,
|
---|
92 | texcoordsVertexBuffer->getSizeInBytes(),
|
---|
93 | texcoordsBufData,
|
---|
94 | true); // true?
|
---|
95 | delete [] texcoordsBufData;
|
---|
96 | vbind->setBinding(2, texcoordsVertexBuffer);
|
---|
97 |
|
---|
98 | // Prepare buffer for indices
|
---|
99 | indexBuffer =
|
---|
100 | HardwareBufferManager::getSingleton().createIndexBuffer(
|
---|
101 | HardwareIndexBuffer::IT_16BIT,
|
---|
102 | 3*numFaces,
|
---|
103 | HardwareBuffer::HBU_STATIC, true);
|
---|
104 | unsigned short *faceVertexIndices = (unsigned short*)
|
---|
105 | indexBuffer->lock(0, numFaces*3*2, HardwareBuffer::HBL_DISCARD);
|
---|
106 | for(y=0 ; y<complexity ; y++) {
|
---|
107 | for(int x=0 ; x<complexity ; x++) {
|
---|
108 | unsigned short *twoface = faceVertexIndices + (y*complexity+x)*2*3;
|
---|
109 | int p0 = y*(complexity+1) + x ;
|
---|
110 | int p1 = y*(complexity+1) + x + 1 ;
|
---|
111 | int p2 = (y+1)*(complexity+1) + x ;
|
---|
112 | int p3 = (y+1)*(complexity+1) + x + 1 ;
|
---|
113 | twoface[0]=p2; //first tri
|
---|
114 | twoface[1]=p1;
|
---|
115 | twoface[2]=p0;
|
---|
116 | twoface[3]=p2; //second tri
|
---|
117 | twoface[4]=p3;
|
---|
118 | twoface[5]=p1;
|
---|
119 | }
|
---|
120 | }
|
---|
121 | indexBuffer->unlock();
|
---|
122 | // Set index buffer for this submesh
|
---|
123 | subMesh->indexData->indexBuffer = indexBuffer;
|
---|
124 | subMesh->indexData->indexStart = 0;
|
---|
125 | subMesh->indexData->indexCount = 3*numFaces;
|
---|
126 |
|
---|
127 | /* prepare vertex positions
|
---|
128 | * note - we use 3 vertex buffers, since algorighm uses two last phases
|
---|
129 | * to calculate the next one
|
---|
130 | */
|
---|
131 | for(b=0;b<3;b++) {
|
---|
132 | vertexBuffers[b] = new float[numVertices * 3] ;
|
---|
133 | for(y=0;y<=complexity;y++) {
|
---|
134 | for(x=0;x<=complexity;x++) {
|
---|
135 | int numPoint = y*(complexity+1) + x ;
|
---|
136 | float* vertex = vertexBuffers[b] + 3*numPoint ;
|
---|
137 | vertex[0]=(float)(x) / (float)(complexity) * (float) planeSize ;
|
---|
138 | vertex[1]= 0 ; // rand() % 30 ;
|
---|
139 | vertex[2]=(float)(y) / (float)(complexity) * (float) planeSize ;
|
---|
140 | }
|
---|
141 | }
|
---|
142 | }
|
---|
143 |
|
---|
144 | AxisAlignedBox meshBounds(0,0,0,
|
---|
145 | planeSize,0, planeSize);
|
---|
146 | mesh->_setBounds(meshBounds);
|
---|
147 |
|
---|
148 | currentBuffNumber = 0 ;
|
---|
149 | posVertexBuffer->writeData(0,
|
---|
150 | posVertexBuffer->getSizeInBytes(), // size
|
---|
151 | vertexBuffers[currentBuffNumber], // source
|
---|
152 | true); // discard?
|
---|
153 |
|
---|
154 | mesh->load();
|
---|
155 | mesh->touch();
|
---|
156 | }
|
---|
157 | /* ========================================================================= */
|
---|
158 | WaterMesh::~WaterMesh ()
|
---|
159 | {
|
---|
160 | delete[] vertexBuffers[0];
|
---|
161 | delete[] vertexBuffers[1];
|
---|
162 | delete[] vertexBuffers[2];
|
---|
163 |
|
---|
164 | delete[] vNormals;
|
---|
165 | }
|
---|
166 | /* ========================================================================= */
|
---|
167 | void WaterMesh::push(Real x, Real y, Real depth, bool absolute)
|
---|
168 | {
|
---|
169 | float *buf = vertexBuffers[currentBuffNumber]+1 ;
|
---|
170 | // scale pressure according to time passed
|
---|
171 | depth = depth * lastFrameTime * ANIMATIONS_PER_SECOND ;
|
---|
172 | #define _PREP(addx,addy) { \
|
---|
173 | float *vertex=buf+3*((int)(y+addy)*(complexity+1)+(int)(x+addx)) ; \
|
---|
174 | float diffy = y - floor(y+addy); \
|
---|
175 | float diffx = x - floor(x+addx); \
|
---|
176 | float dist=sqrt(diffy*diffy + diffx*diffx) ; \
|
---|
177 | float power = 1 - dist ; \
|
---|
178 | if (power<0) \
|
---|
179 | power = 0; \
|
---|
180 | if (absolute) \
|
---|
181 | *vertex = depth*power ; \
|
---|
182 | else \
|
---|
183 | *vertex += depth*power ; \
|
---|
184 | } /* #define */
|
---|
185 | _PREP(0,0);
|
---|
186 | _PREP(0,1);
|
---|
187 | _PREP(1,0);
|
---|
188 | _PREP(1,1);
|
---|
189 | #undef _PREP
|
---|
190 | }
|
---|
191 | /* ========================================================================= */
|
---|
192 | Real WaterMesh::getHeight(Real x, Real y)
|
---|
193 | {
|
---|
194 | #define hat(_x,_y) buf[3*((int)_y*(complexity+1)+(int)(_x))]
|
---|
195 | float *buf = vertexBuffers[currentBuffNumber] ;
|
---|
196 | Real xa = floor(x);
|
---|
197 | Real xb = xa + 1 ;
|
---|
198 | Real ya = floor(y);
|
---|
199 | Real yb = ya + 1 ;
|
---|
200 | float *vertex = buf + 3*((int)(ya)*(complexity+1)+(int)(xa));
|
---|
201 | Real yaxavg = hat(xa,ya) * (1.0f-fabs(xa-x)) + hat(xb,ya) * (1.0f-fabs(xb-x));
|
---|
202 | Real ybxavg = hat(xa,yb) * (1.0f-fabs(xa-x)) + hat(xb,yb) * (1.0f-fabs(xb-x));
|
---|
203 | Real yavg = yaxavg * (1.0f-fabs(ya-y)) + ybxavg * (1.0f-fabs(yb-y)) ;
|
---|
204 | return yavg ;
|
---|
205 | }
|
---|
206 | /* ========================================================================= */
|
---|
207 | void WaterMesh::calculateFakeNormals()
|
---|
208 | {
|
---|
209 | int x,y;
|
---|
210 | float *buf = vertexBuffers[currentBuffNumber] + 1;
|
---|
211 | float *pNormals = (float*) normVertexBuffer->lock(
|
---|
212 | 0,normVertexBuffer->getSizeInBytes(), HardwareBuffer::HBL_DISCARD);
|
---|
213 | for(y=1;y<complexity;y++) {
|
---|
214 | float *nrow = pNormals + 3*y*(complexity+1);
|
---|
215 | float *row = buf + 3*y*(complexity+1) ;
|
---|
216 | float *rowup = buf + 3*(y-1)*(complexity+1) ;
|
---|
217 | float *rowdown = buf + 3*(y+1)*(complexity+1) ;
|
---|
218 | for(x=1;x<complexity;x++) {
|
---|
219 | Real xdiff = row[3*x+3] - row[3*x-3] ;
|
---|
220 | Real ydiff = rowup[3*x] - rowdown[3*x-3] ;
|
---|
221 | Vector3 norm(xdiff,30,ydiff);
|
---|
222 | norm.normalise();
|
---|
223 | nrow[3*x+0] = norm.x;
|
---|
224 | nrow[3*x+1] = norm.y;
|
---|
225 | nrow[3*x+2] = norm.z;
|
---|
226 | }
|
---|
227 | }
|
---|
228 | normVertexBuffer->unlock();
|
---|
229 | }
|
---|
230 | /* ========================================================================= */
|
---|
231 | void WaterMesh::calculateNormals()
|
---|
232 | {
|
---|
233 | int i,x,y;
|
---|
234 | float *buf = vertexBuffers[currentBuffNumber] + 1;
|
---|
235 | // zero normals
|
---|
236 | for(i=0;i<numVertices;i++) {
|
---|
237 | vNormals[i] = Vector3::ZERO;
|
---|
238 | }
|
---|
239 | // first, calculate normals for faces, add them to proper vertices
|
---|
240 | buf = vertexBuffers[currentBuffNumber] ;
|
---|
241 | unsigned short* vinds = (unsigned short*) indexBuffer->lock(
|
---|
242 | 0, indexBuffer->getSizeInBytes(), HardwareBuffer::HBL_READ_ONLY);
|
---|
243 | float *pNormals = (float*) normVertexBuffer->lock(
|
---|
244 | 0, normVertexBuffer->getSizeInBytes(), HardwareBuffer::HBL_DISCARD);
|
---|
245 | for(i=0;i<numFaces;i++) {
|
---|
246 | int p0 = vinds[3*i] ;
|
---|
247 | int p1 = vinds[3*i+1] ;
|
---|
248 | int p2 = vinds[3*i+2] ;
|
---|
249 | Vector3 v0(buf[3*p0], buf[3*p0+1], buf[3*p0+2]);
|
---|
250 | Vector3 v1(buf[3*p1], buf[3*p1+1], buf[3*p1+2]);
|
---|
251 | Vector3 v2(buf[3*p2], buf[3*p2+1], buf[3*p2+2]);
|
---|
252 | Vector3 diff1 = v2 - v1 ;
|
---|
253 | Vector3 diff2 = v0 - v1 ;
|
---|
254 | Vector3 fn = diff1.crossProduct(diff2);
|
---|
255 | vNormals[p0] += fn ;
|
---|
256 | vNormals[p1] += fn ;
|
---|
257 | vNormals[p2] += fn ;
|
---|
258 | }
|
---|
259 | // now normalize vertex normals
|
---|
260 | for(y=0;y<=complexity;y++) {
|
---|
261 | for(x=0;x<=complexity;x++) {
|
---|
262 | int numPoint = y*(complexity+1) + x ;
|
---|
263 | Vector3 n = vNormals[numPoint] ;
|
---|
264 | n.normalise() ;
|
---|
265 | float* normal = pNormals + 3*numPoint ;
|
---|
266 | normal[0]=n.x;
|
---|
267 | normal[1]=n.y;
|
---|
268 | normal[2]=n.z;
|
---|
269 | }
|
---|
270 | }
|
---|
271 | indexBuffer->unlock();
|
---|
272 | normVertexBuffer->unlock();
|
---|
273 | }
|
---|
274 | /* ========================================================================= */
|
---|
275 | void WaterMesh::updateMesh(Real timeSinceLastFrame)
|
---|
276 | {
|
---|
277 | int x, y ;
|
---|
278 |
|
---|
279 | lastFrameTime = timeSinceLastFrame ;
|
---|
280 | lastTimeStamp += timeSinceLastFrame ;
|
---|
281 |
|
---|
282 | // do rendering to get ANIMATIONS_PER_SECOND
|
---|
283 | while(lastAnimationTimeStamp <= lastTimeStamp) {
|
---|
284 |
|
---|
285 | // switch buffer numbers
|
---|
286 | currentBuffNumber = (currentBuffNumber + 1) % 3 ;
|
---|
287 | float *buf = vertexBuffers[currentBuffNumber] + 1 ; // +1 for Y coordinate
|
---|
288 | float *buf1 = vertexBuffers[(currentBuffNumber+2)%3] + 1 ;
|
---|
289 | float *buf2 = vertexBuffers[(currentBuffNumber+1)%3] + 1;
|
---|
290 |
|
---|
291 | /* we use an algorithm from
|
---|
292 | * http://collective.valve-erc.com/index.php?go=water_simulation
|
---|
293 | * The params could be dynamically changed every frame ofcourse
|
---|
294 | */
|
---|
295 | double C = PARAM_C; // ripple speed
|
---|
296 | double D = PARAM_D; // distance
|
---|
297 | double U = PARAM_U; // viscosity
|
---|
298 | double T = PARAM_T; // time
|
---|
299 | Real TERM1 = ( 4.0f - 8.0f*C*C*T*T/(D*D) ) / (U*T+2) ;
|
---|
300 | Real TERM2 = ( U*T-2.0f ) / (U*T+2.0f) ;
|
---|
301 | Real TERM3 = ( 2.0f * C*C*T*T/(D*D) ) / (U*T+2) ;
|
---|
302 | for(y=1;y<complexity;y++) { // don't do anything with border values
|
---|
303 | float *row = buf + 3*y*(complexity+1) ;
|
---|
304 | float *row1 = buf1 + 3*y*(complexity+1) ;
|
---|
305 | float *row1up = buf1 + 3*(y-1)*(complexity+1) ;
|
---|
306 | float *row1down = buf1 + 3*(y+1)*(complexity+1) ;
|
---|
307 | float *row2 = buf2 + 3*y*(complexity+1) ;
|
---|
308 | for(x=1;x<complexity;x++) {
|
---|
309 | row[3*x] = TERM1 * row1[3*x]
|
---|
310 | + TERM2 * row2[3*x]
|
---|
311 | + TERM3 * ( row1[3*x-3] + row1[3*x+3] + row1up[3*x]+row1down[3*x] ) ;
|
---|
312 | }
|
---|
313 | }
|
---|
314 |
|
---|
315 | lastAnimationTimeStamp += (1.0f / ANIMATIONS_PER_SECOND);
|
---|
316 | }
|
---|
317 |
|
---|
318 | if (useFakeNormals) {
|
---|
319 | calculateFakeNormals();
|
---|
320 | } else {
|
---|
321 | calculateNormals();
|
---|
322 | }
|
---|
323 |
|
---|
324 | // set vertex buffer
|
---|
325 | posVertexBuffer->writeData(0,
|
---|
326 | posVertexBuffer->getSizeInBytes(), // size
|
---|
327 | vertexBuffers[currentBuffNumber], // source
|
---|
328 | true); // discard?
|
---|
329 | }
|
---|