Jump to content
  • Advertisement
Sign in to follow this  
PingHosting

Direct9x Water Reflection in HLSL

This topic is 554 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 everybody,

I work on water reflection on my project. And I have some problems with HLSL code.

My water work with many primitives and work like a large plane with coordinates.

I cannot found the right way to make an mirror of the view and use it with my water rendering.
 

D3DXMATRIX matTextTransformWater // Represent the texture matrix of my water.

float m_fWaterTextCoordBase // Represent the size of the texture.

LPDIRECT3DTEXTURE9 water // Represent the texture of my water.

Part of Texture size calculation:

D3DXMatrixScaling(&matTexTransformWater, m_fWaterTexCoordBase, -m_fWaterTexCoordBase, 0.0f);
D3DXMatrixMultiply(&matTexTransformWater, &m_matViewInverse, &matTexTransformWater);



Part of setting texture with matrix:
 

STATEMANAGER.SetTexture(0, water);

STATEMANAGER.SaveTransform(D3DTS_TEXTURE0, &matTexTransformWater);


Part of get Reflection Texture map:

 

void CMapOutdoor::MapTextureReflection()
{
	D3DXMATRIX oldView; // Ancienne vue.
	D3DXMATRIX oldWorld; // Ancien monde.
	D3DXMATRIX oldProj; // Ancienne projection.

	STATEMANAGER.GetTransform(D3DTS_VIEW, &oldView); // récupération de la vue.
	STATEMANAGER.GetTransform(D3DTS_WORLD, &oldWorld); // récupération du monde.
	STATEMANAGER.GetTransform(D3DTS_PROJECTION, &oldProj); // récupération de la projection.

	STATEMANAGER.SetTransform(D3DTS_VIEW, &ReflectionView());


	LPDIRECT3DSURFACE9 pBackBuffer;



	if (SUCCEEDED(STATEMANAGER.m_lpD3DDev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer)))
	{

		D3DVIEWPORT9 viewPort;
		STATEMANAGER.m_lpD3DDev->GetViewport(&viewPort);
		D3DXCreateTexture(STATEMANAGER.m_lpD3DDev, viewPort.Width, viewPort.Height, D3DX_DEFAULT, D3DUSAGE_RENDERTARGET,
			D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &TextureReflectionMap);

		LPDIRECT3DSURFACE9 pTexSurface;
		TextureReflectionMap->GetSurfaceLevel(0, &pTexSurface);
		STATEMANAGER.m_lpD3DDev->StretchRect(pBackBuffer, NULL, pTexSurface, NULL, D3DTEXF_NONE);
		pBackBuffer->Release();
		pTexSurface->Release();
		
	}

	STATEMANAGER.SetTransform(D3DTS_VIEW, &oldView);
	STATEMANAGER.SetTransform(D3DTS_WORLD, &oldWorld);
	STATEMANAGER.SetTransform(D3DTS_PROJECTION, &oldProj);
}

D3DXMATRIX CMapOutdoor::ReflectedCameraPositionMatrix()
{
	D3DXMATRIX CameraReflected;
	D3DXMatrixTranslation(&CameraReflected, ReflectedCameraPositionVector3().x, ReflectedCameraPositionVector3().y, ReflectedCameraPositionVector3().z);

	return CameraReflected;
}

D3DXVECTOR3 CMapOutdoor::ReflectedCameraPositionVector3()
{
	D3DXVECTOR3 CameraReflectedPosition;

	CCamera * pCurrentCamera = CCameraManager::Instance().GetCurrentCamera();
	CameraReflectedPosition = pCurrentCamera->GetTarget();
	CameraReflectedPosition.z = -CameraReflectedPosition.z;

	return CameraReflectedPosition;
}

D3DXMATRIX CMapOutdoor::ReflectionView()
{
	CCamera * pCurrentCamera = CCameraManager::Instance().GetCurrentCamera();


	D3DXVECTOR3 CameraReflectedPosition;
	D3DXMATRIX ReflectionMatrix;

	CameraReflectedPosition = ReflectedCameraPositionVector3();

	D3DXVECTOR3 CameraLookTowards(pCurrentCamera->GetTarget().x, pCurrentCamera->GetTarget().y, pCurrentCamera->GetTarget().z);
	CameraLookTowards += CameraReflectedPosition;

	D3DXVECTOR3 vectorUP(0.0f, 0.0f, 1.0f);
	//D3DXMatrixAffineTransformation(&ReflectionMatrix, &CameraLookTowards, &CameraReflectedPosition, &vectorUP);
	D3DXMatrixLookAtLH(&ReflectionMatrix, &CameraLookTowards, &CameraReflectedPosition, &vectorUP);
	return ReflectionMatrix;
}


 

Part of HLSL code:

float4x4 World;
float4x4 View;
float4x4 Projection;
float3 CameraPosition;
float4x4 ReflectionView;
float ViewPortWidth;
float ViewPortHeight;
texture ReflectionMap;

sampler2D ReflectionSampler = sampler_state
{
    texture = <ReflectionMap>;
    MinFilter = Linear;
    MagFilter = Linear;
    MipFilter = Linear;
    AddressU = Clamp;
    AddressV = Clamp;
};

// TODO: add effect parameters here.
float2 postProjToScreen(float4 position)
{
  float2 screenPos = position.xy / position.w;
  return 0.5f * (float2(screenPos.x, -screenPos.y) + 1);
}

float2 halfPixel()
{
  return 0.5f / float2(ViewPortWidth, ViewPortHeight);
}



struct VertexShaderInput
{
    float4 Position : POSITION0;
};

struct VertexShaderOutput
{
    float4 Position : POSITION0;
    float4 ReflectionPosition : TEXCOORD1;

    // TODO: add vertex shader outputs such as colors and texture
    // coordinates here. These values will automatically be interpolated
    // over the triangle, and provided as input to your pixel shader.
};

VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
    VertexShaderOutput output;

    float4 worldPosition = mul(input.Position, World);
    float4 viewPosition = mul(worldPosition, View);
    output.Position = mul(viewPosition, Projection);

    // TODO: add your vertex shader code here.
    float4x4 Reflected = mul(World, mul(ReflectionView, Projection));
    output.ReflectionPosition = mul(input.Position, Reflected);

    return output;
}

float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
    // TODO: add your pixel shader code here.

    //float2 ReflectionUV = float2(input.ReflectionPosition.x/input.ReflectionPosition.w/2.0f + 0.5f, input.ReflectionPosition.y/input.ReflectionPosition.w/2.0f + 0.5f);
    float2 ReflectionUV = postProjToScreen(input.ReflectionPosition) + halfPixel();
    float3 Reflection = tex2D(ReflectionSampler, ReflectionUV);

    return float4(Reflection, 1);
}



technique Technique1
{
    pass Pass1
    {
        // TODO: set renderstates here.

        VertexShader = compile vs_2_0 VertexShaderFunction();
        PixelShader = compile ps_2_0 PixelShaderFunction();
    }
}

Part of Rendering primitive with HLSL initialization:

	if (EffetEau) // If water hlsl file is correctly readed.
	{
		// Variable
		D3DVIEWPORT9 viewport;
		D3DXMATRIX oldWorld;
		D3DXMATRIX oldView;
		D3DXMATRIX oldProj;
		STATEMANAGER.GetTransform(D3DTS_WORLD, &oldWorld);
		STATEMANAGER.GetTransform(D3DTS_VIEW, &oldView);
		STATEMANAGER.GetTransform(D3DTS_PROJECTION, &oldProj);


		D3DXMATRIX invertWorld;
		D3DXMATRIX transposeWorld;

		D3DXMatrixInverse(&invertWorld, 0, &oldWorld);
		D3DXMatrixTranspose(&transposeWorld, &invertWorld);
		STATEMANAGER.m_lpD3DDev->GetViewport(&viewport);


		// Handle de l'effet;
		D3DXHANDLE Technique = matEauEffet->GetTechniqueByName("Technique1");
		D3DXHANDLE World = matEauEffet->GetParameterByName(0, "World");
		D3DXHANDLE View = matEauEffet->GetParameterByName(0, "View");
		D3DXHANDLE Proj = matEauEffet->GetParameterByName(0, "Projection");
		D3DXHANDLE CameraPosition = matEauEffet->GetParameterByName(0, "CameraPosition");
		D3DXHANDLE ReflectionView = matEauEffet->GetParameterByName(0, "ReflectionView");
		D3DXHANDLE ViewPortWidth = matEauEffet->GetParameterByName(0, "ViewPortWidth");
		D3DXHANDLE ViewPortHeight = matEauEffet->GetParameterByName(0, "ViewPortHeight");
		D3DXHANDLE ReflectionMap = matEauEffet->GetParameterByName(0, "ReflectionMap");


		HRESULT hr;
		hr = matEauEffet->SetMatrix(View, &oldView);
		if (FAILED(hr))
		{
			TraceError("Erreur Effet View");
		}
		hr = matEauEffet->SetMatrix(World, &oldWorld);
		if (FAILED(hr))
		{
			TraceError("Erreur Effet World");
		}
		hr = matEauEffet->SetMatrix(Proj, &oldProj);
		if (FAILED(hr))
		{
			TraceError("Erreur Effet Proj");
		}


		hr = matEauEffet->SetValue(CameraPosition, &CCameraManager::Instance().GetCurrentCamera()->GetView(), sizeof(D3DXVECTOR3));
		if (FAILED(hr))
		{
			TraceError("Erreur Effet CameraPosition");
		}

		hr = matEauEffet->SetMatrix(ReflectionView, &invertWorld);
		if (FAILED(hr))
		{
			TraceError("Erreur Effet ReflectionView");
		}
		hr = matEauEffet->SetFloat(ViewPortWidth, viewport.Width);
		if (FAILED(hr))
		{
			TraceError("Erreur Effet Viewport Height");
		}
		hr = matEauEffet->SetFloat(ViewPortHeight, viewport.Height);
		if (FAILED(hr))
		{
			TraceError("Erreur Effet Viewport Width");
		}
		hr = matEauEffet->SetTexture(ReflectionMap, TextureReflectionMap);
		if (FAILED(hr))
		{
			TraceError("Erreur Effet Reflection Texture");
		}
		hr = matEauEffet->SetTechnique(Technique);
		if (FAILED(hr))
		{
			TraceError("Erreur Effet Technique");
		}
		UINT cPasses;
		matEauEffet->Begin(&cPasses, 0);
		for (int k = 0; k < cPasses; k++)
		{
			matEauEffet->BeginPass(k);
			matEauEffet->CommitChanges();
			STATEMANAGER.DrawPrimitive(D3DPT_TRIANGLELIST, 0, uPriCount);

			matEauEffet->EndPass();
		}
		matEauEffet->End();
	}
	else
	{
		STATEMANAGER.DrawPrimitive(D3DPT_TRIANGLELIST, 0, uPriCount);
	}

