📄 waterblock.cc
字号:
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "terrain/waterBlock.h"
#include "console/consoleTypes.h"
#include "sceneGraph/sceneGraph.h"
#include "sceneGraph/sceneState.h"
#include "core/bitStream.h"
#include "math/mBox.h"
#include "dgl/dgl.h"
#include "core/color.h"
#include "terrain/terrData.h"
#include "terrain/terrRender.h"
#include "math/mathIO.h"
#include "sceneGraph/sgUtil.h"
#include "audio/audioDataBlock.h"
//==============================================================================
IMPLEMENT_CO_NETOBJECT_V1(WaterBlock);
//==============================================================================
bool WaterBlock::mCameraSubmerged = false;
U32 WaterBlock::mSubmergedType = 0;
TextureHandle WaterBlock::mSubmergeTexture[WC_NUM_SUBMERGE_TEX];
//==============================================================================
// I know this is a bit of a hack. I've done this in order to avoid a coupling
// between the fluid and the rest of the system.
//
static SceneState* pSceneState = NULL;
static F32 FogFunction( F32 Distance, F32 DeltaZ )
{
return( pSceneState->getHazeAndFog( Distance, DeltaZ ) );
}
//==============================================================================
WaterBlock::WaterBlock()
{
mNetFlags.set(Ghostable | ScopeAlways);
mTypeMask = WaterObjectType;
mObjBox.min.set( 0, 0, 0 );
mObjBox.max.set( 1, 1, 1 );
mTile = true;
mLiquidType = eOceanWater;
mDensity = 1;
mViscosity = 15;
mWaveMagnitude = 1.0f;
mSurfaceTexture = TextureHandle();
mSpecMaskTex = TextureHandle();
mSurfaceOpacity = 0.75f;
mEnvMapOverTexture = TextureHandle();
mEnvMapUnderTexture = TextureHandle();
mEnvMapIntensity = 0.4f;
mShoreTexture = TextureHandle();
mRemoveWetEdges = false;
mAudioEnvironment = 0;
// lets be good little programmers and initialize our data!
mSurfaceName = NULL;
mSpecMaskName = NULL;
mEnvMapOverName = NULL;
mEnvMapUnderName = NULL;
mShoreName = NULL;
dMemset( mSubmergeName, 0, sizeof( mSubmergeName ) );
mpTerrain = NULL;
mSurfaceZ = 0.0f;
mEditorApplied = false;
mShoreDepth = 20.0f;
mMinAlpha = 0.03f;
mMaxAlpha = 1.0f;
mDepthGradient = 1.0f;
mUseDepthMap = true;
mTessellationSurface = 50;
mTessellationShore = 60;
mSurfaceParallax = 0.5f;
mFlowAngle = 0.0f;
mFlowRate = 0.0f;
mDistortGridScale = 0.1f;
mDistortMagnitude = 0.05f;
mDistortTime = 0.5f;
mFluid.SetFogFn( FogFunction );
mSpecColor.set( 1.0, 1.0, 1.0, 1.0 );
mSpecPower = 6;
}
//==============================================================================
WaterBlock::~WaterBlock()
{
}
//==============================================================================
void WaterBlock::SnagTerrain( SceneObject* sceneObj, void * key )
{
WaterBlock* pWater = (WaterBlock*)key;
pWater->mpTerrain = dynamic_cast<TerrainBlock*>(sceneObj);
}
//==============================================================================
void WaterBlock::UpdateFluidRegion( void )
{
MatrixF M;
Point3F P;
P = mObjToWorld.getPosition();
P.x += 1024.0f;
P.y += 1024.0f;
mSurfaceZ = P.z + mObjScale.z;
mFluid.SetInfo( P.x,
P.y,
mObjScale.x, mObjScale.y,
mSurfaceZ,
mWaveMagnitude,
mSurfaceOpacity,
mEnvMapIntensity,
mRemoveWetEdges,
mUseDepthMap,
mTessellationSurface,
mTessellationShore,
mSurfaceParallax,
mFlowAngle,
mFlowRate,
mDistortGridScale,
mDistortMagnitude,
mDistortTime,
mSpecColor,
mSpecPower,
mTile);
P.x -= 1024.0f;
P.y -= 1024.0f;
M.identity();
M.setPosition( P );
Parent::setTransform( M );
resetWorldBox();
if( isServerObject() )
setMaskBits(1);
}
//==============================================================================
void WaterBlock::CalculateDepthMaps(void)
{
// Generate Depth Textures.
GenerateDepthTextures(mDepthBitmap, mDepthTexture, false);
GenerateDepthTextures(mShoreDepthBitmap, mShoreDepthTexture, true);
}
//==============================================================================
/// Generate depth textures for water interaction with terrain.
///
/// What we are doing here is sample the terrain height at it's own resolution over the area of the
/// defined waterblock. With these height points we can calculate an appropriate alpha value for the
/// depth-map texture texel. This results in a *very* coarse alpha-map but this is resolved by passing
/// the texture through an iterative blur-convolution.
///
/// The resultant texture is used to alpha-blend in the surfaces and environment map using multi-texturing.
/// @author Melv May
void WaterBlock::GenerateDepthTextures(GBitmap* pBitmap, TextureHandle& mTexture, bool ShoreFlag)
{
// Is this a client object?
if (isClientObject())
{
// Yes, so we should have a depth-map bitmap.
AssertWarn(pBitmap != NULL, "Waterblock: We should have a depth-map bitmap!");
// Do we have the terrain yet?
if (mpTerrain)
{
F32 DepthPoint;
U32 FluidPointColour;
U32* pTexelBlockOutput;
// Fetch the Bitmaps Data.
U32* pDepthBits = (U32*)pBitmap->getAddress(0,0,0);
// Calculate Fluid Min/Max Colour-Alpha.
const U32 mFluidColour = 0xffffff;
const U32 mMinColour = (mFluidColour + (((U32)(mMinAlpha * 255)) << 24));
const U32 mMaxColour = (mFluidColour + (((U32)(mMaxAlpha * 255)) << 24));
// Calculate the Depth Bitmap Resolutions.
F32 DepthSqrResX = pBitmap->getWidth(0) / mFluid.m_SquaresInX;
F32 DepthSqrResY = pBitmap->getHeight(0) / mFluid.m_SquaresInY;
// Calculate the Inverse Depth Bitmap Resolutions.
F32 InvDepthSqrResX = 1.0f / DepthSqrResX;
F32 InvDepthSqrResY = 1.0f / DepthSqrResY;
// Calculate the Depth Bitmap Texel Resolutions.
F32 DepthTexResX = mObjScale.x / eDepthMapResolution;
F32 DepthTexResY = mObjScale.y / eDepthMapResolution;
// Calculate the Depth Bitmap Strides.
U32 XStride = pBitmap->getWidth(0);
U32 YStride = pBitmap->getHeight(0);
// Calculate the FluidLevel.
F32 FluidLevel = mSurfaceZ;
F32 Height;
// Fetch the Waterblock Position.
Point3F TerrainPos = mObjToWorld.getPosition();
// Change Spaces.
TerrainPos.x += 1024.0f;
TerrainPos.y += 1024.0f;
// Terrain Height Offsets.
F32 TerrainOffsetX;
F32 TerrainOffsetY = 0;
// Calculate Alpha Range.
F32 AlphaRange = mMaxAlpha - mMinAlpha;
// Calculate depth Alpha-Texel Map.
for (s32 t = 0; t < eDepthMapResolution; t++)
{
// Reset Terrain Height Offset X.
TerrainOffsetX = 0;
for (s32 s = 0; s < eDepthMapResolution; s++)
{
// Fetch Terrain Height at current position.
if ( mpTerrain->getHeight( Point2F(TerrainPos.x + TerrainOffsetX , TerrainPos.y + TerrainOffsetY),
&Height) )
{
// Got a valid height so ...
// Calculate Depth Point.
DepthPoint = FluidLevel - Height;
// Are we below the minimum depth?
if (DepthPoint <= 0)
{
// Yes, so set to minimum colour/alpha.
FluidPointColour = mMinColour;
}
// ... so are we below the maximum depth?
else if (DepthPoint < mShoreDepth)
{
// Normalise Range.
F32 NormRange = mClampF(DepthPoint / mShoreDepth, 0.0f, 1.0f);
// Calculate Depth Alpha.
F32 DepthAlpha = (AlphaRange * mPow(NormRange, 1.0f / mDepthGradient)) + mMinAlpha;
// Calculate Resultant Fluid Colour/Alpha.
FluidPointColour = ((U32)(DepthAlpha*255)) << 24 | mFluidColour;
}
// ... out of our depth range ...
else
{
// Are we doing a shoreline depth-map?
if (ShoreFlag)
{
// Yesm so normalise Range.
F32 NormRange = mClampF((DepthPoint-mShoreDepth) / mShoreDepth, 0.0f, 1.0f);
// Calculate Depth Alpha.
F32 DepthAlpha = mMaxAlpha - ((AlphaRange * mPow(NormRange, 1.0f / mDepthGradient)) + mMinAlpha);
// Calculate Resultant Fluid Colour/Alpha.
FluidPointColour = ((U32)(255*DepthAlpha)) << 24 | mFluidColour;
}
else
{
// No so clip to maximum colour/alpha.
FluidPointColour = mMaxColour;
}
}
}
else
{
// Eeek, empty grid square ...
FluidPointColour = mFluidColour;
}
// Calculate Position of Texel Block Origin.
pTexelBlockOutput = pDepthBits + (U32)(s + (t * YStride));
// Write Point Height to Texel.
*pTexelBlockOutput = convertLEndianToHost(FluidPointColour);
// Move to next Terrain Height Point.
TerrainOffsetX += DepthTexResX;
}
// Move to next Terrain Height Point.
TerrainOffsetY += DepthTexResY;
}
// Update the texture.
mTexture.refresh();
#if 0
// --------------------------------------------------------------------------------------
// DEBUG CODE: Dump the Depth Alpha-Map as a PNG file.
// --------------------------------------------------------------------------------------
// Output file.
FileStream fStream;
if(!fStream.open("depthmap.png", FileStream::Write))
{
Con::printf("Waterblock: Failed to open debug depth-map file!");
return;
}
else
{
mDepthTexture.getBitmap()->writePNG(fStream);
fStream.close();
}
#endif
// --------------------------------------------------------------------------------------
}
}
}
//==============================================================================
bool WaterBlock::onAdd()
{
#ifndef TGE_RPGCLIENT2 /// TGE_RPGIsClientObject
if( !isClientObject() )
#endif
{
// Make sure that the Fluid has had a chance to tweak the values.
UpdateFluidRegion();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -