waterPlane.cpp 29 KB

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