1
0
forked from 0ad/0ad

# Added fancy water.

This was SVN commit r3897.
This commit is contained in:
Matei 2006-05-28 02:13:32 +00:00
parent 27c38e2fc8
commit 106f59c5c7
8 changed files with 327 additions and 19 deletions

View File

@ -43,4 +43,11 @@ static inline int RoundUpToPowerOf2(int x)
return d<<1;
}
inline float sgn(float a)
{
if (a > 0.0f) return 1.0f;
if (a < 0.0f) return -1.0f;
return 0.0f;
}
#endif

View File

@ -44,6 +44,15 @@ CMatrix3D::CMatrix3D(float a11,float a12,float a13,float a14,float a21,float a22
_44=a44;
}
CMatrix3D::CMatrix3D(float data[])
{
for(int i=0; i<16; i++)
{
_data[i] = data[i];
}
}
//Matrix multiplication
CMatrix3D CMatrix3D::operator*(const CMatrix3D& matrix) const
{

View File

@ -31,6 +31,7 @@ public:
CMatrix3D();
CMatrix3D(float a11,float a12,float a13,float a14,float a21,float a22,float a23,float a24,
float a31,float a32,float a33,float a34,float a41,float a42,float a43,float a44);
CMatrix3D(float data[]);
// accessors to individual elements of matrix
float& operator()(int col,int row) {

View File

@ -933,6 +933,220 @@ void CRenderer::RenderTransparentModels()
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// GetModelViewProjectionMatrix: save the current OpenGL model-view-projection matrix
CMatrix3D CRenderer::GetModelViewProjectionMatrix()
{
CMatrix3D proj;
CMatrix3D view;
glGetFloatv( GL_PROJECTION_MATRIX, &proj._11 );
glGetFloatv( GL_MODELVIEW_MATRIX, &view._11 );
return( proj * view );
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// SetObliqueFrustumClipping: change the near plane to the given clip plane (in world space)
// Based on code from Game Programming Gems 5, from http://www.terathon.com/code/oblique.html
// - cp is a clip plane in camera space (cp.dot(v) = 0 for any vector v on the plane)
// - sign is 1 or -1, to specify the side to clip on
void CRenderer::SetObliqueFrustumClipping(const CVector4D& cp, int sign)
{
float matrix[16];
CVector4D q;
// First, we'll convert the given clip plane to camera space, then we'll
// Get the view matrix and normal matrix (top 3x3 part of view matrix)
CMatrix3D viewMatrix;
m_ViewCamera.m_Orientation.GetInverse(viewMatrix);
CMatrix3D normalMatrix = viewMatrix;
normalMatrix._14 = 0;
normalMatrix._24 = 0;
normalMatrix._34 = 0;
normalMatrix._44 = 1;
normalMatrix._41 = 0;
normalMatrix._42 = 0;
normalMatrix._43 = 0;
// Convert the normal to camera space
CVector4D planeNormal(cp.m_X, cp.m_Y, cp.m_Z, 0);
planeNormal = normalMatrix.Transform(planeNormal);
planeNormal.normalize();
// Find a point on the plane: we'll take the normal times -D
float oldD = cp.m_W;
CVector4D pointOnPlane(-oldD * cp.m_X, -oldD * cp.m_Y, -oldD * cp.m_Z, 1);
pointOnPlane = viewMatrix.Transform(pointOnPlane);
float newD = -pointOnPlane.dot(planeNormal);
// Now create a clip plane from the new normal and new D
CVector4D camPlane = planeNormal;
camPlane.m_W = newD;
// Grab the current projection matrix from OpenGL
glGetFloatv(GL_PROJECTION_MATRIX, matrix);
// Calculate the clip-space corner point opposite the clipping plane
// as (sgn(camPlane.x), sgn(camPlane.y), 1, 1) and
// transform it into camera space by multiplying it
// by the inverse of the projection matrix
q.m_X = (sgn(camPlane.m_X) + matrix[8]) / matrix[0];
q.m_Y = (sgn(camPlane.m_Y) + matrix[9]) / matrix[5];
q.m_Z = -1.0f;
q.m_W = (1.0f + matrix[10]) / matrix[14];
// Calculate the scaled plane vector
CVector4D c = camPlane * (sign * 2.0f / camPlane.dot(q));
// Replace the third row of the projection matrix
matrix[2] = c.m_X;
matrix[6] = c.m_Y;
matrix[10] = c.m_Z + 1.0f;
matrix[14] = c.m_W;
// Load it back into OpenGL
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(matrix);
glMatrixMode(GL_MODELVIEW);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// RenderReflections: render the water reflections to the reflection texture
void CRenderer::RenderReflections()
{
MICROLOG(L"render reflections");
WaterManager& wm = m->waterManager;
// Remember old camera
CCamera normalCamera = m_ViewCamera;
// Temporarily change the camera to one that is reflected
m_ViewCamera.m_Orientation.Translate(0, -wm.m_WaterHeight, 0);
m_ViewCamera.m_Orientation.Scale(1, -1, 1);
m_ViewCamera.m_Orientation.Translate(0, wm.m_WaterHeight, 0);
SViewPort vp;
vp.m_Height = wm.m_ReflectionTextureSize;
vp.m_Width = wm.m_ReflectionTextureSize;
vp.m_X = 0;
vp.m_Y = 0;
m_ViewCamera.SetViewPort(&vp);
m_ViewCamera.SetProjection(1, 5000, DEGTORAD(25));
SetCamera(m_ViewCamera, m_CullCamera);
CVector4D camPlane(0, 1, 0, -wm.m_WaterHeight);
SetObliqueFrustumClipping(camPlane, -1);
// Save the model-view-projection matrix so the shaders can use it for projective texturing
wm.m_ReflectionMatrix = GetModelViewProjectionMatrix();
// Disable backface culling so trees render properly (it might also be possible to flip
// the culling direction here, but this seems to lead to problems)
glDisable(GL_CULL_FACE);
// Make the depth buffer work backwards; there seems to be some oddness with
// oblique frustum clipping and the "sign" parameter here
glClearDepth(0);
glClear(GL_DEPTH_BUFFER_BIT);
glDepthFunc(GL_GEQUAL);
// Render sky, terrain and models
m->skyManager.RenderSky();
oglCheck();
RenderPatches();
oglCheck();
RenderModels();
oglCheck();
RenderTransparentModels();
oglCheck();
// Copy the image to a texture
pglActiveTextureARB(GL_TEXTURE0_ARB);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, wm.m_ReflectionTexture);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0,
wm.m_ReflectionTextureSize, wm.m_ReflectionTextureSize);
//Reset old camera and re-enable backface culling
SetCamera(normalCamera, m_CullCamera);
glEnable(GL_CULL_FACE);
//glClearDepth(1);
//glClear(GL_DEPTH_BUFFER_BIT);
//glDepthFunc(GL_LEQUAL);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// RenderRefractions: render the water refractions to the refraction texture
void CRenderer::RenderRefractions()
{
MICROLOG(L"render refractions");
WaterManager& wm = m->waterManager;
// Remember old camera
CCamera normalCamera = m_ViewCamera;
// Temporarily change the camera to have a higher FOV (so we get bits on the edge of the view)
SViewPort vp;
vp.m_Height = wm.m_RefractionTextureSize;
vp.m_Width = wm.m_RefractionTextureSize;
vp.m_X = 0;
vp.m_Y = 0;
m_ViewCamera.SetViewPort(&vp);
m_ViewCamera.SetProjection(1, 5000, DEGTORAD(25));
SetCamera(m_ViewCamera, m_CullCamera);
CVector4D camPlane(0, 1, 0, -wm.m_WaterHeight);
SetObliqueFrustumClipping(camPlane, -1);
// Save the model-view-projection matrix so the shaders can use it for projective texturing
wm.m_RefractionMatrix = GetModelViewProjectionMatrix();
// Disable backface culling so trees render properly (it might also be possible to flip
// the culling direction here, but this seems to lead to problems)
//glDisable(GL_CULL_FACE);
// Make the depth buffer work backwards; there seems to be some oddness with
// oblique frustum clipping and the "sign" parameter here
glClearDepth(0);
glClearColor(0.5f, 0.5f, 0.5f, 1.0f); // a neutral gray to blend in with shores
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDepthFunc(GL_GEQUAL);
// Render terrain and models
//m->skyManager.RenderSky();
//oglCheck();
RenderPatches();
oglCheck();
RenderModels();
oglCheck();
RenderTransparentModels();
oglCheck();
// Copy the image to a texture
pglActiveTextureARB(GL_TEXTURE0_ARB);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, wm.m_RefractionTexture);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0,
wm.m_RefractionTextureSize, wm.m_RefractionTextureSize);
//Reset old camera and re-enable backface culling
SetCamera(normalCamera, m_CullCamera);
glEnable(GL_CULL_FACE);
glClearDepth(1);
glDepthFunc(GL_LEQUAL);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// FlushFrame: force rendering of any batched objects
void CRenderer::FlushFrame()
@ -968,6 +1182,15 @@ void CRenderer::FlushFrame()
oglCheck();
if(m_Options.m_FancyWater)
{
// render reflected and refracted scenes, then re-clear the screen
RenderReflections();
RenderRefractions();
glClearColor(m_ClearColor[0],m_ClearColor[1],m_ClearColor[2],m_ClearColor[3]);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
// render sky; this is done before everything so that
// (a) we can use a box around the camera instead of placing it "infinitely far away"
// (we just disable depth write so that this doesn't affect future rendering)
@ -1236,9 +1459,6 @@ bool CRenderer::IsTextureTransparent(CTexture* texture)
return (flags & TEX_ALPHA) != 0;
}
static inline void CopyTriple(unsigned char* dst,const unsigned char* src)
{
dst[0]=src[0];

View File

@ -273,6 +273,9 @@ public:
// return the current cull camera
const CCamera& GetCullCamera() const { return m_CullCamera; }
// get the current OpenGL model-view-projection matrix into the given float[]
CMatrix3D GetModelViewProjectionMatrix();
/**
* GetWaterManager: Return the renderer's water manager.
*
@ -345,9 +348,16 @@ protected:
// shadow rendering stuff
void RenderShadowMap();
// render water reflection and refraction textures
void RenderReflections();
void RenderRefractions();
// debugging
void DisplayFrustum();
// enable oblique frustum clipping with the given clip plane
void SetObliqueFrustumClipping(const CVector4D& clipPlane, int sign);
// RENDERER DATA:
/// Private data that is not needed by inline functions
CRendererInternals* m;

View File

@ -448,16 +448,6 @@ void TerrainRenderer::RenderWater()
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PRIMARY_COLOR_ARB);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
}
else
{
// Temp stuff for testing
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
}
// Set the proper LOD bias
glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, g_Renderer.m_Options.m_LodBias);
@ -470,25 +460,38 @@ void TerrainRenderer::RenderWater()
if(fancy)
{
ogl_program_use( m->fancyWaterShader );
// Bind reflection and refraction textures on texture units 1 and 2
pglActiveTextureARB( GL_TEXTURE1_ARB );
glEnable( GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D, WaterMgr->m_ReflectionTexture );
pglActiveTextureARB( GL_TEXTURE2_ARB );
glEnable( GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D, WaterMgr->m_RefractionTexture );
const CLightEnv& lightEnv = g_Renderer.GetLightEnv();
//SetAmbient(lightenv.m_TerrainAmbientColor);
//SetSunDir(lightenv.GetSunDir());
//SetSunColor(lightenv.m_SunColor);
// Bind water shader and set arguments
ogl_program_use( m->fancyWaterShader );
GLint ambient = ogl_program_get_uniform_location( m->fancyWaterShader, "ambient" );
GLint sunDir = ogl_program_get_uniform_location( m->fancyWaterShader, "sunDir" );
GLint sunColor = ogl_program_get_uniform_location( m->fancyWaterShader, "sunColor" );
GLint shininess = ogl_program_get_uniform_location( m->fancyWaterShader, "shininess" );
GLint cameraPos = ogl_program_get_uniform_location( m->fancyWaterShader, "cameraPos" );
GLint reflectionMatrix = ogl_program_get_uniform_location( m->fancyWaterShader, "reflectionMatrix" );
GLint refractionMatrix = ogl_program_get_uniform_location( m->fancyWaterShader, "refractionMatrix" );
GLint normalMap = ogl_program_get_uniform_location( m->fancyWaterShader, "normalMap" );
GLint reflectionMap = ogl_program_get_uniform_location( m->fancyWaterShader, "reflectionMap" );
GLint refractionMap = ogl_program_get_uniform_location( m->fancyWaterShader, "refractionMap" );
const CLightEnv& lightEnv = g_Renderer.GetLightEnv();
pglUniform3fvARB( ambient, 1, &lightEnv.m_TerrainAmbientColor.X );
pglUniform3fvARB( sunDir, 1, &lightEnv.GetSunDir().X );
pglUniform3fvARB( sunColor, 1, &lightEnv.m_SunColor.X );
pglUniform1fARB( shininess, 200.0f );
pglUniformMatrix4fvARB( reflectionMatrix, 1, false, &WaterMgr->m_ReflectionMatrix._11 );
pglUniformMatrix4fvARB( refractionMatrix, 1, false, &WaterMgr->m_RefractionMatrix._11 );
pglUniform1iARB( normalMap, 0 ); // texture unit 0
pglUniform1iARB( reflectionMap, 1 ); // texture unit 1
pglUniform1iARB( refractionMap, 2 ); // texture unit 2
const CCamera& camera = g_Renderer.GetViewCamera();
CVector3D camPos = camera.m_Orientation.GetTranslation();
@ -497,7 +500,7 @@ void TerrainRenderer::RenderWater()
vertexDepth = ogl_program_get_attrib_location( m->fancyWaterShader, "vertexDepth" );
}
float repeatFreq = (fancy ? 10.0f : 16.0f);
float repeatFreq = (fancy ? 17.0f : 16.0f);
glBegin(GL_QUADS);
@ -574,6 +577,18 @@ void TerrainRenderer::RenderWater()
if(fancy)
{
// Unbind the refraction/reflection textures and the shader
pglActiveTextureARB( GL_TEXTURE1_ARB );
glBindTexture( GL_TEXTURE_2D, 0 );
glDisable( GL_TEXTURE_2D );
pglActiveTextureARB( GL_TEXTURE2_ARB );
glBindTexture( GL_TEXTURE_2D, 0 );
glDisable( GL_TEXTURE_2D );
pglActiveTextureARB( GL_TEXTURE0_ARB );
ogl_program_use( 0 );
}

View File

@ -15,10 +15,13 @@
#include "lib/res/graphics/tex.h"
#include "lib/res/graphics/ogl_tex.h"
#include "maths/MathUtil.h"
#include "ps/CLogger.h"
#include "ps/Loader.h"
#include "renderer/WaterManager.h"
#include "renderer/Renderer.h"
#define LOG_CATEGORY "graphics"
@ -45,6 +48,8 @@ WaterManager::WaterManager()
m_SWaterScrollCounter = 0;
m_TWaterScrollCounter = 0;
m_WaterCurrentTex = 0;
m_ReflectionTexture = 0;
m_RefractionTexture = 0;
m_WaterTexTimer = 0.0;
for (uint i = 0; i < ARRAY_SIZE(m_WaterTexture); i++)
@ -81,6 +86,7 @@ int WaterManager::LoadWaterTextures()
char filename[PATH_MAX];
// Load diffuse grayscale images (for non-fancy water)
while (cur_loading_water_tex < num_textures)
{
snprintf(filename, ARRAY_SIZE(filename), "art/textures/animated/water/%s/diffuse%02d.dds",
@ -97,6 +103,7 @@ int WaterManager::LoadWaterTextures()
LDR_CHECK_TIMEOUT(cur_loading_water_tex, num_textures + num_normal_maps);
}
// Load normalmaps (for fancy water)
while (cur_loading_normal_map < num_normal_maps)
{
snprintf(filename, ARRAY_SIZE(filename), "art/textures/animated/water/%s/normal%02d.dds",
@ -113,6 +120,37 @@ int WaterManager::LoadWaterTextures()
LDR_CHECK_TIMEOUT(num_textures + cur_loading_normal_map, num_textures + num_normal_maps);
}
// Set the size to the largest power of 2 that is <= to the window height, so
// the reflection/reflaction images will fit within the window
// (alternative: use FBO's, which can have arbitrary size - but do we need
// the reflection/refraction textures to be that large?)
int size = RoundUpToPowerOf2(g_Renderer.GetHeight());
if(size > g_Renderer.GetHeight()) size /= 2;
m_ReflectionTextureSize = size;
m_RefractionTextureSize = size;
// Create reflection texture
glGenTextures(1, &m_ReflectionTexture);
glBindTexture(GL_TEXTURE_2D, m_ReflectionTexture);
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB,
m_ReflectionTextureSize, m_ReflectionTextureSize,
0, GL_RGB, GL_UNSIGNED_BYTE, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// Create refraction texture
glGenTextures(1, &m_RefractionTexture);
glBindTexture(GL_TEXTURE_2D, m_RefractionTexture);
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB,
m_RefractionTextureSize, m_RefractionTextureSize,
0, GL_RGB, GL_UNSIGNED_BYTE, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
return 0;
}

View File

@ -12,6 +12,7 @@
#define WATERMANAGER_H
#include "ps/Overlay.h"
#include "maths/Matrix3D.h"
/**
* Class WaterManager: Maintain water settings and textures.
@ -24,6 +25,13 @@ class WaterManager
public:
Handle m_WaterTexture[60];
Handle m_NormalMap[60];
GLuint m_ReflectionTexture;
GLuint m_RefractionTexture;
uint m_ReflectionTextureSize;
uint m_RefractionTextureSize;
CMatrix3D m_ReflectionMatrix; // model-view-projection matrix for reflected camera
CMatrix3D m_RefractionMatrix; // model-view-projection matrix for refraction camera
int m_WaterCurrentTex;
CColor m_WaterColor;
bool m_RenderWater;