Jump to content
  • Advertisement
Sign in to follow this  
Sam Segura

Problem with water reflection

This topic is 588 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello everyone, I hope you can help me with my problem of reflection of my water in my game.

I share you a screenshot for see the render result:

[attachment=33166:Sans titre.png]

So any reflection work here.

I share to you my code: 

 

void CMapOutdoor::RenderWater()
{
	if (m_PatchVector.empty())
		return;

	if (!IsVisiblePart(PART_WATER))
		return;

        D3DXMATRIX oldView = m_matLightView; // 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(&m_matLightView, &m_matLightView, &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_STENCILMASK, 0xffffffff);
	STATEMANAGER.SaveRenderState(D3DRS_STENCILWRITEMASK, 0xffffffff);
	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);
	STATEMANAGER.SaveRenderState(D3DRS_STENCILWRITEMASK, 0xFFFFFFFF);

	/// 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.SaveSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_MIRROR);
	STATEMANAGER.SaveSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);
	STATEMANAGER.SaveSamplerState(0, D3DSAMP_ADDRESSW, D3DTADDRESS_CLAMP);

	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);


	/// Water
	textureEau = m_WaterInstances[((ELTimer_GetMSec() / 30) % 250)].GetTexturePointer()->GetD3DTexture();

	STATEMANAGER.SetTexture(1, textureEau);
	D3DXMatrixScaling(&matTexTransformWater, m_fWaterTexCoordBase, -m_fWaterTexCoordBase, 0.0f);
	D3DXMatrixMultiply(&matTexTransformWater, &ms_matInverseView, &matTexTransformWater);

	ms_matWater = matTexTransformWater;
	STATEMANAGER.SaveTransform(D3DTS_TEXTURE1, &matTexTransformWater);
	STATEMANAGER.SaveTextureStageState(1, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEPOSITION);
	STATEMANAGER.SaveTextureStageState(1, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT3);
	STATEMANAGER.SaveSamplerState(1, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
	STATEMANAGER.SaveSamplerState(1, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
	STATEMANAGER.SaveSamplerState(1, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
	STATEMANAGER.SaveSamplerState(1, D3DSAMP_ADDRESSU, D3DTADDRESS_MIRROR);
	STATEMANAGER.SaveSamplerState(1, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);
	STATEMANAGER.SaveSamplerState(1, D3DSAMP_ADDRESSW, D3DTADDRESS_CLAMP);

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

	// RenderState
	//////////////////////////////////////////////////////////////////////////

	static float s_fWaterHeightCurrent = rand() % (251 - 125) + 125;
	static float s_fWaterHeightBegin = 0;
	static float s_fWaterHeightEnd = 0;
	static DWORD s_dwLastHeightChangeTime = CTimer::Instance().GetCurrentMillisecond();
	static DWORD s_dwBlendtime = 300;

	if ((CTimer::Instance().GetCurrentMillisecond() - s_dwLastHeightChangeTime) > s_dwBlendtime)
	{
		s_dwBlendtime = random_range(5000, 10000);

		if (s_fWaterHeightEnd == 0)
		{
			srand(time(NULL));
			s_fWaterHeightEnd = -random_range(0, rand() % (251 - 125) + 125);
		}
		else
			s_fWaterHeightEnd = 0;

		s_fWaterHeightBegin = s_fWaterHeightCurrent;
		s_dwLastHeightChangeTime = CTimer::Instance().GetCurrentMillisecond();
	}

	s_fWaterHeightCurrent = s_fWaterHeightBegin + (s_fWaterHeightEnd - s_fWaterHeightBegin) * (float)((CTimer::Instance().GetCurrentMillisecond() - s_dwLastHeightChangeTime) / (float)s_dwBlendtime);


	m_matWorldForCommonUse._43 = s_fWaterHeightCurrent;

	m_matWorldForCommonUse._41 = 0.0f;
	m_matWorldForCommonUse._42 = 0.0f;
	STATEMANAGER.SetTransform(D3DTS_WORLD, &m_matWorldForCommonUse);


	float fFogDistance = __GetFogDistance();


	std::vector<std::pair<float, long> >::iterator i;

	for (i = m_PatchVector.begin(); i != m_PatchVector.end(); ++i)
	{
		if (i->first<fFogDistance)
			DrawWater(i->second, textureEau);
	}

	STATEMANAGER.SetTexture(0, NULL);
	STATEMANAGER.SetTexture(1, NULL);
	STATEMANAGER.SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);

	for (i = m_PatchVector.begin(); i != m_PatchVector.end(); ++i)
	{
		if (i->first >= fFogDistance)
			DrawWater(i->second, textureEau);
	}



	m_matWorldForCommonUse._43 = 0.0f;


	STATEMANAGER.RestoreFVF();
	STATEMANAGER.RestoreTransform(D3DTS_TEXTURE0);
	STATEMANAGER.RestoreTransform(D3DTS_TEXTURE1);
	STATEMANAGER.RestoreSamplerState(0, D3DSAMP_MINFILTER);
	STATEMANAGER.RestoreSamplerState(0, D3DSAMP_MAGFILTER);
	STATEMANAGER.RestoreSamplerState(0, D3DSAMP_MIPFILTER);
	STATEMANAGER.RestoreSamplerState(0, D3DSAMP_ADDRESSU);
	STATEMANAGER.RestoreSamplerState(0, D3DSAMP_ADDRESSV);
	STATEMANAGER.RestoreTextureStageState(0, D3DTSS_TEXCOORDINDEX);
	STATEMANAGER.RestoreTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS);

	STATEMANAGER.RestoreSamplerState(1, D3DSAMP_MINFILTER);
	STATEMANAGER.RestoreSamplerState(1, D3DSAMP_MAGFILTER);
	STATEMANAGER.RestoreSamplerState(1, D3DSAMP_MIPFILTER);
	STATEMANAGER.RestoreSamplerState(1, D3DSAMP_ADDRESSU);
	STATEMANAGER.RestoreSamplerState(1, D3DSAMP_ADDRESSV);
	STATEMANAGER.RestoreTextureStageState(1, D3DTSS_TEXCOORDINDEX);
	STATEMANAGER.RestoreTextureStageState(1, D3DTSS_TEXTURETRANSFORMFLAGS);

	STATEMANAGER.RestoreRenderState(D3DRS_DIFFUSEMATERIALSOURCE);
	STATEMANAGER.RestoreRenderState(D3DRS_COLORVERTEX);
	STATEMANAGER.RestoreRenderState(D3DRS_ZWRITEENABLE);
	STATEMANAGER.RestoreRenderState(D3DRS_ALPHABLENDENABLE);
	STATEMANAGER.RestoreRenderState(D3DRS_CULLMODE);
	STATEMANAGER.RestoreRenderState(D3DRS_STENCILENABLE);
	STATEMANAGER.RestoreRenderState(D3DRS_STENCILFUNC);
	STATEMANAGER.RestoreRenderState(D3DRS_STENCILPASS);
	STATEMANAGER.RestoreRenderState(D3DRS_SPECULARENABLE);
	STATEMANAGER.RestoreRenderState(D3DRS_SPECULARMATERIALSOURCE);
	STATEMANAGER.RestoreRenderState(D3DRS_STENCILWRITEMASK);
	STATEMANAGER.SetRenderState(D3DRS_STENCILENABLE, false);

	m_matLightView = oldLight;
}

void CMapOutdoor::DrawWater(long patchnum, LPDIRECT3DBASETEXTURE9 textureEau)
{
	assert(NULL != m_pTerrainPatchProxyList);
	if (!m_pTerrainPatchProxyList)
		return;

	CTerrainPatchProxy& rkTerrainPatchProxy = m_pTerrainPatchProxyList[patchnum];

	if (!rkTerrainPatchProxy.isUsed())
		return;

	if (!rkTerrainPatchProxy.isWaterExists())
		return;

	CGraphicVertexBuffer* pkVB = rkTerrainPatchProxy.GetWaterVertexBufferPointer();
	if (!pkVB)
		return;

	if (!pkVB->GetD3DVertexBuffer())
		return;

	UINT uPriCount = rkTerrainPatchProxy.GetWaterFaceCount();
	if (!uPriCount)
		return;

	STATEMANAGER.SetStreamSource(0, pkVB->GetD3DVertexBuffer(), sizeof(SWaterVertex));

	

	STATEMANAGER.DrawPrimitive(D3DPT_TRIANGLELIST, 0, uPriCount);


}

I wish you can help , thank in advance :)

Share this post


Link to post
Share on other sites
Advertisement

Well, when i try to make a reflect of the world that's not work, the water is just inverted position.

 

like that:

[attachment=33171:Sans titre2.png]

I don't how to reflect world,skybox,character,object into the water plane.

If you have an example it well be cool :)

Thank in advance.

Share this post


Link to post
Share on other sites

Well, when i try to make a reflect of the world that's not work, the water is just inverted position.

 

like that:

attachicon.gifSans titre2.png

I don't how to reflect world,skybox,character,object into the water plane.

If you have an example it well be cool :)

Thank in advance.

 

http://www.riemers.net/eng/Tutorials/XNA/Csharp/Series4/Reflection_map.php This tutorial here is pretty good. Even though its for XNA it's still DirectX and you could probably learn from this.

Share this post


Link to post
Share on other sites

You're not supposed to render the water with the mirrored matrix, instead you're supposed to render the reflected scene (i.e. everything above the water plane) using the mirrored matrix into a texture, then use that texture on the water (using screenspace uvs)

 

*edit: typo

Edited by Digitalfragment

Share this post


Link to post
Share on other sites

Thank for your reply , but I work into C++ I have try it , I have the result of my screenshot :(

 

Yeah you have to translate C# to C++, but it works fairly well.

Share this post


Link to post
Share on other sites

Hello thank you for your reply, i have translate it into C++ but i get nothing about it. 

I think i need maybe to get the texture of the surface with the view inverted and use it on the water like you say.

If you have any idea to get it or an example I realy appreciate it   :)

Thank you :)

Edited by Herra07

Share this post


Link to post
Share on other sites

Most of this is math, so whether it's C# or C++ is largely irrelevant. I built my own example in XNA, probably off Riemer's tutorial although when doing those projects I would consult several different sources. That was years ago and I don't really remember how it works. But at the time I wrote:

 

"The technique on mirroring is basically to move the camera to the upside down opposite position (flip the Y coordinate assuming the "ground" is at zero and that the mirrored surface faces upwards). You then draw the scene as normal, from this perspective, on to a hidden drawing surface (place in memory). Then you can draw the whole scene normally and add a "mirrored" surface, by "texturing" the surface from the stored image you created. It's really pretty straight forward."

 

I lost my primary computer a year or so ago and with it this program. So, I can't easily just pop it open. I don't think I even have XNA installed any more and most of these projects take a minimal amount of work to convert to MonoGame. So, I don't have super easy access to the program. However, the entire project file including source code is on my website under the "Water" or "Ocean Example". If you want to see what it looks like when it runs, it's the 4th in the video montage that is the intro to my YouTube channel.

 

In that project, I built it up as 3 separate projects in Visual Studio starting with just a mirror surface, then adding the waves, and so forth.

 