The result:

[attachment=35336:resultat.png]


I hope you can help me, thank you in advance.

Edited by PingHosting

Share this post


Link to post
Share on other sites
Advertisement

For the water rendering you have two possible way :
- Planar reflection : render a second time the scene with a reflection matrix
- Screen-Space Reflection (SSR)

Here the planar reflection.
Here how to compute the reflection plane :

CVector4 PlaneEquation = CVector4( 0.0f, 1.0f, 0.0f, 0.0f );
PlaneEquation = WaterObject->GetWorldMatrix().Inverse().Transpose().Transform( PlaneEquation );
CPlane ReflectionPlane = CPlane( PlaneEquation.x, PlaneEquation.y, PlaneEquation.z, PlaneEquation.w );
ReflectionPlane.Normalize();

You then set a matrix based on this plane :

CMatrix4 ReflectionMatrix;
ReflectionMatrix.Reflect( ReflectionPlane );

Here the reflect function :

void CMatrix4::Reflect( const CPlane& p )
{
  m16[ 0 ] = -2.0f * p.n.x * p.n.x + 1.0f; m16[ 4 ] = -2.0f * p.n.x * p.n.y;        m16[ 8 ] = -2.0f * p.n.x * p.n.z;         m16[ 12 ] = -2.0f * p.n.x * p.d;
  m16[ 1 ] = -2.0f * p.n.y * p.n.x;        m16[ 5 ] = -2.0f * p.n.y * p.n.y + 1.0f; m16[ 9 ] = -2.0f * p.n.y * p.n.z;         m16[ 13 ] = -2.0f * p.n.y * p.d;
  m16[ 2 ] = -2.0f * p.n.z * p.n.x;        m16[ 6 ] = -2.0f * p.n.z * p.n.y;        m16[ 10 ] = -2.0f * p.n.z * p.n.z + 1.0f; m16[ 14 ] = -2.0f * p.n.z * p.d;
  m16[ 3 ] =  0.0f;                        m16[ 7 ] =  0.0f;                        m16[ 11 ] =  0.0f;                        m16[ 15 ] =  1.0f;
}

The clip plane :

CVector4 ClipPlane = CVector4( 0.0f, -1.0f, 0.0f, 0.0f );
const CMatrix4 WVP = WaterObject->GetWorldMatrix() * Camera->GetViewMatrix() * Camera->GetProjectionMatrix();
ClipPlane = WVP.Inverse().Transpose().Transform( ClipPlane );
ClipPlane.Normalize();

The reflection matrix is multiplied with the view matrix : ReflectionMatrix * Camera->GetViewMatrix()
For the clip plane you output in the vertex shader :

?OutClipDot = dot( gl_Position, ClipPlane );

In the pixel shader you simply check the value :

if( OutClipDot < 0.0 )
    discard;
Edited by Alundra

Share this post


Link to post
Share on other sites

The code I gave is C++ and for the shader part it's GLSL but it's mostly identical to HLSL.
I simply have custom class and not use D3DX because I write cross platform code generally.

Edited by Alundra

Share this post


Link to post
Share on other sites

So I need to make a class like you? Or I need to use D3DXVECTOR4 and more?

Edit: your example is good, i just need to remove distance of my camera for see each part of my view and add it after taking texture view.

 

Edited by PingHosting

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!