I render my scene, then I render my scene again
to texture(1024x1024) with y-flipped camera.
That's ok, reflection is correct.
I also know how to map that texture to mesh.
But, deforming the mesh won't deform the texture :(
Also my rippling code is all messed up, it won't work good enough.
Class:
class DX9_Water
{
public:
Vertex *vertices;
DWORD *indices;
DWORD dwNumVertices, dwNumIndices, dwNumGridsAcross;
LPDIRECT3DSURFACE9 surface, stencil;
LPDIRECT3DTEXTURE9 lpReflectionTexture;
D3DSURFACE_DESC desc;
LPDIRECT3DTEXTURE9 psBumpMap;
Plane clip_plane;
Matrix matReflect, matRemap;
Material material;
float fSeaLevel, fA, fBlurryFactor;
float *fVerticeLevels; // Height of vertices
void Init(Vector vMin, Vector vMax, float fSeaLevel, float fBlurryLevel, DWORD dwNumGridsAcross, float fA, float fR, float fG, float fB);
void Render(DX9_Texture *tex);
void BuildReflectionTexture(void (*pRenderItems)(), DWORD color);
void Update(float fSpeed, float fWaveDepth);
DX9_Water();
virtual ~DX9_Water();
};
Init:
void DX9_Water::Init(Vector vMin, Vector vMax, float fSeaLevel, float fBlurryFactor, DWORD dwNumGridsAcross, float fA, float fR, float fG, float fB)
{
this ->dwNumGridsAcross = dwNumGridsAcross;
this ->fSeaLevel = fSeaLevel;
this ->fA = fA;
this ->fBlurryFactor = fBlurryFactor;
// Calculate x and z sizes
float fXSize = vMax.x - vMin.x;
float fZSize = vMax.z - vMin.z;
// Calculate sizes in world units
// Movement across the map is calculated as this
float fMovWorldDeltaX = (float)(fXSize / (float)dwNumGridsAcross);
float fMovWorldDeltaZ = (float)(fZSize / (float)dwNumGridsAcross);
// Calculate the number of vertices
dwNumVertices = (dwNumGridsAcross + 1) * (dwNumGridsAcross + 1);
// Calculate the number of indices
dwNumIndices = (dwNumGridsAcross * dwNumGridsAcross) * 6;
// Create the arrays
vertices = new Vertex[dwNumVertices];
memset(vertices, 0, sizeof(Vertex) * dwNumVertices);
indices = new DWORD[dwNumIndices];
memset(indices, 0, sizeof(DWORD) * dwNumIndices);
// Loop trough the whole map
float fWorldX = vMin.x, fWorldZ = vMin.z;
int iV = 0;
for(DWORD y = 0 ; y <= dwNumGridsAcross ; y++)
{
for(DWORD x = 0 ; x <= dwNumGridsAcross ; x++)
{
// The most important thing is to calculate
// U and V as the functions of sin
float U = (float)x / (float)dwNumGridsAcross;
float V = (float)y / (float)dwNumGridsAcross;
vertices[iV] = Vertex(Vector(fWorldX, 0, fWorldZ), Vector(0,1,0), U*32, V*32);
// Next vertices
iV++;
// Go on
fWorldX += fMovWorldDeltaX;
}
// Go on
fWorldX = vMin.x;
fWorldZ += fMovWorldDeltaZ;
}
// Create index table
DWORD dwI = 0;
DWORD dwG = 0;
// Calculate index table
for(y = 0 ; y <= dwNumGridsAcross - 1 ; y++)
{
for(DWORD x = 0 ; x <= dwNumGridsAcross - 1 ; x++)
{
indices[dwI+0] = dwG + dwNumGridsAcross + 1;
indices[dwI+1] = dwG + 1;
indices[dwI+2] = dwG;
indices[dwI+3] = dwG + dwNumGridsAcross + 2;
indices[dwI+4] = dwG + 1;
indices[dwI+5] = dwG + dwNumGridsAcross + 1;
dwI += 6;
dwG++;
}
dwG++;
}
// Calculate the normals
int _h = dwNumGridsAcross - 1;
for(int i = 0; i < _h; i++)
for(int j = 0; j < _h; j++)
{
Vector p1, p2, p3, v1, v2,tmp;
int v[4];
v[0] = i * dwNumGridsAcross + j;
v[1] = i * dwNumGridsAcross + j + 1;
v[2] = (i + 1) * dwNumGridsAcross + j;
v[3] = (i + 1) * dwNumGridsAcross + j + 1;
// Store the positions of first triangle into 3 usable vertices
p1 = Vector(vertices[v[0]].x,vertices[v[0]].y,vertices[v[0]].z);
p2 = Vector(vertices[v[3]].x,vertices[v[3]].y,vertices[v[3]].z);
p3 = Vector(vertices[v[2]].x,vertices[v[2]].y,vertices[v[2]].z);
// Calculate the triangle sides
v1 = p2 - p1;
v2 = p3 - p1;
// Calculate normal
D3DXVec3Cross(&tmp, &v1, &v2);
// add normal to the normal of all the vertices in the triangle
vertices[v[0]].nx += tmp.x; vertices[v[0]].ny += tmp.y; vertices[v[0]].nz += tmp.z;
vertices[v[3]].nx += tmp.x; vertices[v[3]].ny += tmp.y; vertices[v[3]].nz += tmp.z;
vertices[v[2]].nx += tmp.x; vertices[v[2]].ny += tmp.y; vertices[v[2]].nz += tmp.z;
// store the positions of second triangle into 3 usable vertices
p1 = Vector(vertices[v[1]].x,vertices[v[1]].y,vertices[v[1]].z);
p2 = Vector(vertices[v[3]].x,vertices[v[3]].y,vertices[v[3]].z);
p3 = Vector(vertices[v[0]].x,vertices[v[0]].y,vertices[v[0]].z);
// Calculate the triangle sides
v1 = p2 - p1;
v2 = p3 - p1;
// Calculate normal
D3DXVec3Cross(&tmp, &v1, &v2);
// add normal to the normal of all the vertices in the triangle
vertices[v[1]].nx += tmp.x; vertices[v[1]].ny += tmp.y; vertices[v[1]].nz += tmp.z;
vertices[v[3]].nx += tmp.x; vertices[v[3]].ny += tmp.y; vertices[v[3]].nz += tmp.z;
vertices[v[0]].nx += tmp.x; vertices[v[0]].ny += tmp.y; vertices[v[0]].nz += tmp.z;
}
// normalize all vertices
for(DWORD d = 0; d < dwNumVertices; d++)
{
Vector normal;
Vector normal_n(vertices[d].nx, vertices[d].ny, vertices[d].nz);
D3DXVec3Normalize(&normal, &normal_n);
vertices[d].nx = -normal.x;
vertices[d].ny = -normal.y;
vertices[d].nz = -normal.z;
}
D3DXCreateTexture(GFX.lpDevice, 1024, 1024, 1, D3DUSAGE_RENDERTARGET,
GFX.best_texture_format, D3DPOOL_DEFAULT, &lpReflectionTexture);
// Create a new rendertarget
lpReflectionTexture -> GetSurfaceLevel(0, &surface);
surface -> GetDesc(&desc);
// Create stencil
GFX.lpDevice->CreateDepthStencilSurface(desc.Width, desc.Height, GFX.d3d_modes[GFX.dwCurMode].formatStencil,D3DMULTISAMPLE_NONE,0,0,&stencil,0);
// Create vertice level array
fVerticeLevels = new float[dwNumVertices];
for(DWORD x = 0 ; x < dwNumVertices ; x++)
{
fVerticeLevels[x] = ((rand()%360) / 360.0f) * DOUB_PII;
}
// Reflect matrix
Vector vPoint(0, fSeaLevel,0);
Vector vNormal(0,1,0);
D3DXPlaneFromPointNormal(&clip_plane, &vPoint, &vNormal );
D3DXMatrixReflect(&matReflect, &clip_plane );
// Material
memset(&material, 0, sizeof(Material));
material.Diffuse.r = 1;
material.Diffuse.g = 1;
material.Diffuse.b = 1;
material.Diffuse.a = fA;
// Remap matrix
ZeroMemory(&matRemap,sizeof(Matrix));
// Calculate mirror transformation matrix
float fy = 1.0f / tanf(GFX.fCurFOV * 0.5f);
matRemap._11 = fy * 0.5f; // xscale
matRemap._22 = -matRemap._11; // yscale
matRemap._31 = 0.5f; // xpos
matRemap._32 = 0.5f; // ypos
matRemap._33 = 1.0f;
matRemap._44 = 1.0f;
}
BuildReflectionTexture:
void DX9_Water::BuildReflectionTexture(void(*pRenderItems)(void), DWORD color)
{
// Save the view and proj matrix
Matrix matViewSaved, matNewView;
GFX.lpDevice -> GetTransform( D3DTS_VIEW, &matViewSaved );
// Reflect camera in X-Z plane mirror
D3DXMatrixMultiply(&matNewView, &matReflect, &matViewSaved );
GFX.lpDevice -> SetTransform( D3DTS_VIEW, &matNewView );
// Set a clip plane, so that only objects above the plane are reflected
GFX.lpDevice -> SetClipPlane(0, clip_plane);
GFX.lpDevice -> SetRenderState( D3DRS_CLIPPLANEENABLE, 0x01 );
GFX.lpDevice -> SetRenderState( D3DRS_CULLMODE, D3DCULL_CW );
GFX.lpDevice->SetRenderTarget(0,surface);
GFX.lpDevice->SetDepthStencilSurface(stencil);
// Clear the target & zbuffer & stencil
GFX.lpDevice -> Clear(0,0,D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, color, 1, 0);
GFX.lpDevice -> Clear(0,0,D3DCLEAR_STENCIL, 0, 0, 0);
// Render the scene
pRenderItems();
GFX.lpDevice -> SetRenderTarget(0,GFX.back_buffer);
GFX.lpDevice -> SetDepthStencilSurface(GFX.stencil_buffer);
// Restore render states
GFX.lpDevice -> SetRenderState( D3DRS_CULLMODE, D3DCULL_CCW );
GFX.lpDevice -> SetRenderState( D3DRS_CLIPPLANEENABLE, 0x00 );
GFX.lpDevice -> SetTransform( D3DTS_VIEW, &matViewSaved );
}
Render:
void DX9_Water::Render(DX9_Texture *tex)
{
// MATERIAL
GFX.lpDevice -> SetMaterial(&material);
// REFLECTION
GFX.lpDevice -> SetTexture(1, lpReflectionTexture);
GFX.lpDevice -> SetTextureStageState(1,D3DTSS_TEXCOORDINDEX,D3DTSS_TCI_CAMERASPACEPOSITION);
GFX.lpDevice -> SetTextureStageState(1,D3DTSS_TEXTURETRANSFORMFLAGS,D3DTTFF_COUNT3 | D3DTTFF_PROJECTED);
GFX.lpDevice -> SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE );
GFX.lpDevice -> SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_SELECTARG1 );
// REMAP
GFX.lpDevice -> SetTransform(D3DTS_TEXTURE1, &matRemap);
// BUMPWAVES
tex->Use(0);
GFX.lpDevice -> SetTextureStageState(0,D3DTSS_TEXCOORDINDEX,0);
// Left right
GFX.lpDevice -> SetTextureStageState(0, D3DTSS_BUMPENVMAT00, F2DW(0));
GFX.lpDevice -> SetTextureStageState(0, D3DTSS_BUMPENVMAT10, F2DW(0));
// Up down
GFX.lpDevice -> SetTextureStageState(0, D3DTSS_BUMPENVMAT01, F2DW(0.25f));
GFX.lpDevice -> SetTextureStageState(0, D3DTSS_BUMPENVMAT11, F2DW(-0.20f));
GFX.lpDevice -> SetTextureStageState(0, D3DTSS_BUMPENVLSCALE, F2DW((float)GFX.d3d_modes[GFX.dwCurMode].dwHeight / 1024));
GFX.lpDevice -> SetTextureStageState(0, D3DTSS_BUMPENVLOFFSET, F2DW(0.20f) );
GFX.lpDevice -> SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_BUMPENVMAP);
GFX.lpDevice -> SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
GFX.lpDevice -> SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE);
GFX.lpDevice -> SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
GFX.lpDevice -> SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT );
// NO CULL
GFX.lpDevice -> SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
// TRANSPARENCY
GFX.lpDevice -> SetRenderState(D3DRS_ALPHABLENDENABLE, 1);
GFX.lpDevice -> SetRenderState(D3DRS_LIGHTING, 1);
GFX.lpDevice -> SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
GFX.lpDevice -> SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
// RENDER
GFX.lpDevice -> SetFVF(VertexFVF);
GFX.lpDevice -> DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0, dwNumVertices, dwNumIndices / 3, indices,D3DFMT_INDEX32, vertices, sizeof(Vertex));
GFX.lpDevice -> SetRenderState( D3DRS_CULLMODE, D3DCULL_CCW );
GFX.lpDevice -> SetTextureStageState(0,D3DTSS_TEXTURETRANSFORMFLAGS,D3DTTFF_DISABLE);
GFX.lpDevice -> SetTextureStageState(0,D3DTSS_TEXCOORDINDEX,0);
GFX.lpDevice -> SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_DISABLE);
GFX.lpDevice -> SetTextureStageState( 2, D3DTSS_COLOROP, D3DTOP_DISABLE );
}
Please, I've provided you good start. Help me to get my water rippling like in FarCry for example.
Also, feel free to criticize and comment my code.
:< Tired