But to save you the trouble of going through all that code, I "believe" this is the key code:

        public Vector3 ReflectedCameraPosition()
        {
            Vector3 CameraReflectedPosition;

            CameraReflectedPosition = CameraPosition;
            CameraReflectedPosition.Y = -CameraReflectedPosition.Y;

            return CameraReflectedPosition;
        }


        public Matrix ReflectionView()
        //===================================================================================
        // ReflectionView()
        //
        // Purpose: Converts CameraFacing and CameraPostion to a ViewMatrix that can be sent to the shader.
        // Parameters: none
        // Notes: This was created to make it easy to pass a ViewMatrix to the shader. I intentionally
        //          store the camera position and facing seperately and consider them the "true" state.
        //          This allows the data to be converted to a ViewMatrix because that's what the shader
        //          is going to want and it will need to be done often.
        // Returns:
        //===================================================================================
        {
            Vector3 CameraLookTowards;
            Vector3 CameraReflectedPosition;
            Matrix ReflectionMatrix;

            CameraReflectedPosition = ReflectedCameraPosition();
            CameraLookTowards = new Vector3(CameraFacing.X, -PitchPercentage, CameraFacing.Z);
            CameraLookTowards += CameraReflectedPosition;    //CameraLookTowards is on the ground and must be raised to camera height or the camera will just look at it's "toes".
            ReflectionMatrix = Matrix.CreateLookAt(CameraReflectedPosition, CameraLookTowards, Vector3.Up);

            return ReflectionMatrix;
        }
        //===================================================================================
 

There was an issue with things showing up in the reflection that should have not shown up at specific angles. I believe this is because you're supposed to use a clipping plane and I did not. They apparently took the clipping plane method that Reimer uses out of XNA 4.0 and at the time I had no idea how to get it in there.

 

So, this is not perfect working code, but maybe it will help.

 

(Without trying it, I think you might be able to pull this all off without using vectors and just reverse the value directly within the matrix to get a reflected view matrix. I wrote this code many years ago when I had substantially less experience. If I were to do it today, my first effort would be to store the camera position and orientation in the view matrix and not re-build the view matrix every frame using LookAt. Since I wrote this I moved on to DX11 and now I'm doing OGL 4.5 and my latest 1st person camera is just a view matrix and a pitch angle. The pitch angle is maintained separately in order to limit the angle you can look up or down and prevent 360+ degree pitching. I apply the pitch angle to the view matrix right before sending it to the shader each frame. But otherwise, I maintain the position and orientation of the camera in the view matrix from frame to frame - which means what I send to the shader is not the actual view matrix but the view matrix modified to include the pitch data.

 

So, in this case I think you could just multiply the view matrix times a scale matrix that is scaled -1 on the Y axis to get your reflection matrix.

 

I believe this all assumes that 0 height is sea level. Otherwise, you would probably have to take that into account since you are reflecting across that plane.)

Edited by BBeck

Share this post


Link to post
Share on other sites

Thank you for your help, I have translate your code into my C++ code but I don't think i have make the right thing.

 

Code translated:
 

D3DXVECTOR3 ReflectedCameraPosition()
{
	D3DXVECTOR3 CameraReflectedPosition;

	CCamera * pCurrentCamera = CCameraManager::Instance().GetCurrentCamera(); 
	CameraReflectedPosition = pCurrentCamera->GetView();
	CameraReflectedPosition.y = -CameraReflectedPosition.y;

	return CameraReflectedPosition;
}
D3DXMATRIX ReflectionView()
{
	CCamera * pCurrentCamera = CCameraManager::Instance().GetCurrentCamera();
	
	D3DXVECTOR3 CameraReflectedPosition;
	D3DXMATRIX ReflectionMatrix;

	CameraReflectedPosition = ReflectedCameraPosition();

	D3DXVECTOR3 CameraLookTowards(pCurrentCamera->GetEye().x, -50, pCurrentCamera->GetEye().z);
	CameraLookTowards += CameraReflectedPosition;

	D3DXVECTOR3 vectorUP(0.0f, 1.0f, 0.0f);
	D3DXMatrixLookAtLH(&ReflectionMatrix, &CameraLookTowards, &CameraReflectedPosition, &vectorUP);


	return ReflectionMatrix;
}

I put the matrix into the water texture like that
 

	m_lpDevice->SaveTransform(D3DTS_TEXTURE0, &ReflectionView());

And i get this result :

[attachment=33185:Sans titre3.png]

[attachment=33186:Sans titre4.png]

So i get a black plane who follow my water, i think I have make a wrong translation of your example.

 

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!