waterPlane.cpp
Engine/source/environment/waterPlane.cpp
Public Defines
define
BLEND_TEX_SIZE() 256
define
Public Variables
Public Functions
ConsoleDocClass(WaterPlane , "@brief Represents <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> large body of water stretching <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the horizon in all <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">directions.\n\n</a>" "<a href="/coding/class/classwaterplane/">WaterPlane</a>'s position is defined only height, the z element of position, " "it is infinite in xy and depth. %<a href="/coding/class/classwaterplane/">WaterPlane</a> is designed <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> represent the " "ocean on an island scene and viewed from ground level;other uses may not " "be appropriate and <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classwaterblock/">WaterBlock</a> may be <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">used.\n\n</a>" " @see <a href="/coding/class/classwaterobject/">WaterObject</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> inherited <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">functionality.\n\n</a>" "<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Limitations:\n\n</a>" "Because %<a href="/coding/class/classwaterplane/">WaterPlane</a> cannot be projected exactly <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the far-clip distance, " "other objects nearing this distance can have noticible artifacts as they " "clip through first the %<a href="/coding/class/classwaterplane/">WaterPlane</a> and then the far <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">plane.\n\n</a>" "To avoid this large objects should be positioned such that they will not line up with " "the far-clip from vantage points the player is expected <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be. In particular, " "your <a href="/coding/class/classterrainblock/">TerrainBlock</a> should be completely contained by the far-clip <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">distance.\n\n</a>" "Viewing %<a href="/coding/class/classwaterplane/">WaterPlane</a> from <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> high altitude with <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> tight far-clip distance " "will accentuate this limitation. %<a href="/coding/class/classwaterplane/">WaterPlane</a> is primarily designed <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> " "be viewed from ground <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">level.\n\n</a>" " @ingroup Water" )
Detailed Description
Public Defines
BLEND_TEX_SIZE() 256
V_SHADER_PARAM_OFFSET() 50
Public Variables
ColorI gCanvasClearColor
Public Functions
ConsoleDocClass(WaterPlane , "@brief Represents <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> large body of water stretching <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the horizon in all <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">directions.\n\n</a>" "<a href="/coding/class/classwaterplane/">WaterPlane</a>'s position is defined only height, the z element of position, " "it is infinite in xy and depth. %<a href="/coding/class/classwaterplane/">WaterPlane</a> is designed <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> represent the " "ocean on an island scene and viewed from ground level;other uses may not " "be appropriate and <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classwaterblock/">WaterBlock</a> may be <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">used.\n\n</a>" " @see <a href="/coding/class/classwaterobject/">WaterObject</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> inherited <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">functionality.\n\n</a>" "<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Limitations:\n\n</a>" "Because %<a href="/coding/class/classwaterplane/">WaterPlane</a> cannot be projected exactly <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the far-clip distance, " "other objects nearing this distance can have noticible artifacts as they " "clip through first the %<a href="/coding/class/classwaterplane/">WaterPlane</a> and then the far <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">plane.\n\n</a>" "To avoid this large objects should be positioned such that they will not line up with " "the far-clip from vantage points the player is expected <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be. In particular, " "your <a href="/coding/class/classterrainblock/">TerrainBlock</a> should be completely contained by the far-clip <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">distance.\n\n</a>" "Viewing %<a href="/coding/class/classwaterplane/">WaterPlane</a> from <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> high altitude with <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> tight far-clip distance " "will accentuate this limitation. %<a href="/coding/class/classwaterplane/">WaterPlane</a> is primarily designed <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> " "be viewed from ground <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">level.\n\n</a>" " @ingroup Water" )
IMPLEMENT_CO_NETOBJECT_V1(WaterPlane )
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#include "platform/platform.h" 25#include "environment/waterPlane.h" 26 27#include "core/util/safeDelete.h" 28#include "scene/sceneRenderState.h" 29#include "scene/sceneManager.h" 30#include "lighting/lightInfo.h" 31#include "core/stream/bitStream.h" 32#include "math/mathIO.h" 33#include "math/mathUtils.h" 34#include "console/consoleTypes.h" 35#include "gui/3d/guiTSControl.h" 36#include "gfx/primBuilder.h" 37#include "gfx/gfxTransformSaver.h" 38#include "gfx/gfxDebugEvent.h" 39#include "gfx/gfxOcclusionQuery.h" 40#include "renderInstance/renderPassManager.h" 41#include "sim/netConnection.h" 42#include "scene/reflectionManager.h" 43#include "ts/tsShapeInstance.h" 44#include "T3D/gameFunctions.h" 45#include "postFx/postEffect.h" 46#include "math/util/matrixSet.h" 47 48extern ColorI gCanvasClearColor; 49 50#define BLEND_TEX_SIZE 256 51#define V_SHADER_PARAM_OFFSET 50 52 53IMPLEMENT_CO_NETOBJECT_V1(WaterPlane); 54 55ConsoleDocClass( WaterPlane, 56 "@brief Represents a large body of water stretching to the horizon in all directions.\n\n" 57 58 "WaterPlane's position is defined only height, the z element of position, " 59 "it is infinite in xy and depth. %WaterPlane is designed to represent the " 60 "ocean on an island scene and viewed from ground level; other uses may not " 61 "be appropriate and a WaterBlock may be used.\n\n" 62 63 "@see WaterObject for inherited functionality.\n\n" 64 65 "Limitations:\n\n" 66 67 "Because %WaterPlane cannot be projected exactly to the far-clip distance, " 68 "other objects nearing this distance can have noticible artifacts as they " 69 "clip through first the %WaterPlane and then the far plane.\n\n" 70 71 "To avoid this large objects should be positioned such that they will not line up with " 72 "the far-clip from vantage points the player is expected to be. In particular, " 73 "your TerrainBlock should be completely contained by the far-clip distance.\n\n" 74 75 "Viewing %WaterPlane from a high altitude with a tight far-clip distance " 76 "will accentuate this limitation. %WaterPlane is primarily designed to " 77 "be viewed from ground level.\n\n" 78 79 "@ingroup Water" 80); 81 82WaterPlane::WaterPlane() 83{ 84 mGridElementSize = 1.0f; 85 mGridSize = 101; 86 mGridSizeMinusOne = mGridSize - 1; 87 88 mNetFlags.set(Ghostable | ScopeAlways); 89 90 mVertCount = 0; 91 mIndxCount = 0; 92 mPrimCount = 0; 93} 94 95WaterPlane::~WaterPlane() 96{ 97} 98 99bool WaterPlane::onAdd() 100{ 101 if ( !Parent::onAdd() ) 102 return false; 103 104 setGlobalBounds(); 105 resetWorldBox(); 106 addToScene(); 107 108 mWaterFogData.plane.set( 0, 0, 1, -getPosition().z ); 109 110 return true; 111} 112 113void WaterPlane::onRemove() 114{ 115 removeFromScene(); 116 117 Parent::onRemove(); 118} 119 120void WaterPlane::initPersistFields() 121{ 122 addGroup( "WaterPlane" ); 123 124 addProtectedField( "gridSize", TypeS32, Offset( mGridSize, WaterPlane ), &protectedSetGridSize, &defaultProtectedGetFn, 125 "Spacing between vertices in the WaterBlock mesh" ); 126 127 addProtectedField( "gridElementSize", TypeF32, Offset( mGridElementSize, WaterPlane ), &protectedSetGridElementSize, &defaultProtectedGetFn, 128 "Duplicate of gridElementSize for backwards compatility"); 129 130 endGroup( "WaterPlane" ); 131 132 Parent::initPersistFields(); 133 134 removeField( "rotation" ); 135 removeField( "scale" ); 136} 137 138U32 WaterPlane::packUpdate(NetConnection* con, U32 mask, BitStream* stream) 139{ 140 U32 retMask = Parent::packUpdate(con, mask, stream); 141 142 stream->write( mGridSize ); 143 stream->write( mGridElementSize ); 144 145 if ( stream->writeFlag( mask & UpdateMask ) ) 146 { 147 stream->write( getPosition().z ); 148 } 149 150 return retMask; 151} 152 153void WaterPlane::unpackUpdate(NetConnection* con, BitStream* stream) 154{ 155 Parent::unpackUpdate(con, stream); 156 157 U32 inGridSize; 158 stream->read( &inGridSize ); 159 setGridSize( inGridSize ); 160 161 F32 inGridElementSize; 162 stream->read( &inGridElementSize ); 163 setGridElementSize( inGridElementSize ); 164 165 if( stream->readFlag() ) // UpdateMask 166 { 167 F32 posZ; 168 stream->read( &posZ ); 169 Point3F newPos = getPosition(); 170 newPos.z = posZ; 171 setPosition( newPos ); 172 } 173} 174 175void WaterPlane::setupVBIB( SceneRenderState *state ) 176{ 177 const Frustum &frustum = state->getCullingFrustum(); 178 179 // World-Up vector, assigned as normal for all verts. 180 const Point3F worldUp( 0.0f, 0.0f, 1.0f ); 181 182 // World-unit size of a grid cell. 183 const F32 squareSize = mGridElementSize; 184 185 // Column/Row count. 186 // So we don't neet to access class-specific member variables 187 // in the code below. 188 const U32 gridSize = mGridSize; 189 190 // Number of verts in one column / row 191 const U32 gridStride = gridSize + 1; 192 193 // Grid is filled in this order... 194 195 // Ex. Grid with gridSize of 2. 196 // 197 // Letters are cells. 198 // Numbers are verts, enumerated in their order within the vert buffer. 199 // 200 // 6 7 8 201 // (c) (d) 202 // 3 4 5 203 // (a) (b) 204 // 0 1 2 205 // 206 // Note... 207 // Camera would be positioned at vert 4 ( in this particular grid not a constant ). 208 // Positive Y points UP the diagram ( verts 0, 3, 6 ). 209 // Positive X points RIGHT across the diagram ( verts 0, 1, 2 ). 210 211 // Length of a grid row/column divided by two. 212 F32 gridSideHalfLen = squareSize * gridSize * 0.5f; 213 214 // Position of the first vertex in the grid. 215 // Relative to the camera this is the "Back Left" corner vert. 216 const Point3F cornerPosition( -gridSideHalfLen, -gridSideHalfLen, 0.0f ); 217 218 // Number of verts in the grid centered on the camera. 219 const U32 gridVertCount = gridStride * gridStride; 220 221 // Number of verts surrounding the grid, projected by the frustum. 222 const U32 borderVertCount = gridSize * 4; 223 224 // Number of verts in the front-most row which are raised to the horizon. 225 const U32 horizonVertCount = gridStride; 226 227 // Total number of verts. Calculation explained above. 228 mVertCount = gridVertCount + borderVertCount + horizonVertCount; 229 230 231 // Fill the vertex buffer... 232 233 mVertBuff.set( GFX, mVertCount, GFXBufferTypeStatic ); 234 235 GFXWaterVertex *vertPtr = mVertBuff.lock(); 236 237 // Fill verts in the camera centered grid... 238 239 // Temorary storage for calculation of vert position. 240 F32 xVal, yVal; 241 242 for ( U32 i = 0; i < gridStride; i++ ) 243 { 244 yVal = cornerPosition.y + (F32)( i * squareSize ); 245 246 for ( U32 j = 0; j < gridStride; j++ ) 247 { 248 xVal = cornerPosition.x + (F32)( j * squareSize ); 249 250 vertPtr->point.set( xVal, yVal, 0.0f ); 251 vertPtr->normal = worldUp; 252 vertPtr->undulateData.set( xVal, yVal ); 253 vertPtr->horizonFactor.set( 0, 0, 0, 0 ); 254 vertPtr++; 255 } 256 } 257 258 // Fill in 'border' verts, surrounding the grid, projected by the frustum. 259 260 // Ex. Grid with gridSize of 2. 261 // 262 // Letters in parenthesis are cells. 263 // x's are grid-verts ( we have already filled ). 264 // Numbers are border verts, enumerated in their order within the vert buffer. 265 // 266 // Lines connecting verts explained in the code below. 267 // 268 // Front 269 // 270 // L 0------1 2 R 271 // e x x x | i 272 // f (c) (d) | g 273 // t 7 x x x 3 h 274 // | (a) (b) t 275 // | x x x 276 // 6 5------4 277 // 278 // Back 279 // 280 // As in previous diagram... 281 // Camera would be positioned at vert 4 ( in this particular grid not a constant ). 282 // Positive Y points UP the diagram ( verts 6, 7, 0 ). 283 // Positive X points RIGHT across the diagram ( verts 0, 1, 2 ). 284 285 286 // Iterator i is looping through the 4 'sides' of the grid. 287 // Inner loop ( using iterator j ) will fill in a number of verts 288 // where that count is 'gridSize'. 289 // 290 // 291 // Ex. Given the grid with gridSize of 2 diagramed above, 292 // Outer loop iterates through: Front, Right, Back, Left 293 // Inner loop fills 2 verts per iteration of the outer loop: { 0, 1 }, { 2, 3 }, { 4, 5 }, { 6, 7 } 294 295 // Grid-space vectors indexed by 'side'. 296 // Each vector describes the direction we iterate when 297 // filling in verts ( mathematically the tangent ). 298 const Point2F sBorderTangentVec [4] = { 299 Point2F( 1, 0 ), // Front ( 0 ) 300 Point2F( 0, -1 ), // Right ( 1 ) 301 Point2F( -1, 0 ), // Back ( 2 ) 302 Point2F( 0, 1 ) // Left ( 3 ) 303 }; 304 305 306 // Normalized positions indexed by 'side' 307 // Defines the 'start' position of each side, eg. the position of the first vert. 308 // See Diagram below. 309 const Point2F sBorderStartPos [4] = { 310 Point2F( -1, 1 ), // Front ( 0 ) 311 Point2F( 1, 1 ), // Right ( 1 ) 312 Point2F( 1, -1 ), // Back ( 2 ) 313 Point2F( -1, -1 ) // Left ( 3 ) 314 }; 315 316 // Diagram of Start vert position per Side. 317 // 318 // Labeling convention for verts is 'As' where A is the first letter of 319 // that side's descriptive name and lower-case s indicates 'start'. 320 // 321 // 322 // 323 // Front 324 // (-1,1) 325 // Fs------o-----Rs(1,1)R 326 // | | i 327 // | | g 328 // o (0,0) o h 329 // | | t 330 // | | 331 // L(-1,-1)Ls------o-----Bs 332 // e (1,-1) 333 // f Back 334 // t 335 336 // Calculate the world-space dimension of the border-vert-ring... 337 338 // Diagram shows overall layout of the WaterPlane with a gridSize of 1, 339 // with all 'quads' enumerated. 340 // center-grid ( 1 ), border ( 2, 3, 4, 5 ), and horizon ( 6 ). 341 // 342 // 343 // x------------x 344 // \ 6 \ <- horizon quad is really 'above' the front border 345 // x --------- x not in front of it 346 // | \ 2 / | 347 // | x---- x | 348 // | | | | 349 // | 5| 1 |3 | 350 // | x --- x | 351 // | / 4 \| 352 // x------------x 353 354 355 // WaterPlane renders relative to the camera rotation around z and xy position. 356 // 357 // That is, it rotates around the z-up axis with the camera such that the 358 // camera is always facing towards the front border unless looking straight 359 // down or up. 360 // 361 // Also note that the horizon verts are pulled straight up from the front 362 // border verts. 363 // 364 // Therefore... 365 // 366 // The front border must be as close to the farclip plane as possible 367 // so distant objects clip through the horizon and farplane at the same time. 368 // 369 // The left and right borders must be pulled outward a distance such 370 // that water extends horizontally across the entire viewable area while 371 // looking straight forward +y or straight down -z. 372 // 373 374 // 375 const F32 farDistScale = 0.99f; 376 377 // 378 F32 farDist = frustum.getFarDist() * farDistScale; 379 380 // 381 F32 farWidth = (F32)state->getViewport().extent.x * farDist / state->getWorldToScreenScale().x; 382 383 Point2F borderExtents( farWidth * 2.0f, farDist * 2.0f ); 384 Point2F borderHalfExtents( farWidth, farDist ); 385 386 Point2F borderDir; 387 Point2F borderStart; 388 389 for ( U32 i = 0; i < 4; i++ ) 390 { 391 borderDir = sBorderTangentVec[i]; 392 borderStart = sBorderStartPos[i]; 393 394 for ( U32 j = 0; j < gridSize; j++ ) 395 { 396 F32 frac = (F32)j / (F32)gridSize; 397 398 Point2F pos( borderStart * borderHalfExtents ); 399 pos += borderDir * borderExtents * frac; 400 401 vertPtr->point.set( pos.x, pos.y, 0.0f ); 402 vertPtr->undulateData.set( pos.x, pos.y ); 403 vertPtr->horizonFactor.set( 0, 0, 0, 0 ); 404 vertPtr->normal = worldUp; 405 vertPtr++; 406 } 407 } 408 409 // Fill in row of horizion verts. 410 // Verts are positioned identical to the front border, but will be 411 // manipulated in z within the shader. 412 // 413 // Z position of 50.0f is unimportant unless you want to disable 414 // shader manipulation and render in wireframe for debugging. 415 416 for ( U32 i = 0; i < gridStride; i++ ) 417 { 418 F32 frac = (F32)i / (F32)gridSize; 419 420 Point2F pos( sBorderStartPos[0] * borderHalfExtents ); 421 pos += sBorderTangentVec[0] * borderExtents * frac; 422 423 vertPtr->point.set( pos.x, pos.y, 50.0f ); 424 vertPtr->undulateData.set( pos.x, pos.y ); 425 vertPtr->horizonFactor.set( 1, 0, 0, 0 ); 426 vertPtr->normal = worldUp; 427 vertPtr++; 428 } 429 430 mVertBuff.unlock(); 431 432 433 // Fill in the PrimitiveBuffer... 434 435 // 2 triangles per cell/quad 436 const U32 gridTriCount = gridSize * gridSize * 2; 437 438 // 4 sides, mGridSize quads per side, 2 triangles per quad 439 const U32 borderTriCount = 4 * gridSize * 2; 440 441 // 1 quad per gridSize, 2 triangles per quad 442 // i.e. an extra row of 'cells' leading the front side of the grid 443 const U32 horizonTriCount = gridSize * 2; 444 445 mPrimCount = gridTriCount + borderTriCount + horizonTriCount; 446 447 // 3 indices per triangle. 448 mIndxCount = mPrimCount * 3; 449 450 mPrimBuff.set( GFX, mIndxCount, mPrimCount, GFXBufferTypeStatic ); 451 U16 *idxPtr; 452 mPrimBuff.lock(&idxPtr); 453 454 // Temporaries to hold indices for the corner points of a quad. 455 U32 p00, p01, p11, p10; 456 U32 offset = 0; 457 458 // Given a single cell of the grid diagramed below, 459 // quad indice variables are in this orientation. 460 // 461 // p01 --- p11 462 // | | 463 // | | 464 // p00 --- p10 465 // 466 // Positive Y points UP the diagram ( p00, p01 ). 467 // Positive X points RIGHT across the diagram ( p00, p10 ) 468 // 469 470 // i iterates bottom to top "column-wise" 471 for ( U32 i = 0; i < mGridSize; i++ ) 472 { 473 // j iterates left to right "row-wise" 474 for ( U32 j = 0; j < mGridSize; j++ ) 475 { 476 // where (j,i) is a particular cell. 477 p00 = offset; 478 p10 = offset + 1; 479 p01 = offset + gridStride; 480 p11 = offset + 1 + gridStride; 481 482 // Top Left Triangle 483 484 *idxPtr = p00; 485 idxPtr++; 486 *idxPtr = p01; 487 idxPtr++; 488 *idxPtr = p11; 489 idxPtr++; 490 491 // Bottom Right Triangle 492 493 *idxPtr = p00; 494 idxPtr++; 495 *idxPtr = p11; 496 idxPtr++; 497 *idxPtr = p10; 498 idxPtr++; 499 500 offset += 1; 501 } 502 503 offset += 1; 504 } 505 506 // Fill border indices... 507 508 // Given a grid size of 1, 509 // the grid / border verts are in the vertex buffer in this order. 510 // 511 // 512 // 4 5 513 // 2 --- 3 514 // | | 515 // | | 516 // 0 --- 1 517 // 7 6 518 // 519 // Positive Y points UP the diagram ( p00, p01 ). 520 // Positive X points RIGHT across the diagram ( p00, p10 ) 521 // 522 // Note we duplicate the first border vert ( 4 ) since it is also the last 523 // and this makes our loop easier. 524 525 const U32 sBorderStartVert [4] = { 526 gridStride * gridSize, // Index to the Top-Left grid vert. 527 gridStride * gridSize + gridSize, // Index to the Top-Right grid vert. 528 gridSize, // Index to the Bottom-Right grid vert. 529 0, // Index to the Bottom-Left grid vert. 530 }; 531 532 const S32 sBorderStepSize [4] = { 533 // Step size to the next grid vert along the specified side.... 534 1, // Top 535 -(S32)gridStride, // Right 536 -1, // Bottom 537 (S32)gridStride, // Left 538 }; 539 540 const U32 firstBorderVert = gridStride * gridSize + gridStride; 541 const U32 lastBorderVert = firstBorderVert + ( borderVertCount - 1 ); 542 U32 startBorderVert = firstBorderVert; 543 U32 startGridVert; 544 U32 curStepSize; 545 546 547 for ( U32 i = 0; i < 4; i++ ) 548 { 549 startGridVert = sBorderStartVert[i]; 550 curStepSize = sBorderStepSize[i]; 551 552 for ( U32 j = 0; j < gridSize; j++ ) 553 { 554 // Each border cell is 1 quad, 2 triangles. 555 556 p00 = startGridVert; 557 p10 = startGridVert + curStepSize; 558 p01 = startBorderVert; 559 p11 = startBorderVert + 1; 560 561 if ( p11 > lastBorderVert ) 562 p11 = firstBorderVert; 563 564 // Top Left Triangle 565 566 *idxPtr = p00; 567 idxPtr++; 568 *idxPtr = p01; 569 idxPtr++; 570 *idxPtr = p11; 571 idxPtr++; 572 573 // Bottom Right Triangle 574 575 *idxPtr = p00; 576 idxPtr++; 577 *idxPtr = p11; 578 idxPtr++; 579 *idxPtr = p10; 580 idxPtr++; 581 582 startBorderVert++; 583 startGridVert += curStepSize; 584 } 585 } 586 587 // Fill in 'horizon' triangles. 588 589 U32 curHorizonVert = lastBorderVert + 1; 590 U32 curBorderVert = firstBorderVert; 591 592 for ( U32 i = 0; i < gridSize; i++ ) 593 { 594 p00 = curBorderVert; 595 p10 = curBorderVert + 1; 596 p01 = curHorizonVert; 597 p11 = curHorizonVert + 1; 598 599 // Top Left Triangle 600 601 *idxPtr = p00; 602 idxPtr++; 603 *idxPtr = p01; 604 idxPtr++; 605 *idxPtr = p11; 606 idxPtr++; 607 608 // Bottom Right Triangle 609 610 *idxPtr = p00; 611 idxPtr++; 612 *idxPtr = p11; 613 idxPtr++; 614 *idxPtr = p10; 615 idxPtr++; 616 617 curBorderVert++; 618 curHorizonVert++; 619 } 620 621 mPrimBuff.unlock(); 622} 623 624SceneData WaterPlane::setupSceneGraphInfo( SceneRenderState *state ) 625{ 626 SceneData sgData; 627 628 sgData.lights[0] = LIGHTMGR->getSpecialLight( LightManager::slSunLightType ); 629 630 // fill in water's transform 631 sgData.objTrans = &getRenderTransform(); 632 633 // fog 634 sgData.setFogParams( state->getSceneManager()->getFogData() ); 635 636 // misc 637 sgData.backBuffTex = REFLECTMGR->getRefractTex(); 638 sgData.reflectTex = mPlaneReflector.reflectTex; 639 sgData.wireframe = GFXDevice::getWireframe() || smWireframe; 640 641 return sgData; 642} 643 644void WaterPlane::setShaderParams( SceneRenderState *state, BaseMatInstance* mat, const WaterMatParams& paramHandles) 645{ 646 // Set variables that will be assigned to shader consts within WaterCommon 647 // before calling Parent::setShaderParams 648 649 mUndulateMaxDist = mGridElementSize * mGridSizeMinusOne * 0.5f; 650 651 Parent::setShaderParams( state, mat, paramHandles ); 652 653 // Now set the rest of the shader consts that are either unique to this 654 // class or that WaterObject leaves to us to handle... 655 656 MaterialParameters* matParams = mat->getMaterialParameters(); 657 658 // set vertex shader constants 659 //----------------------------------- 660 matParams->setSafe(paramHandles.mGridElementSizeSC, (F32)mGridElementSize); 661 //matParams->setSafe( paramHandles.mReflectTexSizeSC, mReflectTexSize ); 662 if ( paramHandles.mModelMatSC->isValid() ) 663 matParams->set(paramHandles.mModelMatSC, getRenderTransform(), GFXSCT_Float4x4); 664 665 // set pixel shader constants 666 //----------------------------------- 667 668 LinearColorF c( mWaterFogData.color ); 669 matParams->setSafe( paramHandles.mBaseColorSC, c ); 670 671 // By default we need to show a true reflection is fullReflect is enabled and 672 // we are above water. 673 F32 reflect = mPlaneReflector.isEnabled() && !isUnderwater( state->getCameraPosition() ); 674 675 // If we were occluded the last frame a query was fetched ( not necessarily last frame ) 676 // and we weren't updated last frame... we don't have a valid texture to show 677 // so use the cubemap / fake reflection color this frame. 678 if ( mPlaneReflector.lastUpdateMs != REFLECTMGR->getLastUpdateMs() && mPlaneReflector.isOccluded() ) 679 reflect = false; 680 681 //Point4F reflectParams( getRenderPosition().z, mReflectMinDist, mReflectMaxDist, reflect ); 682 Point4F reflectParams( getRenderPosition().z, 0.0f, 1000.0f, !reflect ); 683 684 // TODO: This is a hack... why is this broken... check after 685 // we merge advanced lighting with trunk! 686 // 687 reflectParams.z = 0.0f; 688 matParams->setSafe( paramHandles.mReflectParamsSC, reflectParams ); 689 690 VectorF reflectNorm( 0, 0, 1 ); 691 matParams->setSafe(paramHandles.mReflectNormalSC, reflectNorm ); 692} 693 694void WaterPlane::prepRenderImage( SceneRenderState *state ) 695{ 696 PROFILE_SCOPE(WaterPlane_prepRenderImage); 697 698 if( !state->isDiffusePass() ) 699 return; 700 701 mBasicLighting = dStricmp( LIGHTMGR->getId(), "BLM" ) == 0; 702 mUnderwater = isUnderwater( state->getCameraPosition() ); 703 704 mMatrixSet->setSceneView(GFX->getWorldMatrix()); 705 706 const Frustum &frustum = state->getCameraFrustum(); 707 708 if ( mPrimBuff.isNull() || 709 mGenerateVB || 710 frustum != mFrustum ) 711 { 712 mFrustum = frustum; 713 setupVBIB( state ); 714 mGenerateVB = false; 715 716 MatrixF proj( true ); 717 MathUtils::getZBiasProjectionMatrix( 0.0001f, mFrustum, &proj ); 718 mMatrixSet->setSceneProjection(proj); 719 } 720 721 _getWaterPlane( state->getCameraPosition(), mWaterPlane, mWaterPos ); 722 mWaterFogData.plane = mWaterPlane; 723 mPlaneReflector.refplane = mWaterPlane; 724 updateUnderwaterEffect( state ); 725 726 ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>(); 727 ri->renderDelegate.bind( this, &WaterObject::renderObject ); 728 ri->type = RenderPassManager::RIT_Water; 729 state->getRenderPass()->addInst( ri ); 730 731 //mRenderUpdateCount++; 732} 733 734void WaterPlane::innerRender( SceneRenderState *state ) 735{ 736 GFXDEBUGEVENT_SCOPE( WaterPlane_innerRender, ColorI( 255, 0, 0 ) ); 737 738 const Point3F &camPosition = state->getCameraPosition(); 739 740 Point3F rvec, fvec, uvec, pos; 741 742 const MatrixF &objMat = getTransform(); //getRenderTransform(); 743 const MatrixF &camMat = state->getCameraTransform(); 744 745 MatrixF renderMat( true ); 746 747 camMat.getColumn( 1, &fvec ); 748 uvec.set( 0, 0, 1 ); 749 rvec = mCross( fvec, uvec ); 750 rvec.normalize(); 751 fvec = mCross( uvec, rvec ); 752 pos = camPosition; 753 pos.z = objMat.getPosition().z; 754 755 renderMat.setColumn( 0, rvec ); 756 renderMat.setColumn( 1, fvec ); 757 renderMat.setColumn( 2, uvec ); 758 renderMat.setColumn( 3, pos ); 759 760 setRenderTransform( renderMat ); 761 762 // Setup SceneData 763 SceneData sgData = setupSceneGraphInfo( state ); 764 765 // set the material 766 S32 matIdx = getMaterialIndex( camPosition ); 767 768 if ( !initMaterial( matIdx ) ) 769 return; 770 771 BaseMatInstance *mat = mMatInstances[matIdx]; 772 WaterMatParams matParams = mMatParamHandles[matIdx]; 773 774 // render the geometry 775 if ( mat ) 776 { 777 // setup proj/world transform 778 mMatrixSet->restoreSceneViewProjection(); 779 mMatrixSet->setWorld(getRenderTransform()); 780 781 setShaderParams( state, mat, matParams ); 782 783 while( mat->setupPass( state, sgData ) ) 784 { 785 mat->setSceneInfo(state, sgData); 786 mat->setTransforms(*mMatrixSet, state); 787 setCustomTextures( matIdx, mat->getCurPass(), matParams ); 788 789 // set vert/prim buffer 790 GFX->setVertexBuffer( mVertBuff ); 791 GFX->setPrimitiveBuffer( mPrimBuff ); 792 GFX->drawIndexedPrimitive( GFXTriangleList, 0, 0, mVertCount, 0, mPrimCount ); 793 } 794 } 795} 796 797bool WaterPlane::isUnderwater( const Point3F &pnt ) const 798{ 799 F32 height = getPosition().z; 800 801 F32 diff = pnt.z - height; 802 803 return ( diff < 0.1 ); 804} 805 806F32 WaterPlane::distanceTo( const Point3F& point ) const 807{ 808 if( isUnderwater( point ) ) 809 return 0.f; 810 else 811 return ( point.z - getPosition().z ); 812} 813 814bool WaterPlane::buildPolyList( PolyListContext context, AbstractPolyList* polyList, const Box3F& box, const SphereF& ) 815{ 816 if(context == PLC_Navigation) 817 { 818 polyList->setObject( this ); 819 polyList->setTransform( &MatrixF::Identity, Point3F( 1.0f, 1.0f, 1.0f ) ); 820 821 F32 z = getPosition().z; 822 Point3F 823 p0(box.minExtents.x, box.maxExtents.y, z), 824 p1(box.maxExtents.x, box.maxExtents.y, z), 825 p2(box.maxExtents.x, box.minExtents.y, z), 826 p3(box.minExtents.x, box.minExtents.y, z); 827 828 // Add vertices to poly list. 829 U32 v0 = polyList->addPoint(p0); 830 polyList->addPoint(p1); 831 polyList->addPoint(p2); 832 polyList->addPoint(p3); 833 834 // Add plane between first three vertices. 835 polyList->begin(0, 0); 836 polyList->vertex(v0); 837 polyList->vertex(v0+1); 838 polyList->vertex(v0+2); 839 polyList->plane(v0, v0+1, v0+2); 840 polyList->end(); 841 842 // Add plane between last three vertices. 843 polyList->begin(0, 1); 844 polyList->vertex(v0+2); 845 polyList->vertex(v0+3); 846 polyList->vertex(v0); 847 polyList->plane(v0+2, v0+3, v0); 848 polyList->end(); 849 850 return true; 851 } 852 853 return false; 854} 855 856void WaterPlane::inspectPostApply() 857{ 858 Parent::inspectPostApply(); 859 860 setMaskBits( UpdateMask ); 861} 862 863void WaterPlane::setTransform( const MatrixF &mat ) 864{ 865 // We only accept the z value from the new transform. 866 867 MatrixF newMat( true ); 868 869 Point3F newPos = getPosition(); 870 newPos.z = mat.getPosition().z; 871 newMat.setPosition( newPos ); 872 873 Parent::setTransform( newMat ); 874 875 // Parent::setTransforms ends up setting our worldBox to something other than 876 // global, so we have to set it back... but we can't actually call setGlobalBounds 877 // again because it does extra work adding and removing us from the container. 878 879 mGlobalBounds = true; 880 mObjBox.minExtents.set(-1e10, -1e10, -1e10); 881 mObjBox.maxExtents.set( 1e10, 1e10, 1e10); 882 883 // Keep mWaterPlane up to date. 884 mWaterFogData.plane.set( 0, 0, 1, -getPosition().z ); 885} 886 887void WaterPlane::onStaticModified( const char* slotName, const char*newValue ) 888{ 889 Parent::onStaticModified( slotName, newValue ); 890 891 if ( dStricmp( slotName, "surfMaterial" ) == 0 ) 892 setMaskBits( MaterialMask ); 893} 894 895bool WaterPlane::castRay(const Point3F& start, const Point3F& end, RayInfo* info ) 896{ 897 // Simply look for the hit on the water plane 898 // and ignore any future issues with waves, etc. 899 const Point3F norm(0,0,1); 900 PlaneF plane( Point3F::Zero, norm ); 901 902 F32 hit = plane.intersect( start, end ); 903 if ( hit < 0.0f || hit > 1.0f ) 904 return false; 905 906 info->t = hit; 907 info->object = this; 908 info->point = start + ( ( end - start ) * hit ); 909 info->normal = norm; 910 info->material = mMatInstances[ WaterMat ]; 911 912 return true; 913} 914 915F32 WaterPlane::getWaterCoverage( const Box3F &testBox ) const 916{ 917 F32 posZ = getPosition().z; 918 919 F32 coverage = 0.0f; 920 921 if ( posZ > testBox.minExtents.z ) 922 { 923 if ( posZ < testBox.maxExtents.z ) 924 coverage = (posZ - testBox.minExtents.z) / (testBox.maxExtents.z - testBox.minExtents.z); 925 else 926 coverage = 1.0f; 927 } 928 929 return coverage; 930} 931 932F32 WaterPlane::getSurfaceHeight( const Point2F &pos ) const 933{ 934 return getPosition().z; 935} 936 937void WaterPlane::onReflectionInfoChanged() 938{ 939 /* 940 if ( isClientObject() && GFX->getPixelShaderVersion() >= 1.4 ) 941 { 942 if ( mFullReflect ) 943 REFLECTMGR->registerObject( this, ReflectDelegate( this, &WaterPlane::updateReflection ), mReflectPriority, mReflectMaxRateMs, mReflectMaxDist ); 944 else 945 { 946 REFLECTMGR->unregisterObject( this ); 947 mReflectTex = NULL; 948 } 949 } 950 */ 951} 952 953void WaterPlane::setGridSize( U32 inSize ) 954{ 955 if ( inSize == mGridSize ) 956 return; 957 958 // GridSize must be an odd number. 959 //if ( inSize % 2 == 0 ) 960 // inSize++; 961 962 // GridSize must be at least 1 963 inSize = getMax( inSize, (U32)1 ); 964 965 mGridSize = inSize; 966 mGridSizeMinusOne = mGridSize - 1; 967 mGenerateVB = true; 968 setMaskBits( UpdateMask ); 969} 970 971void WaterPlane::setGridElementSize( F32 inSize ) 972{ 973 if ( inSize == mGridElementSize ) 974 return; 975 976 // GridElementSize must be greater than 0 977 inSize = getMax( inSize, 0.0001f ); 978 979 mGridElementSize = inSize; 980 mGenerateVB = true; 981 setMaskBits( UpdateMask ); 982} 983 984bool WaterPlane::protectedSetGridSize( void *obj, const char *index, const char *data ) 985{ 986 WaterPlane *object = static_cast<WaterPlane*>(obj); 987 S32 size = dAtoi( data ); 988 989 object->setGridSize( size ); 990 991 // We already set the field. 992 return false; 993} 994 995bool WaterPlane::protectedSetGridElementSize( void *obj, const char *index, const char *data ) 996{ 997 WaterPlane *object = static_cast<WaterPlane*>(obj); 998 F32 size = dAtof( data ); 999 1000 object->setGridElementSize( size ); 1001 1002 // We already set the field. 1003 return false; 1004} 1005 1006void WaterPlane::_getWaterPlane( const Point3F &camPos, PlaneF &outPlane, Point3F &outPos ) 1007{ 1008 outPos = getPosition(); 1009 outPlane.set( outPos, Point3F(0,0,1) ); 1010} 1011