1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2012 GarageGames, LLC
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //-----------------------------------------------------------------------------
- #include "platform/platform.h"
- #include "environment/waterPlane.h"
- #include "core/util/safeDelete.h"
- #include "scene/sceneRenderState.h"
- #include "scene/sceneManager.h"
- #include "lighting/lightInfo.h"
- #include "core/stream/bitStream.h"
- #include "math/mathIO.h"
- #include "math/mathUtils.h"
- #include "console/consoleTypes.h"
- #include "gui/3d/guiTSControl.h"
- #include "gfx/primBuilder.h"
- #include "gfx/gfxTransformSaver.h"
- #include "gfx/gfxDebugEvent.h"
- #include "gfx/gfxOcclusionQuery.h"
- #include "renderInstance/renderPassManager.h"
- #include "sim/netConnection.h"
- #include "scene/reflectionManager.h"
- #include "ts/tsShapeInstance.h"
- #include "T3D/gameFunctions.h"
- #include "postFx/postEffect.h"
- #include "math/util/matrixSet.h"
- extern ColorI gCanvasClearColor;
- #define BLEND_TEX_SIZE 256
- #define V_SHADER_PARAM_OFFSET 50
- IMPLEMENT_CO_NETOBJECT_V1(WaterPlane);
- ConsoleDocClass( WaterPlane,
- "@brief Represents a large body of water stretching to the horizon in all directions.\n\n"
- "WaterPlane's position is defined only height, the z element of position, "
- "it is infinite in xy and depth. %WaterPlane is designed to represent the "
- "ocean on an island scene and viewed from ground level; other uses may not "
- "be appropriate and a WaterBlock may be used.\n\n"
- "@see WaterObject for inherited functionality.\n\n"
- "Limitations:\n\n"
-
- "Because %WaterPlane cannot be projected exactly to the far-clip distance, "
- "other objects nearing this distance can have noticible artifacts as they "
- "clip through first the %WaterPlane and then the far plane.\n\n"
-
- "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 to be. In particular, "
- "your TerrainBlock should be completely contained by the far-clip distance.\n\n"
-
- "Viewing %WaterPlane from a high altitude with a tight far-clip distance "
- "will accentuate this limitation. %WaterPlane is primarily designed to "
- "be viewed from ground level.\n\n"
-
- "@ingroup Water"
- );
- WaterPlane::WaterPlane()
- {
- mGridElementSize = 1.0f;
- mGridSize = 101;
- mGridSizeMinusOne = mGridSize - 1;
- mNetFlags.set(Ghostable | ScopeAlways);
- mVertCount = 0;
- mIndxCount = 0;
- mPrimCount = 0;
- }
- WaterPlane::~WaterPlane()
- {
- }
- bool WaterPlane::onAdd()
- {
- if ( !Parent::onAdd() )
- return false;
-
- setGlobalBounds();
- resetWorldBox();
- addToScene();
- mWaterFogData.plane.set( 0, 0, 1, -getPosition().z );
- return true;
- }
- void WaterPlane::onRemove()
- {
- removeFromScene();
- Parent::onRemove();
- }
- void WaterPlane::initPersistFields()
- {
- addGroup( "WaterPlane" );
- addProtectedField( "gridSize", TypeS32, Offset( mGridSize, WaterPlane ), &protectedSetGridSize, &defaultProtectedGetFn,
- "Spacing between vertices in the WaterBlock mesh" );
- addProtectedField( "gridElementSize", TypeF32, Offset( mGridElementSize, WaterPlane ), &protectedSetGridElementSize, &defaultProtectedGetFn,
- "Duplicate of gridElementSize for backwards compatility");
- endGroup( "WaterPlane" );
- Parent::initPersistFields();
- removeField( "rotation" );
- removeField( "scale" );
- }
- U32 WaterPlane::packUpdate(NetConnection* con, U32 mask, BitStream* stream)
- {
- U32 retMask = Parent::packUpdate(con, mask, stream);
- stream->write( mGridSize );
- stream->write( mGridElementSize );
- if ( stream->writeFlag( mask & UpdateMask ) )
- {
- stream->write( getPosition().z );
- }
- return retMask;
- }
- void WaterPlane::unpackUpdate(NetConnection* con, BitStream* stream)
- {
- Parent::unpackUpdate(con, stream);
- U32 inGridSize;
- stream->read( &inGridSize );
- setGridSize( inGridSize );
- F32 inGridElementSize;
- stream->read( &inGridElementSize );
- setGridElementSize( inGridElementSize );
- if( stream->readFlag() ) // UpdateMask
- {
- F32 posZ;
- stream->read( &posZ );
- Point3F newPos = getPosition();
- newPos.z = posZ;
- setPosition( newPos );
- }
- }
- void WaterPlane::setupVBIB( SceneRenderState *state )
- {
- const Frustum &frustum = state->getCullingFrustum();
-
- // World-Up vector, assigned as normal for all verts.
- const Point3F worldUp( 0.0f, 0.0f, 1.0f );
- // World-unit size of a grid cell.
- const F32 squareSize = mGridElementSize;
- // Column/Row count.
- // So we don't neet to access class-specific member variables
- // in the code below.
- const U32 gridSize = mGridSize;
- // Number of verts in one column / row
- const U32 gridStride = gridSize + 1;
- // Grid is filled in this order...
-
- // Ex. Grid with gridSize of 2.
- //
- // Letters are cells.
- // Numbers are verts, enumerated in their order within the vert buffer.
- //
- // 6 7 8
- // (c) (d)
- // 3 4 5
- // (a) (b)
- // 0 1 2
- //
- // Note...
- // Camera would be positioned at vert 4 ( in this particular grid not a constant ).
- // Positive Y points UP the diagram ( verts 0, 3, 6 ).
- // Positive X points RIGHT across the diagram ( verts 0, 1, 2 ).
- // Length of a grid row/column divided by two.
- F32 gridSideHalfLen = squareSize * gridSize * 0.5f;
- // Position of the first vertex in the grid.
- // Relative to the camera this is the "Back Left" corner vert.
- const Point3F cornerPosition( -gridSideHalfLen, -gridSideHalfLen, 0.0f );
- // Number of verts in the grid centered on the camera.
- const U32 gridVertCount = gridStride * gridStride;
- // Number of verts surrounding the grid, projected by the frustum.
- const U32 borderVertCount = gridSize * 4;
- // Number of verts in the front-most row which are raised to the horizon.
- const U32 horizonVertCount = gridStride;
- // Total number of verts. Calculation explained above.
- mVertCount = gridVertCount + borderVertCount + horizonVertCount;
-
- // Fill the vertex buffer...
- mVertBuff.set( GFX, mVertCount, GFXBufferTypeStatic );
- GFXWaterVertex *vertPtr = mVertBuff.lock();
- // Fill verts in the camera centered grid...
- // Temorary storage for calculation of vert position.
- F32 xVal, yVal;
- for ( U32 i = 0; i < gridStride; i++ )
- {
- yVal = cornerPosition.y + (F32)( i * squareSize );
- for ( U32 j = 0; j < gridStride; j++ )
- {
- xVal = cornerPosition.x + (F32)( j * squareSize );
- vertPtr->point.set( xVal, yVal, 0.0f );
- vertPtr->normal = worldUp;
- vertPtr->undulateData.set( xVal, yVal );
- vertPtr->horizonFactor.set( 0, 0, 0, 0 );
- vertPtr++;
- }
- }
- // Fill in 'border' verts, surrounding the grid, projected by the frustum.
- // Ex. Grid with gridSize of 2.
- //
- // Letters in parenthesis are cells.
- // x's are grid-verts ( we have already filled ).
- // Numbers are border verts, enumerated in their order within the vert buffer.
- //
- // Lines connecting verts explained in the code below.
- //
- // Front
- //
- // L 0------1 2 R
- // e x x x | i
- // f (c) (d) | g
- // t 7 x x x 3 h
- // | (a) (b) t
- // | x x x
- // 6 5------4
- //
- // Back
- //
- // As in previous diagram...
- // Camera would be positioned at vert 4 ( in this particular grid not a constant ).
- // Positive Y points UP the diagram ( verts 6, 7, 0 ).
- // Positive X points RIGHT across the diagram ( verts 0, 1, 2 ).
- // Iterator i is looping through the 4 'sides' of the grid.
- // Inner loop ( using iterator j ) will fill in a number of verts
- // where that count is 'gridSize'.
- //
- //
- // Ex. Given the grid with gridSize of 2 diagramed above,
- // Outer loop iterates through: Front, Right, Back, Left
- // Inner loop fills 2 verts per iteration of the outer loop: { 0, 1 }, { 2, 3 }, { 4, 5 }, { 6, 7 }
- // Grid-space vectors indexed by 'side'.
- // Each vector describes the direction we iterate when
- // filling in verts ( mathematically the tangent ).
- const Point2F sBorderTangentVec [4] = {
- Point2F( 1, 0 ), // Front ( 0 )
- Point2F( 0, -1 ), // Right ( 1 )
- Point2F( -1, 0 ), // Back ( 2 )
- Point2F( 0, 1 ) // Left ( 3 )
- };
-
- // Normalized positions indexed by 'side'
- // Defines the 'start' position of each side, eg. the position of the first vert.
- // See Diagram below.
- const Point2F sBorderStartPos [4] = {
- Point2F( -1, 1 ), // Front ( 0 )
- Point2F( 1, 1 ), // Right ( 1 )
- Point2F( 1, -1 ), // Back ( 2 )
- Point2F( -1, -1 ) // Left ( 3 )
- };
- // Diagram of Start vert position per Side.
- //
- // Labeling convention for verts is 'As' where A is the first letter of
- // that side's descriptive name and lower-case s indicates 'start'.
- //
- //
- //
- // Front
- // (-1,1)
- // Fs------o-----Rs(1,1)R
- // | | i
- // | | g
- // o (0,0) o h
- // | | t
- // | |
- // L(-1,-1)Ls------o-----Bs
- // e (1,-1)
- // f Back
- // t
- // Calculate the world-space dimension of the border-vert-ring...
- // Diagram shows overall layout of the WaterPlane with a gridSize of 1,
- // with all 'quads' enumerated.
- // center-grid ( 1 ), border ( 2, 3, 4, 5 ), and horizon ( 6 ).
- //
- //
- // x------------x
- // \ 6 \ <- horizon quad is really 'above' the front border
- // x --------- x not in front of it
- // | \ 2 / |
- // | x---- x |
- // | | | |
- // | 5| 1 |3 |
- // | x --- x |
- // | / 4 \|
- // x------------x
- // WaterPlane renders relative to the camera rotation around z and xy position.
- //
- // That is, it rotates around the z-up axis with the camera such that the
- // camera is always facing towards the front border unless looking straight
- // down or up.
- //
- // Also note that the horizon verts are pulled straight up from the front
- // border verts.
- //
- // Therefore...
- //
- // The front border must be as close to the farclip plane as possible
- // so distant objects clip through the horizon and farplane at the same time.
- //
- // The left and right borders must be pulled outward a distance such
- // that water extends horizontally across the entire viewable area while
- // looking straight forward +y or straight down -z.
- //
- //
- const F32 farDistScale = 0.99f;
- //
- F32 farDist = frustum.getFarDist() * farDistScale;
-
- //
- F32 farWidth = (F32)state->getViewport().extent.x * farDist / state->getWorldToScreenScale().x;
- Point2F borderExtents( farWidth * 2.0f, farDist * 2.0f );
- Point2F borderHalfExtents( farWidth, farDist );
- Point2F borderDir;
- Point2F borderStart;
- for ( U32 i = 0; i < 4; i++ )
- {
- borderDir = sBorderTangentVec[i];
- borderStart = sBorderStartPos[i];
- for ( U32 j = 0; j < gridSize; j++ )
- {
- F32 frac = (F32)j / (F32)gridSize;
- Point2F pos( borderStart * borderHalfExtents );
- pos += borderDir * borderExtents * frac;
- vertPtr->point.set( pos.x, pos.y, 0.0f );
- vertPtr->undulateData.set( pos.x, pos.y );
- vertPtr->horizonFactor.set( 0, 0, 0, 0 );
- vertPtr->normal = worldUp;
- vertPtr++;
- }
- }
- // Fill in row of horizion verts.
- // Verts are positioned identical to the front border, but will be
- // manipulated in z within the shader.
- //
- // Z position of 50.0f is unimportant unless you want to disable
- // shader manipulation and render in wireframe for debugging.
- for ( U32 i = 0; i < gridStride; i++ )
- {
- F32 frac = (F32)i / (F32)gridSize;
-
- Point2F pos( sBorderStartPos[0] * borderHalfExtents );
- pos += sBorderTangentVec[0] * borderExtents * frac;
- vertPtr->point.set( pos.x, pos.y, 50.0f );
- vertPtr->undulateData.set( pos.x, pos.y );
- vertPtr->horizonFactor.set( 1, 0, 0, 0 );
- vertPtr->normal = worldUp;
- vertPtr++;
- }
- mVertBuff.unlock();
- // Fill in the PrimitiveBuffer...
- // 2 triangles per cell/quad
- const U32 gridTriCount = gridSize * gridSize * 2;
- // 4 sides, mGridSize quads per side, 2 triangles per quad
- const U32 borderTriCount = 4 * gridSize * 2;
- // 1 quad per gridSize, 2 triangles per quad
- // i.e. an extra row of 'cells' leading the front side of the grid
- const U32 horizonTriCount = gridSize * 2;
-
- mPrimCount = gridTriCount + borderTriCount + horizonTriCount;
- // 3 indices per triangle.
- mIndxCount = mPrimCount * 3;
- mPrimBuff.set( GFX, mIndxCount, mPrimCount, GFXBufferTypeStatic );
- U16 *idxPtr;
- mPrimBuff.lock(&idxPtr);
- // Temporaries to hold indices for the corner points of a quad.
- U32 p00, p01, p11, p10;
- U32 offset = 0;
- // Given a single cell of the grid diagramed below,
- // quad indice variables are in this orientation.
- //
- // p01 --- p11
- // | |
- // | |
- // p00 --- p10
- //
- // Positive Y points UP the diagram ( p00, p01 ).
- // Positive X points RIGHT across the diagram ( p00, p10 )
- //
- // i iterates bottom to top "column-wise"
- for ( U32 i = 0; i < mGridSize; i++ )
- {
- // j iterates left to right "row-wise"
- for ( U32 j = 0; j < mGridSize; j++ )
- {
- // where (j,i) is a particular cell.
- p00 = offset;
- p10 = offset + 1;
- p01 = offset + gridStride;
- p11 = offset + 1 + gridStride;
- // Top Left Triangle
- *idxPtr = p00;
- idxPtr++;
- *idxPtr = p01;
- idxPtr++;
- *idxPtr = p11;
- idxPtr++;
- // Bottom Right Triangle
- *idxPtr = p00;
- idxPtr++;
- *idxPtr = p11;
- idxPtr++;
- *idxPtr = p10;
- idxPtr++;
- offset += 1;
- }
- offset += 1;
- }
- // Fill border indices...
- // Given a grid size of 1,
- // the grid / border verts are in the vertex buffer in this order.
- //
- //
- // 4 5
- // 2 --- 3
- // | |
- // | |
- // 0 --- 1
- // 7 6
- //
- // Positive Y points UP the diagram ( p00, p01 ).
- // Positive X points RIGHT across the diagram ( p00, p10 )
- //
- // Note we duplicate the first border vert ( 4 ) since it is also the last
- // and this makes our loop easier.
- const U32 sBorderStartVert [4] = {
- gridStride * gridSize, // Index to the Top-Left grid vert.
- gridStride * gridSize + gridSize, // Index to the Top-Right grid vert.
- gridSize, // Index to the Bottom-Right grid vert.
- 0, // Index to the Bottom-Left grid vert.
- };
- const S32 sBorderStepSize [4] = {
- // Step size to the next grid vert along the specified side....
- 1, // Top
- -(S32)gridStride, // Right
- -1, // Bottom
- (S32)gridStride, // Left
- };
- const U32 firstBorderVert = gridStride * gridSize + gridStride;
- const U32 lastBorderVert = firstBorderVert + ( borderVertCount - 1 );
- U32 startBorderVert = firstBorderVert;
- U32 startGridVert;
- U32 curStepSize;
-
-
- for ( U32 i = 0; i < 4; i++ )
- {
- startGridVert = sBorderStartVert[i];
- curStepSize = sBorderStepSize[i];
-
- for ( U32 j = 0; j < gridSize; j++ )
- {
- // Each border cell is 1 quad, 2 triangles.
- p00 = startGridVert;
- p10 = startGridVert + curStepSize;
- p01 = startBorderVert;
- p11 = startBorderVert + 1;
-
- if ( p11 > lastBorderVert )
- p11 = firstBorderVert;
- // Top Left Triangle
- *idxPtr = p00;
- idxPtr++;
- *idxPtr = p01;
- idxPtr++;
- *idxPtr = p11;
- idxPtr++;
- // Bottom Right Triangle
- *idxPtr = p00;
- idxPtr++;
- *idxPtr = p11;
- idxPtr++;
- *idxPtr = p10;
- idxPtr++;
- startBorderVert++;
- startGridVert += curStepSize;
- }
- }
- // Fill in 'horizon' triangles.
- U32 curHorizonVert = lastBorderVert + 1;
- U32 curBorderVert = firstBorderVert;
- for ( U32 i = 0; i < gridSize; i++ )
- {
- p00 = curBorderVert;
- p10 = curBorderVert + 1;
- p01 = curHorizonVert;
- p11 = curHorizonVert + 1;
-
- // Top Left Triangle
- *idxPtr = p00;
- idxPtr++;
- *idxPtr = p01;
- idxPtr++;
- *idxPtr = p11;
- idxPtr++;
- // Bottom Right Triangle
- *idxPtr = p00;
- idxPtr++;
- *idxPtr = p11;
- idxPtr++;
- *idxPtr = p10;
- idxPtr++;
- curBorderVert++;
- curHorizonVert++;
- }
- mPrimBuff.unlock();
- }
- SceneData WaterPlane::setupSceneGraphInfo( SceneRenderState *state )
- {
- SceneData sgData;
- sgData.lights[0] = LIGHTMGR->getSpecialLight( LightManager::slSunLightType );
- // fill in water's transform
- sgData.objTrans = &getRenderTransform();
- // fog
- sgData.setFogParams( state->getSceneManager()->getFogData() );
- // misc
- sgData.backBuffTex = REFLECTMGR->getRefractTex();
- sgData.reflectTex = mPlaneReflector.reflectTex;
- sgData.wireframe = GFXDevice::getWireframe() || smWireframe;
- return sgData;
- }
- void WaterPlane::setShaderParams( SceneRenderState *state, BaseMatInstance* mat, const WaterMatParams& paramHandles)
- {
- // Set variables that will be assigned to shader consts within WaterCommon
- // before calling Parent::setShaderParams
- mUndulateMaxDist = mGridElementSize * mGridSizeMinusOne * 0.5f;
- Parent::setShaderParams( state, mat, paramHandles );
- // Now set the rest of the shader consts that are either unique to this
- // class or that WaterObject leaves to us to handle...
- MaterialParameters* matParams = mat->getMaterialParameters();
- // set vertex shader constants
- //-----------------------------------
- matParams->setSafe(paramHandles.mGridElementSizeSC, (F32)mGridElementSize);
- //matParams->setSafe( paramHandles.mReflectTexSizeSC, mReflectTexSize );
- if ( paramHandles.mModelMatSC->isValid() )
- matParams->set(paramHandles.mModelMatSC, getRenderTransform(), GFXSCT_Float4x4);
- // set pixel shader constants
- //-----------------------------------
- LinearColorF c( mWaterFogData.color );
- matParams->setSafe( paramHandles.mBaseColorSC, c );
-
- // By default we need to show a true reflection is fullReflect is enabled and
- // we are above water.
- F32 reflect = mPlaneReflector.isEnabled() && !isUnderwater( state->getCameraPosition() );
-
- // If we were occluded the last frame a query was fetched ( not necessarily last frame )
- // and we weren't updated last frame... we don't have a valid texture to show
- // so use the cubemap / fake reflection color this frame.
- if ( mPlaneReflector.lastUpdateMs != REFLECTMGR->getLastUpdateMs() && mPlaneReflector.isOccluded() )
- reflect = false;
- //Point4F reflectParams( getRenderPosition().z, mReflectMinDist, mReflectMaxDist, reflect );
- Point4F reflectParams( getRenderPosition().z, 0.0f, 1000.0f, !reflect );
-
- // TODO: This is a hack... why is this broken... check after
- // we merge advanced lighting with trunk!
- //
- reflectParams.z = 0.0f;
- matParams->setSafe( paramHandles.mReflectParamsSC, reflectParams );
- VectorF reflectNorm( 0, 0, 1 );
- matParams->setSafe(paramHandles.mReflectNormalSC, reflectNorm );
- }
- void WaterPlane::prepRenderImage( SceneRenderState *state )
- {
- PROFILE_SCOPE(WaterPlane_prepRenderImage);
- if( !state->isDiffusePass() )
- return;
- mBasicLighting = dStricmp( LIGHTMGR->getId(), "BLM" ) == 0;
- mUnderwater = isUnderwater( state->getCameraPosition() );
- mMatrixSet->setSceneView(GFX->getWorldMatrix());
-
- const Frustum &frustum = state->getCameraFrustum();
- if ( mPrimBuff.isNull() ||
- mGenerateVB ||
- frustum != mFrustum )
- {
- mFrustum = frustum;
- setupVBIB( state );
- mGenerateVB = false;
- MatrixF proj( true );
- MathUtils::getZBiasProjectionMatrix( 0.0001f, mFrustum, &proj );
- mMatrixSet->setSceneProjection(proj);
- }
- _getWaterPlane( state->getCameraPosition(), mWaterPlane, mWaterPos );
- mWaterFogData.plane = mWaterPlane;
- mPlaneReflector.refplane = mWaterPlane;
- updateUnderwaterEffect( state );
- ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
- ri->renderDelegate.bind( this, &WaterObject::renderObject );
- ri->type = RenderPassManager::RIT_Water;
- state->getRenderPass()->addInst( ri );
- //mRenderUpdateCount++;
- }
- void WaterPlane::innerRender( SceneRenderState *state )
- {
- GFXDEBUGEVENT_SCOPE( WaterPlane_innerRender, ColorI( 255, 0, 0 ) );
- const Point3F &camPosition = state->getCameraPosition();
- Point3F rvec, fvec, uvec, pos;
- const MatrixF &objMat = getTransform(); //getRenderTransform();
- const MatrixF &camMat = state->getCameraTransform();
- MatrixF renderMat( true );
- camMat.getColumn( 1, &fvec );
- uvec.set( 0, 0, 1 );
- rvec = mCross( fvec, uvec );
- rvec.normalize();
- fvec = mCross( uvec, rvec );
- pos = camPosition;
- pos.z = objMat.getPosition().z;
- renderMat.setColumn( 0, rvec );
- renderMat.setColumn( 1, fvec );
- renderMat.setColumn( 2, uvec );
- renderMat.setColumn( 3, pos );
- setRenderTransform( renderMat );
- // Setup SceneData
- SceneData sgData = setupSceneGraphInfo( state );
- // set the material
- S32 matIdx = getMaterialIndex( camPosition );
-
- if ( !initMaterial( matIdx ) )
- return;
- BaseMatInstance *mat = mMatInstances[matIdx];
- WaterMatParams matParams = mMatParamHandles[matIdx];
- // render the geometry
- if ( mat )
- {
- // setup proj/world transform
- mMatrixSet->restoreSceneViewProjection();
- mMatrixSet->setWorld(getRenderTransform());
- setShaderParams( state, mat, matParams );
- while( mat->setupPass( state, sgData ) )
- {
- mat->setSceneInfo(state, sgData);
- mat->setTransforms(*mMatrixSet, state);
- setCustomTextures( matIdx, mat->getCurPass(), matParams );
- // set vert/prim buffer
- GFX->setVertexBuffer( mVertBuff );
- GFX->setPrimitiveBuffer( mPrimBuff );
- GFX->drawIndexedPrimitive( GFXTriangleList, 0, 0, mVertCount, 0, mPrimCount );
- }
- }
- }
- bool WaterPlane::isUnderwater( const Point3F &pnt ) const
- {
- F32 height = getPosition().z;
- F32 diff = pnt.z - height;
- return ( diff < 0.1 );
- }
- F32 WaterPlane::distanceTo( const Point3F& point ) const
- {
- if( isUnderwater( point ) )
- return 0.f;
- else
- return ( point.z - getPosition().z );
- }
- bool WaterPlane::buildPolyList( PolyListContext context, AbstractPolyList* polyList, const Box3F& box, const SphereF& )
- {
- if(context == PLC_Navigation)
- {
- polyList->setObject( this );
- polyList->setTransform( &MatrixF::Identity, Point3F( 1.0f, 1.0f, 1.0f ) );
- F32 z = getPosition().z;
- Point3F
- p0(box.minExtents.x, box.maxExtents.y, z),
- p1(box.maxExtents.x, box.maxExtents.y, z),
- p2(box.maxExtents.x, box.minExtents.y, z),
- p3(box.minExtents.x, box.minExtents.y, z);
- // Add vertices to poly list.
- U32 v0 = polyList->addPoint(p0);
- polyList->addPoint(p1);
- polyList->addPoint(p2);
- polyList->addPoint(p3);
- // Add plane between first three vertices.
- polyList->begin(0, 0);
- polyList->vertex(v0);
- polyList->vertex(v0+1);
- polyList->vertex(v0+2);
- polyList->plane(v0, v0+1, v0+2);
- polyList->end();
- // Add plane between last three vertices.
- polyList->begin(0, 1);
- polyList->vertex(v0+2);
- polyList->vertex(v0+3);
- polyList->vertex(v0);
- polyList->plane(v0+2, v0+3, v0);
- polyList->end();
- return true;
- }
- return false;
- }
- void WaterPlane::inspectPostApply()
- {
- Parent::inspectPostApply();
- setMaskBits( UpdateMask );
- }
- void WaterPlane::setTransform( const MatrixF &mat )
- {
- // We only accept the z value from the new transform.
- MatrixF newMat( true );
-
- Point3F newPos = getPosition();
- newPos.z = mat.getPosition().z;
- newMat.setPosition( newPos );
- Parent::setTransform( newMat );
- // Parent::setTransforms ends up setting our worldBox to something other than
- // global, so we have to set it back... but we can't actually call setGlobalBounds
- // again because it does extra work adding and removing us from the container.
- mGlobalBounds = true;
- mObjBox.minExtents.set(-1e10, -1e10, -1e10);
- mObjBox.maxExtents.set( 1e10, 1e10, 1e10);
- // Keep mWaterPlane up to date.
- mWaterFogData.plane.set( 0, 0, 1, -getPosition().z );
- }
- void WaterPlane::onStaticModified( const char* slotName, const char*newValue )
- {
- Parent::onStaticModified( slotName, newValue );
- if ( dStricmp( slotName, "surfMaterial" ) == 0 )
- setMaskBits( MaterialMask );
- }
- bool WaterPlane::castRay(const Point3F& start, const Point3F& end, RayInfo* info )
- {
- // Simply look for the hit on the water plane
- // and ignore any future issues with waves, etc.
- const Point3F norm(0,0,1);
- PlaneF plane( Point3F::Zero, norm );
- F32 hit = plane.intersect( start, end );
- if ( hit < 0.0f || hit > 1.0f )
- return false;
-
- info->t = hit;
- info->object = this;
- info->point = start + ( ( end - start ) * hit );
- info->normal = norm;
- info->material = mMatInstances[ WaterMat ];
- return true;
- }
- F32 WaterPlane::getWaterCoverage( const Box3F &testBox ) const
- {
- F32 posZ = getPosition().z;
-
- F32 coverage = 0.0f;
- if ( posZ > testBox.minExtents.z )
- {
- if ( posZ < testBox.maxExtents.z )
- coverage = (posZ - testBox.minExtents.z) / (testBox.maxExtents.z - testBox.minExtents.z);
- else
- coverage = 1.0f;
- }
- return coverage;
- }
- F32 WaterPlane::getSurfaceHeight( const Point2F &pos ) const
- {
- return getPosition().z;
- }
- void WaterPlane::onReflectionInfoChanged()
- {
- /*
- if ( isClientObject() && GFX->getPixelShaderVersion() >= 1.4 )
- {
- if ( mFullReflect )
- REFLECTMGR->registerObject( this, ReflectDelegate( this, &WaterPlane::updateReflection ), mReflectPriority, mReflectMaxRateMs, mReflectMaxDist );
- else
- {
- REFLECTMGR->unregisterObject( this );
- mReflectTex = NULL;
- }
- }
- */
- }
- void WaterPlane::setGridSize( U32 inSize )
- {
- if ( inSize == mGridSize )
- return;
- // GridSize must be an odd number.
- //if ( inSize % 2 == 0 )
- // inSize++;
- // GridSize must be at least 1
- inSize = getMax( inSize, (U32)1 );
- mGridSize = inSize;
- mGridSizeMinusOne = mGridSize - 1;
- mGenerateVB = true;
- setMaskBits( UpdateMask );
- }
- void WaterPlane::setGridElementSize( F32 inSize )
- {
- if ( inSize == mGridElementSize )
- return;
- // GridElementSize must be greater than 0
- inSize = getMax( inSize, 0.0001f );
- mGridElementSize = inSize;
- mGenerateVB = true;
- setMaskBits( UpdateMask );
- }
- bool WaterPlane::protectedSetGridSize( void *obj, const char *index, const char *data )
- {
- WaterPlane *object = static_cast<WaterPlane*>(obj);
- S32 size = dAtoi( data );
- object->setGridSize( size );
- // We already set the field.
- return false;
- }
- bool WaterPlane::protectedSetGridElementSize( void *obj, const char *index, const char *data )
- {
- WaterPlane *object = static_cast<WaterPlane*>(obj);
- F32 size = dAtof( data );
- object->setGridElementSize( size );
- // We already set the field.
- return false;
- }
- void WaterPlane::_getWaterPlane( const Point3F &camPos, PlaneF &outPlane, Point3F &outPos )
- {
- outPos = getPosition();
- outPlane.set( outPos, Point3F(0,0,1) );
- }
|