waterPlane.cpp 29 KB

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