Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/Samples/Water/src/WaterMesh.cpp @ 1

Last change on this file since 1 was 1, checked in by landauf, 17 years ago
File size: 10.7 KB
Line 
1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4    (Object-oriented Graphics Rendering Engine)
5For the latest info, see http://www.ogre3d.org/
6
7Copyright (c) 2000-2006 Torus Knot Software Ltd
8Also see acknowledgements in Readme.html
9
10You may use this sample code for anything you like, it is not covered by the
11LGPL like the rest of the engine.
12-----------------------------------------------------------------------------
13*/
14
15
16#include "WaterMesh.h"
17
18#define ANIMATIONS_PER_SECOND 100.0f
19
20WaterMesh::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/* ========================================================================= */
158WaterMesh::~WaterMesh ()
159{
160        delete[] vertexBuffers[0];
161        delete[] vertexBuffers[1];
162        delete[] vertexBuffers[2];
163
164        delete[] vNormals;
165}
166/* ========================================================================= */
167void 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/* ========================================================================= */
192Real 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        Real yaxavg = hat(xa,ya) * (1.0f-fabs(xa-x)) + hat(xb,ya) * (1.0f-fabs(xb-x));
201        Real ybxavg = hat(xa,yb) * (1.0f-fabs(xa-x)) + hat(xb,yb) * (1.0f-fabs(xb-x));
202        Real yavg = yaxavg * (1.0f-fabs(ya-y)) + ybxavg * (1.0f-fabs(yb-y)) ;
203        return yavg ;
204}
205/* ========================================================================= */
206void WaterMesh::calculateFakeNormals()
207{
208        int x,y;
209        float *buf = vertexBuffers[currentBuffNumber] + 1;
210        float *pNormals = (float*) normVertexBuffer->lock(
211                0,normVertexBuffer->getSizeInBytes(), HardwareBuffer::HBL_DISCARD);
212        for(y=1;y<complexity;y++) {
213                float *nrow = pNormals + 3*y*(complexity+1);
214                float *row = buf + 3*y*(complexity+1) ;
215                float *rowup = buf + 3*(y-1)*(complexity+1) ;
216                float *rowdown = buf + 3*(y+1)*(complexity+1) ;
217                for(x=1;x<complexity;x++) {
218                        Real xdiff = row[3*x+3] - row[3*x-3] ;
219                        Real ydiff = rowup[3*x] - rowdown[3*x-3] ;
220                        Vector3 norm(xdiff,30,ydiff);
221                        norm.normalise();
222                        nrow[3*x+0] = norm.x;
223                        nrow[3*x+1] = norm.y;
224                        nrow[3*x+2] = norm.z;
225                }
226        }
227        normVertexBuffer->unlock();
228}
229/* ========================================================================= */
230void WaterMesh::calculateNormals()
231{
232        int i,x,y;
233        float *buf = vertexBuffers[currentBuffNumber] + 1;
234        // zero normals
235        for(i=0;i<numVertices;i++) {
236                vNormals[i] = Vector3::ZERO;
237        }
238        // first, calculate normals for faces, add them to proper vertices
239        buf = vertexBuffers[currentBuffNumber] ;
240        unsigned short* vinds = (unsigned short*) indexBuffer->lock(
241                0, indexBuffer->getSizeInBytes(), HardwareBuffer::HBL_READ_ONLY);
242        float *pNormals = (float*) normVertexBuffer->lock(
243                0, normVertexBuffer->getSizeInBytes(), HardwareBuffer::HBL_DISCARD);
244        for(i=0;i<numFaces;i++) {
245                int p0 = vinds[3*i] ;
246                int p1 = vinds[3*i+1] ;
247                int p2 = vinds[3*i+2] ;
248                Vector3 v0(buf[3*p0], buf[3*p0+1], buf[3*p0+2]);
249                Vector3 v1(buf[3*p1], buf[3*p1+1], buf[3*p1+2]);
250                Vector3 v2(buf[3*p2], buf[3*p2+1], buf[3*p2+2]);
251                Vector3 diff1 = v2 - v1 ;
252                Vector3 diff2 = v0 - v1 ;
253                Vector3 fn = diff1.crossProduct(diff2);
254                vNormals[p0] += fn ;
255                vNormals[p1] += fn ;
256                vNormals[p2] += fn ;
257        }
258        // now normalize vertex normals
259        for(y=0;y<=complexity;y++) {
260                for(x=0;x<=complexity;x++) {
261                        int numPoint = y*(complexity+1) + x ;
262                        Vector3 n = vNormals[numPoint] ;
263                        n.normalise() ;
264                        float* normal = pNormals + 3*numPoint ;
265                        normal[0]=n.x;
266                        normal[1]=n.y;
267                        normal[2]=n.z;
268                }
269        }
270        indexBuffer->unlock();
271        normVertexBuffer->unlock();
272}
273/* ========================================================================= */
274void WaterMesh::updateMesh(Real timeSinceLastFrame)
275{
276        int x, y ;
277
278        lastFrameTime = timeSinceLastFrame ;
279        lastTimeStamp += timeSinceLastFrame ;
280
281        // do rendering to get ANIMATIONS_PER_SECOND
282        while(lastAnimationTimeStamp <= lastTimeStamp) {
283
284                // switch buffer numbers
285                currentBuffNumber = (currentBuffNumber + 1) % 3 ;
286                float *buf = vertexBuffers[currentBuffNumber] + 1 ; // +1 for Y coordinate
287                float *buf1 = vertexBuffers[(currentBuffNumber+2)%3] + 1 ;
288                float *buf2 = vertexBuffers[(currentBuffNumber+1)%3] + 1;
289
290                /* we use an algorithm from
291                 * http://collective.valve-erc.com/index.php?go=water_simulation
292                 * The params could be dynamically changed every frame ofcourse
293                 */
294                double C = PARAM_C; // ripple speed
295                double D = PARAM_D; // distance
296                double U = PARAM_U; // viscosity
297                double T = PARAM_T; // time
298                Real TERM1 = ( 4.0f - 8.0f*C*C*T*T/(D*D) ) / (U*T+2) ;
299                Real TERM2 = ( U*T-2.0f ) / (U*T+2.0f) ;
300                Real TERM3 = ( 2.0f * C*C*T*T/(D*D) ) / (U*T+2) ;
301                for(y=1;y<complexity;y++) { // don't do anything with border values
302                        float *row = buf + 3*y*(complexity+1) ;
303                        float *row1 = buf1 + 3*y*(complexity+1) ;
304                        float *row1up = buf1 + 3*(y-1)*(complexity+1) ;
305                        float *row1down = buf1 + 3*(y+1)*(complexity+1) ;
306                        float *row2 = buf2 + 3*y*(complexity+1) ;
307                        for(x=1;x<complexity;x++) {
308                                row[3*x] = TERM1 * row1[3*x]
309                                        + TERM2 * row2[3*x]
310                                        + TERM3 * ( row1[3*x-3] + row1[3*x+3] + row1up[3*x]+row1down[3*x] ) ;
311                        }
312                }
313
314                lastAnimationTimeStamp += (1.0f / ANIMATIONS_PER_SECOND);
315        }
316
317        if (useFakeNormals) {
318                calculateFakeNormals();
319        } else {
320                calculateNormals();
321        }
322
323        // set vertex buffer
324        posVertexBuffer->writeData(0,
325                posVertexBuffer->getSizeInBytes(), // size
326                vertexBuffers[currentBuffNumber], // source
327                true); // discard?
328}
Note: See TracBrowser for help on using the repository browser.