[692] | 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 | }
|
---|