# DX11 Water Reflections in DX8

## Recommended Posts

hey guys,

i have a problem over here with vertex shaders and going to need some professional help, so i thought i create a thread here.

i just decided to work this feature out for me, 2 days ago. so please dont expect me to have any experience in programming D3D.

i am trying to work this out on my own as good as i can, but i would really appreciate if someone could help me a bit or give me a push in the right direction.

i am paying for the solution, so you won't waste your time, if you decide to join me on this case.

but ok, lets start:

first of all, you have to know that i am editing a very old game, which is using Direct X 8. the water in this game is basically a simple plane, which is using a normal texture projected onto it.

so basically its just a plane with a texuture, that is initializing a alpha state for the texture, so you can look through the water ingame.

no shadows, no reflections, no animations yet. my first goal is to get the inverseViewMatrix working, to make at least the shadows of the world appear in the water.

so, here's the code of the actual render state of the water:

Spoiler

{
char buf[256];
for (int i = 0; i < 30; ++i)
{
sprintf(buf, "C:/test/water/%water_1d.dds", i+1);
WaterInstances[i].SetImagePointer((CGraphicImage *) CResourceManager::Instance().GetResourcePointer(buf));
}
}

void RenderWater()
{
// Saving Render State
D3DXMATRIX TransformTextureToWater;

STATEMANAGER.SaveRenderState(D3DRS_ZWRITEENABLE, FALSE);
STATEMANAGER.SaveRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
STATEMANAGER.SaveRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
STATEMANAGER.SaveRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1);
STATEMANAGER.SaveRenderState(D3DRS_COLORVERTEX, TRUE);

STATEMANAGER.SetTexture(0, WaterInstances[((ELTimer_GetMSec() / 70) % 30)].GetTexturePointer()->GetD3DTexture());

D3DXMatrixScaling(&TransformTextureToWater, WaterTextureCoordBase, -WaterTextureCoordBase, 0.0f);
D3DXMatrixMultiply(&TransformTextureToWater, &InverseTheView, &TransformTextureToWater);

STATEMANAGER.SaveTransform(D3DTS_TEXTURE0, &TransformTextureToWater);

STATEMANAGER.SaveTextureStageState(0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEPOSITION);
STATEMANAGER.SaveTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2);
STATEMANAGER.SaveTextureStageState(0, D3DTSS_MINFILTER, D3DTEXF_LINEAR);
STATEMANAGER.SaveTextureStageState(0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR);
STATEMANAGER.SaveTextureStageState(0, D3DTSS_MIPFILTER, D3DTEXF_LINEAR);

STATEMANAGER.SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE);
STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);

STATEMANAGER.SetTexture(1,NULL);
STATEMANAGER.SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
STATEMANAGER.SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);

// Restoring Render State
STATEMANAGER.RestoreTransform(D3DTS_TEXTURE0);
STATEMANAGER.RestoreTextureStageState(0, D3DTSS_MINFILTER);
STATEMANAGER.RestoreTextureStageState(0, D3DTSS_MAGFILTER);
STATEMANAGER.RestoreTextureStageState(0, D3DTSS_MIPFILTER);
STATEMANAGER.RestoreTextureStageState(0, D3DTSS_TEXCOORDINDEX);
STATEMANAGER.RestoreTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS);

STATEMANAGER.RestoreRenderState(D3DRS_DIFFUSEMATERIALSOURCE);
STATEMANAGER.RestoreRenderState(D3DRS_COLORVERTEX);
STATEMANAGER.RestoreRenderState(D3DRS_ZWRITEENABLE);
STATEMANAGER.RestoreRenderState(D3DRS_ALPHABLENDENABLE);
STATEMANAGER.RestoreRenderState(D3DRS_CULLMODE);
}

So, i noticed there's already something started for inversing the view ('&InverseTheView').

in another function, for setting the Inverse View and Shadow Matrices, its declared:

	InverseTheView = pCamera->GetInverseViewMatrix();

D3DXVECTOR3 v3Target = pCamera->GetTarget();

D3DXVECTOR3 v3LightEye(v3Target.x - 1.732f * 1250.0f,
v3Target.y - 1250.0f,
v3Target.z + 2.0f * 1.732f * 1250.0f);

D3DXMatrixLookAtRH(&m_matLightView, &v3LightEye, &v3Target, &D3DXVECTOR3(0.0f, 0.0f, 1.0f));
DynamicShadow = InverseTheView * LightView * DynamicShadowScale;

okay, so far so good. i tried to add the Inversed View to my Water rendering state:

void LoadWaterMaterial()
{
char buf[256];
for (int i = 0; i < 30; ++i)
{
sprintf(buf, "C:/test/water/%water_1d.dds", i+1);
WaterInstances[i].SetImagePointer((CGraphicImage *) CResourceManager::Instance().GetResourcePointer(buf));
}
}

void RenderWater()
{
// Saving Render State
D3DXMATRIX oldView = LightView; // Old light view
D3DXMATRIX oldLight; // old light
D3DXPLANE plane(0.0f, 1.0f, 0.0f, 0.0f);
D3DXMATRIX invertMatrix;
D3DXMatrixReflect(&invertMatrix, &plane);

oldView = ms_matWorldView;
D3DXMATRIX vue = oldView;
D3DXMatrixMultiply(&vue, &vue, &invertMatrix); // Inverse view
D3DXMatrixMultiply(&LightView, &LightView, &invertMatrix); // Inverse light

STATEMANAGER.SaveRenderState(D3DRS_ZWRITEENABLE, FALSE);
STATEMANAGER.SaveRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
STATEMANAGER.SaveRenderState(D3DRS_STENCILENABLE, true);
STATEMANAGER.SaveRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS);
STATEMANAGER.SaveRenderState(D3DRS_STENCILREF, 0x1);
STATEMANAGER.SaveRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP);
STATEMANAGER.SaveRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP);
STATEMANAGER.SaveRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE);
STATEMANAGER.SaveRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
STATEMANAGER.SaveRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1);
STATEMANAGER.SaveRenderState(D3DRS_COLORVERTEX, TRUE);
STATEMANAGER.SaveRenderState(D3DRS_SPECULARENABLE, TRUE);
STATEMANAGER.SaveRenderState(D3DRS_SPECULARMATERIALSOURCE, D3DMCS_COLOR2);

/// Reflection

D3DXMATRIX reflection = vue;
D3DXMatrixScaling(&reflection, m_fWaterTexCoordBase, -m_fWaterTexCoordBase, 0.0f);
STATEMANAGER.SaveTransform(D3DTS_TEXTURE0, &reflection);
LPDIRECT3DTEXTURE9 textureEau = m_WaterInstances[((ELTimer_GetMSec() / 30) % 250)].GetTexturePointer()->GetD3DTexture();

STATEMANAGER.SetFVF(D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX0 | D3DFVF_TEX1);

STATEMANAGER.SetTexture(0, textureEau);

STATEMANAGER.SaveTextureStageState(0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR);
STATEMANAGER.SaveTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_PROJECTED);
STATEMANAGER.SaveSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
STATEMANAGER.SaveSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
STATEMANAGER.SaveSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);

STATEMANAGER.SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE);
STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);

// Start of Water

STATEMANAGER.SetTexture(0, WaterInstances[((ELTimer_GetMSec() / 70) % 30)].GetTexturePointer()->GetD3DTexture());

D3DXMatrixScaling(&TransformTextureToWater, WaterTextureCoordBase, -WaterTextureCoordBase, 0.0f);
D3DXMatrixMultiply(&TransformTextureToWater, &InverseTheView, &TransformTextureToWater);

STATEMANAGER.SaveTransform(D3DTS_TEXTURE0, &TransformTextureToWater);

STATEMANAGER.SaveTextureStageState(0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEPOSITION);
STATEMANAGER.SaveTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2);
STATEMANAGER.SaveTextureStageState(0, D3DTSS_MINFILTER, D3DTEXF_LINEAR);
STATEMANAGER.SaveTextureStageState(0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR);
STATEMANAGER.SaveTextureStageState(0, D3DTSS_MIPFILTER, D3DTEXF_LINEAR);

STATEMANAGER.SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE);
STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);

STATEMANAGER.SetTexture(1,NULL);
STATEMANAGER.SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
STATEMANAGER.SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);

// Restoring Render State
STATEMANAGER.RestoreTransform(D3DTS_TEXTURE0);
STATEMANAGER.RestoreTextureStageState(0, D3DTSS_MINFILTER);
STATEMANAGER.RestoreTextureStageState(0, D3DTSS_MAGFILTER);
STATEMANAGER.RestoreTextureStageState(0, D3DTSS_MIPFILTER);
STATEMANAGER.RestoreTextureStageState(0, D3DTSS_TEXCOORDINDEX);
STATEMANAGER.RestoreTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS);

STATEMANAGER.RestoreRenderState(D3DRS_DIFFUSEMATERIALSOURCE);
STATEMANAGER.RestoreRenderState(D3DRS_COLORVERTEX);
STATEMANAGER.RestoreRenderState(D3DRS_ZWRITEENABLE);
STATEMANAGER.RestoreRenderState(D3DRS_ALPHABLENDENABLE);
STATEMANAGER.RestoreRenderState(D3DRS_CULLMODE);
}

The Output is, i would say strange. its flickering, framing between black and gray color. but its not inversing the view.

Does it have something to do, with clipping the frustum view?

I really do not have any clue how to work with this properly. i would really appreciate if someone here gives me the push in the right direction, as mentioned.

you'll get rewarded, too!

thanks for reading and best regards

##### Share on other sites

You really should try a graphics frame capture debugger like Pix to be sure your issue is what you think it is.

From that last snippet of code, if you comment this line out, does that fix your render from flickering?

D3DXMatrixMultiply﻿﻿(&TransformTextureToWater, &Inverse﻿TheView, &TransformTextureToWater);﻿﻿﻿

Have you tried reversing the order of the matrix multiply?

##### Share on other sites

thanks for your reply. i will try it when i am at home. i managed to work a little further yesterday, but still have trouble with getting this to work.

I added D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR to the SaveTextureStageState and got a pretty accurate result.

its starting to reflect something, but gives me wrong output. i think there's something missing for projecting the scene back onto the plane (inverse).

Edited by dexam234

##### Share on other sites
On 9/10/2019 at 8:13 AM, Steve_Segreto said:

You really should try a graphics frame capture debugger like Pix

I don't think Pix or RenderDoc support DX8.

##### Share on other sites

ok, basically i managed to get some reflection, as i've posted before. so, the vector is already given, i just had to add those statements to the render part, to get this kinda "reflection". but the problem at the moment is, the water plane can't recognize the world environment. thats because there are still missing code parts. i think the right way in this case would be the cube mapping option.

basically the water looks ingame, like something would mirror in it. there's like a white fade effect going over the plane, every few seconds.

also i looked through the source and found some functions that are rendering the specular texture part for the game. they've been using D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR  also for this function, which causes a mirror-like effect ingame.

so basically i am on the right track, i think. but still gonna need some help, so please - if you ever worked with this DX rev. contact me! it won't be a waste of time, as mentioned before.

Link to Forsaken Online Water Shader (could be useful, also using DX8)

Edited by dexam234

##### Share on other sites
6 hours ago, bioglaze said:

I don't think Pix or RenderDoc support DX8.

It’s been almost 15 years since I last worked with D3D8, but at that time it was really trivial to convert even a large commercial program from 8 to 9, might be worth the effort for the better tools. If not you can try things like this: http://jrfonseca.blogspot.com/2008/07/tracing-d3d-applications.html?m=1

## Create an account

Register a new account

• ### Game Developer Survey

We are looking for qualified game developers to participate in a 10-minute online survey. Qualified participants will be offered a \$15 incentive for your time and insights. Click here to start!

• 13
• 14
• 41
• 63