Skip to main content
GameDev.net gamedev.net
🔒 Locked

Water reflections

Started by Mephs Jun 25, 2004 at 4:26 PM 67 replies 38.9k views
Original Post
Mephs
Mephs
Hey all, Well, I'm really stuck with something that I'm certain should be rather simple. I'm trying to render my terrain to texture so that I can project it as a reflection on my water surface. Now I've got no problem with the render to texture part, but setting up the view/world/projection matrices has got me stumped. I've read the VCP article here on Gamedev, but to be honest it just confuses me, in particular, the part about moving mirror vertices. Am I just being thick, but why would I want to move my mirror vertices when all I want to do is change the position and orientation of the camera to render the view from the mirrored camera position, I don't understand why vertices need to be touched at all? So basically I guess my question is how do I reflect the camera position/orientation so that it is in the correct place to render the reflection? I'm using DirectX 8.1 in case that helps. My guess would be that Camera.xPos stays the same Camera.yPos = -(y distance from mirror plane) Camera.zPos stays the same Camera orientation, clueless on this one... mm anyways I'll continue reading up and perhaps find the answer on my own, but if anyone can provide a simpler explanation than the article on how to do this, I'd really appreciate the help. Cheers, Steve AKA Mephs
Promit
Promit
I'm not sure exactly what you're trying to do, but probably the easiest way to do this would be to invert the terrain's transformation matrix (so that it becomes upside down under the water) and render it again. If you render the water to the stencil buffer, then you can clip the terrain against the stencil test. You'd apply some kind of blending mode to the water, of course, so that it would be water, rather than a clean mirror [wink]
SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.
Mephs
Mephs
Does inverting the geometry have the same effect as mirroring the camera position/orientation though? I'm somewhat confused by it all, but would this not produce anomalies due to the viewing angle not being taken into account? Maybe it wouldn't but like I say.... I'm confused!

Basically I'd like the camera to be mirrored in position relative to the mirror plane, with its direction vector being the same as that of a reflected light vector from the original view, dos this achieve the same effect or is it just an approximation?
Yann L
Yann L
Assuming your water plane is at y = 0, and y is the up axis, then the easiest method is to simply multiply the view matrix with a mirror matrix like this one:
1  0  0  00 -1  0  00  0  1  00  0  0  1

That will flip the geometry (or the camera, it's the same, just seen from a different coordinate frame) around the Y axis.

If your plane is not exactly at y=0, then you need to adjust the translation part accordingly.
Mephs
Mephs
Okay, I've tried that, but didn't get the expected results. Perhaps I overlooked something. What I still don't get though, is that if it is as simple as creating a reflection matrix (which can be done with D3DXMatrixReflection), then why go into the huge number of steps taken in the Virtual Camera Position article, it just seems to be a hugely long way around the problem, or am I missing something?

Thanks for the response, and hopefully sooner or later I'll have it up and running :P

Steve
Yann L
Yann L
I haven't read the article you mentioned, but there are various ways to achieve what you want. They are all conceptually equivalent, but operate in different coordinate systems. The one I mentioned (or in more general form - a simple plane reflection matrix) works in world space. So it should be applied before doing any camera dependent transforms. That's the usualy chain of transforms:

Object -> World -> *Reflect* -> Camera transform -> Projection

So yes, it's as easy as inserting a single reflection matrix in this chain. Theoretically, you can insert it anywhere you want, but it has to match the geometry's coordinate frame at that position. Inserting it after the local object to world transform, and before the camera transform, is most intuitive for water IMO. It lets you specify the reflection matrix in world space coordinates.

Can you post the matrices you use for transformation, and the order you multiply them ?
Mephs
Mephs
// Grab the view transformationm_Graphics->GetDeviceCOM()->GetTransform(D3DTS_VIEW, &view_matrix);// Set up a reflection planereflect_plane.a = 0;reflect_plane.b = 1;reflect_plane.c = 0;reflect_plane.d = 0;// Create a reflection matrix and multiply it with the view matrixD3DXMatrixReflect(&reflect_matrix, &reflect_plane);D3DXMatrixMultiply(&view_matrix, &view_matrix, &reflect_matrix);// Set mirrored view matrix for render to texturem_Graphics->GetDeviceCOM()->SetTransform(D3DTS_VIEW, &view_matrix);// Render terrain to texture here// Reflect the view matrix back into its original form ready to render to backbufferD3DXMatrixReflect(&reflect_matrix, &reflect_plane);D3DXMatrixMultiply(&view_matrix, &view_matrix, &reflect_matrix);// Render terrain to backbuffer here


That's pretty much what I'm currently doing, the D3DX function builds the reflection matrix for me, and creates the matrix you showed earlier (checked when debugging).


I now seem to be getting anomalies with my fog that I hadn't previously noticed, and I'm not sure if they were present before, or if it's due to the view matrix tampering, but that could be a clue?

I saw something in another thread about reversing the cullmode to get correctly rendered geometry in the render to texture, is this necessary or should I be ok with the CCW culling I'm doing at present?

Thanks!
Yann L
Yann L
You left out the interesting part: how do you create the view matrix in the first place ? In that code snippet, you simply multiply the current view matrix with the reflection matrix, but the relationship between your view matrix and the camera transform is not clear. What kind of effects do you get with that code ? Does the geometry reflect ? Or what else does it do ?

About the culling, yes you need to reverse it, since you're applying a negative scale which will invert the vertex order.
Mephs
Mephs
Hmm, not sure what you mean there. My view matrix is created by the cCamera class, which creates the view matrix using the D3DXMatrixLookatLH function. I basically feed in a position and rotation each frame and it calculates my view matrix for me.

Aside from that, I've found what is causing the anomaly with the fog. It appears that some of the terrain I'm rendering to texture is being rendered in the backbuffer or the zbuffer (or rather perhaps it is still affecting the old buffer after making the switch) which is causing the terrain rendered to texture to occlude some of the actual terrain with the fog colour. I'm guessing that it could be that when the render to texture part does it's job, it leaves it's zwrites on the zbuffer or something like that, even though I switch back to the previous zbuffer... not quite sure why that's happening.



Above is an image of the current terrain, along with it's reflection (I've now reversed culling on render to texture). I still get the anomaly I mentioned though but I'll sort. Does it look about right?
Yann L
Yann L
Quote:
Original post by Mephs
It appears that some of the terrain I'm rendering to texture is being rendered in the backbuffer or the zbuffer (or rather perhaps it is still affecting the old buffer after making the switch) which is causing the terrain rendered to texture to occlude some of the actual terrain with the fog colour. I'm guessing that it could be that when the render to texture part does it's job, it leaves it's zwrites on the zbuffer or something like that, even though I switch back to the previous zbuffer... not quite sure why that's happening.

Well normally you'd ask for a render texture with it's own zbuffer. There should be no interference with the framebuffer once the switch to the RTT was made. Are you clearing the zbuffer of the RTT before use ?

Quote:
Original post by Mephs
Above is an image of the current terrain, along with it's reflection (I've now reversed culling on render to texture). I still get the anomaly I mentioned though but I'll sort. Does it look about right?

Hmm. Where is your water plane in that screenshot ? It looks like the geometry is reflected around the up camera axis, unless you have the camera at water level - in that case it would be OK. Otherwise, you're doing the reflection in camera space, not in world space - a quick fix would be to reverse the matrix multiplication order from view*reflect to reflect*view.
Mephs
Mephs
The water plane is at y=0 for simplicities sake at the moment. I found the zbuffer artifact was due to not realizing that the GetDepthStencilBuffer() function of a D3DDevice returns the current depth buffer, not the standard depthbuffer. I made this mistake as GetBackBuffer() returns the backbuffer as opposed to the rendertarget buffer. I assumed GetDepthStencilBuffer worked in the same way.

Anyhoo that's all fixed now, and my reflection now look correct!! weee! Sorry for so many questions, but at least it works now.

Now I just have to figure out how to generate projected exture co-ordinates and I'll be able to see the reflection in real-time instead of hacking my way to it :P

Thanks a lot :)
Yann L
Yann L
Yep, that looks correct. Did you reverse the matrix multiplication order or did you keep it as is ?

The projective texturing is not very hard either, now that you got this thing working. It's basically the exact same matrix you used for rendering the RTT, only multiplied with your current projection matrix and an additional remapping matrix. Load that into the texture matrix of the texture unit you want to project from (is it also called texture matrix in D3D ? I think so), and feed the unit the same 3D vertex positions you used for rendering, only as texcoords this time.

Quote:

Sorry for so many questions, but at least it works now.

Keep asking if you still have problems, that's what this forum is for after all.
Mephs
Mephs
Thanks again for the reply. I did indeed reverse the multiplication of matrices.

I'm having some difficulty understanding the projective texture coordinate mapping though. DX does indeed use texture matrices, but as I am not using pre-transformed vertices at the moment, I'm unable to use texture matrices. I am however using a vertex shader program, which I could use to the same effect (finally learnt vertex shaders!).

I assume you mean that I take the RTT matrix (reflected view matrix) and multiply with the projection matrix (in that order?). I'm lost on the remapping matrix? What is that exactly, what kind of matrix am I looking to make to do this remapping?

I'm fine with loading in the resulting matrix though, I can just load it as a VS constant and dp4 each of the components with the respective row of the result matrix, into a temp register (correct?).

Now, feeding the vertex data into the texture coordinates, i imagine that you mean that I would lock the vertex buffer, set the texture coordinates so that u = vertex x position and v = vertex y position? Or should I somehow be looking to make use of the x y AND z components? I assume though that I'm just using the x and z components and simply mul'ing with the temp registers holding the earlier results.

Am I going along the right lines or am I lost again... !?

Thanks as always!

Steve


Oh I should also mention DX has a setting D3DTTFF_PROJECTED which does something to do with dividing texture coordinates by the previous two co-ordinates or something, is this useful or unecessary with your method?
Yann L
Yann L
Quote:
Original post by Mephs
Thanks again for the reply. I did indeed reverse the multiplication of matrices.

OK, that's what I thought.

Quote:

I'm having some difficulty understanding the projective texture coordinate mapping though. DX does indeed use texture matrices, but as I am not using pre-transformed vertices at the moment, I'm unable to use texture matrices. I am however using a vertex shader program, which I could use to the same effect (finally learnt vertex shaders!).

Hmm, what do you mean by pre-transformed coordinates ? I know that D3D lets you specify pretransformed vertices, but that should be independent of the texture matrix (since it will only be applied to texture coordinates anyway) ?

Quote:

I assume you mean that I take the RTT matrix (reflected view matrix) and multiply with the projection matrix (in that order?).

OK, let's see - in OpenGL, it's Remap * Projection * View, so in D3D it should be the inverse (due to the inverted order of matrices): View * Projection * Remap should do it.

Quote:

I'm lost on the remapping matrix? What is that exactly, what kind of matrix am I looking to make to do this remapping?

OK, what I'm going to explain here is from OpenGL, I'm not entirely sure if it's exactly the same in D3D. In OGL, texture coordinates go from 0 to 1, but transformed device coordinates go from -1 to 1. I guess it should be the same for D3D, if not you'll have to adjust some numbers. The remapping matrix simply remaps the -1 to 1 range to the 0 to 1 range used for indexing the texture (as you can't properly index the texture with a -1 to 1 value, it would wrap around !). To do that, you have to divide the value by 2 (scale by 0.5), and add 0.5 (translate by 0.5). In matrix form, it looks like this:
0.5 0   0   00   0.5 0   00   0   0.5 00.5 0.5 0.5 1

(I hope I got that right for D3D)

Quote:

I'm fine with loading in the resulting matrix though, I can just load it as a VS constant and dp4 each of the components with the respective row of the result matrix, into a temp register (correct?).

Yes, correct.

Quote:

Now, feeding the vertex data into the texture coordinates, i imagine that you mean that I would lock the vertex buffer, set the texture coordinates so that u = vertex x position and v = vertex y position? Or should I somehow be looking to make use of the x y AND z components? I assume though that I'm just using the x and z components and simply mul'ing with the temp registers holding the earlier results.

No no, you will use all 3 vertex components (x,y,z) and theoretically also w, but this is usually one on standard geometry. Asuuming you're using a vertex shader, no need to lock any additional vertex buffers. Just use the vertex coordinates as vector into the texture matrix we talked about above.

Here is an example, it's for OpenGL, but you should be able to easily port it to a D3D vs.

First, we transform the vertex position by the combined view-projection matrix, as usual (you can also do two separate DP4 sets, one for the view and one for the projection matrix. But combining both is more efficient). As you can see, we just transform the original 4D vertex position (x,y,z,1) by the view-projection matrix, and write the result to the transformed vertex position register:
DP4 temp.x, ViewProjMatrix[0], vertex.position;DP4 temp.y, ViewProjMatrix[1], vertex.position;DP4 temp.z, ViewProjMatrix[2], vertex.position;DP4 temp.w, ViewProjMatrix[3], vertex.position;MOV result.position, temp;


Now the projective texture coordinates. We use the exact same original 3D vertex positions as above, but transform it by the texture matrix (View * Project * Remap) and write the resulting 4D vector into the texture coordinates of some texture unit:
DP4 temp.x, TextureMatrix[0], vertex.position;DP4 temp.y, TextureMatrix[1], vertex.position;DP4 temp.z, TextureMatrix[2], vertex.position;DP4 temp.w, TextureMatrix[3], vertex.position;MOV result.texcoord, temp;


That's basically it.

Quote:

Oh I should also mention DX has a setting D3DTTFF_PROJECTED which does something to do with dividing texture coordinates by the previous two co-ordinates or something, is this useful or unecessary with your method?

Yes, it's absolutely necessary, as it will enable the perspective divide on texture coordinates (dividing the first three components by the fourth one: a homogeneous divide). Without this step, you won't get the projection.
Mephs
Mephs
Hi again!

Well now my reflections finally look just about as expected!

Some things to take note of though. All matrices needed transposing before multiplication (except the remapping matrix which was fine as Yann suggested), I believe this is something to do with the dp4 instruction working in reverse order? I followed the matrix multiplications suggested and the result is below :



However, when close to the water I get the following anomaly as the texture wraps (I can't understand why it is wrapping, but when clamped it looks worse).



Any ideas what is causing that? Aside from that though, I'm very pleased with the progress so far, I had expected this would take me at least a week or two to figure out, and I've done most of the work in a couple of days :)

*EDIT* Okay, fixed the problem there by tinkering with the remapping matrix, but I have one final problem.

I think I need to be clipping geometry away in the render to texture stage, either with clipping planes, an alpha test or a stencil test. Am I right in thinking this, or is there a simpler way of removing the problem pictured below (which I'm assuming is arising from not clipping geometry, but perhas it could be something else?)





[Edited by - Mephs on June 26, 2004 12:11:18 PM]
Yann L
Yann L
Quote:
Original post by Mephs
*EDIT* Okay, fixed the problem there by tinkering with the remapping matrix, but I have one final problem.

What did you change ?

Quote:

I think I need to be clipping geometry away in the render to texture stage, either with clipping planes, an alpha test or a stencil test. Am I right in thinking this, or is there a simpler way of removing the problem pictured below (which I'm assuming is arising from not clipping geometry, but perhas it could be something else?)

It's hard to tell the origin of such artifacts from one image alone, but you're perfectly right about the clipping. If you didn't account for the clipping against the water plane, then you'll get visual artifacts.

You have different options when it comes to clipping. The most simple one is an additional geometric clip plane, but some hardware (especially from nvidia) can have problems with those. Alpha test is a possibility, but will use up your alpha and will prevent the early z rejection optimization to kick in. Another alternative is to use a pixelshader to remove pixels above the clipping plane. This is effective, but requires an additional pixelshader. Unfortunately, you can't use the stencil buffer for arbitrary 3D clipping.

And then there is also oblique frustum clipping, which might very well be the best alternative - although a little tricky to implement. It basically modifies your projection matrix in such a way, that the near frustum plane is remapped onto the clip plane, effectively substituting it. The whole clipping mechanism is then reduced to standard frustum clipping, all you have to do is upload a special projection matrix. It works on every hardware, and doesn't require any additional resources. There are unfortunately not too many resources about this technique available. Try Google. nVidia used to have a demo, but they took it down because it was buggy. If you select this option, let me know, and I'll post some more resources and code.

[Edit] Here is sample code for optimized (and bug free) oblique frustum clipping from Eric Lengyel.
Mephs
Mephs
Hiya,

Well I'm at work right now on a break, so I don't have access to my code, but I'll post some when I get home to show what I have right now. I think I had to do something along the lines of mutliplying my reflect matrix with the remap matrix, or tranpossing it or both, I'll take a look when I get home and update the thread with it.

Thanks for the advice with the clipping, I'll certainly give the oblique clipping method a try, as you say, using up the alpha might not be such a great idea, and I seemed to have problems trying to set up a hardware clipping plane in that it didn't seem to have any effect at all, though that may be due to not setting up the plane correctly (and yes, I'm using a Geforce FX5700). I also noticed that the artifacts got worse if I move the water/reflection plane away from 0. I had to adjust my reflection plane coefficients to a=0, b=1, c=0, d= -5.0 (negative 5.0) when my water plane was at a height of 5.0 units to get anything resembling a correct reflection, I don't know if that helps identify my problem a little better? Most of the time the reflection looks correct, but sometimes I appear to get reflections coming from nowhere, which may be clipping, or it could be something with my projected texture co-ordinates not lining up correctly I guess?

Anyhoo, I'll post code when I get home,

Cheers,

Steve

Mephs
Mephs
My water rendering code is below, this does not include the code used to render the reflection, only the code used to map the reflection to the water surface :
D3DXMATRIX projection_matrix, reflect_matrix, view_matrix, world_matrix, 		viewprojremap_matrix, viewproj_matrix, remap_matrix;	D3DXPLANE reflect_plane;	D3DXVECTOR4 FogParams, MirrorParams;		// Set the world transform for the water	m_WorldPosition.Update(m_Graphics);	m_Graphics->SetWorldPosition(&m_WorldPosition);	// Plane used to reflect various matrices	reflect_plane.a=0;	reflect_plane.b=1;	reflect_plane.c=0;	reflect_plane.d=-5.0;		// .x = fog start	// .y = fog end	// .z = 1/range	// .w = fog max		FogParams.x = 150.0f;	FogParams.y = 200.0f;	FogParams.z = ((float)1/50);	FogParams.w = 1.0f;		// .x = Water plane height	// .y = Unused	// .z = Water texture scroll modifier	// .w = Unused	MirrorParams.x = 5.0f;	MirrorParams.y = 5.0f;	MirrorParams.z += 0.0001f;	MirrorParams.w = 5.0f;	// Get transform matrices	m_Graphics->GetDeviceCOM()->GetTransform(D3DTS_WORLD, &world_matrix);	m_Graphics->GetDeviceCOM()->GetTransform(D3DTS_PROJECTION, &projection_matrix);	m_Graphics->GetDeviceCOM()->GetTransform(D3DTS_VIEW, &view_matrix);	// Transpose matrices ready for vertex shader dp4	D3DXMatrixTranspose(&view_matrix, &view_matrix);	D3DXMatrixTranspose(&projection_matrix, &projection_matrix);	// Set remap matrix	remap_matrix._11=0.5;	remap_matrix._12=0;	remap_matrix._13=0;	remap_matrix._14=0.5;	remap_matrix._21=0;	remap_matrix._22=0.5;	remap_matrix._23=0;	remap_matrix._24=0.5;	remap_matrix._31=0;	remap_matrix._32=0;	remap_matrix._33=0.5;	remap_matrix._34=0.5;	remap_matrix._41=0;	remap_matrix._42=0;	remap_matrix._43=0;	remap_matrix._44=1.0;		// Create view * projection matrix	D3DXMatrixMultiply(&viewproj_matrix, &projection_matrix, &view_matrix);		// Create & transpose (for dp4) reflection matrix	D3DXMatrixReflect(&reflect_matrix, &reflect_plane);	D3DXMatrixTranspose(&reflect_matrix, &reflect_matrix);	// Reflect the remap matrix	D3DXMatrixMultiply(&remap_matrix, &reflect_matrix, &remap_matrix);		// Create a mirrored version of view * projection * remap matrix	D3DXMatrixMultiply(&viewprojremap_matrix, &projection_matrix, &view_matrix);	D3DXMatrixMultiply(&viewprojremap_matrix,   &remap_matrix,&viewprojremap_matrix);	// Set shader constants	m_Graphics->GetDeviceCOM()->SetVertexShaderConstant(0, viewproj_matrix, 4);	m_Graphics->GetDeviceCOM()->SetVertexShaderConstant(8, viewprojremap_matrix, 4);;	m_Graphics->GetDeviceCOM()->SetVertexShaderConstant(23, MirrorParams, 1);	m_Graphics->GetDeviceCOM()->SetVertexShaderConstant(16, FogParams, 1);		// Working with a flat plane for the time being, water solver unused	// m_WaterSolver->Simulate();		//if(Random > 90)	//	m_WaterSolver->ApplyForce(RandomX,RandomY,Random2);		//sVertex *pVB;	//m_WaterVB->Lock(0,0,(BYTE**)&pVB,0);	//for(int y=0;y<m_NumVertsY;y++)	//{	//	for(int x=0;x<m_NumVertsX;x++)	//	{	//		pVB[(y*m_NumVertsX)+x].y = m_HeightField[(y*m_NumVertsX)+x];	//	}	//}	//m_WaterVB->Unlock();	// Set up for projected textures (count4 divides by previous 3 elements)	m_Graphics->GetDeviceCOM()->SetTextureStageState( 0, D3DTSS_TEXTURETRANSFORMFLAGS,                                 D3DTTFF_COUNT4 | D3DTTFF_PROJECTED );	// Set the render/texture stage states	m_Graphics->GetDeviceCOM()->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX,0);	m_Graphics->GetDeviceCOM()->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE );	m_Graphics->GetDeviceCOM()->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT );	m_Graphics->GetDeviceCOM()->SetTextureStageState(0, D3DTSS_COLOROP,   D3DTOP_SELECTARG1 );	m_Graphics->GetDeviceCOM()->SetTextureStageState(0, D3DTSS_ALPHAOP,  D3DTOP_SELECTARG1 );	m_Graphics->GetDeviceCOM()->SetTextureStageState(0, D3DTSS_ALPHAARG1,   D3DTA_DIFFUSE);	m_Graphics->GetDeviceCOM()->SetTextureStageState(0, D3DTSS_ALPHAARG2,   D3DTA_TEXTURE );	m_Graphics->GetDeviceCOM()->SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR);	m_Graphics->GetDeviceCOM()->SetTextureStageState(0, D3DTSS_MINFILTER, D3DTEXF_LINEAR);	m_Graphics->GetDeviceCOM()->SetTextureStageState(0, D3DTSS_ADDRESSU, D3DTADDRESS_WRAP);	m_Graphics->GetDeviceCOM()->SetTextureStageState(0, D3DTSS_ADDRESSV, D3DTADDRESS_WRAP);	m_Graphics->GetDeviceCOM()->SetTextureStageState(0, D3DTSS_ADDRESSW, D3DTADDRESS_WRAP);		m_Graphics->GetDeviceCOM()->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX,1);	m_Graphics->GetDeviceCOM()->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE);	m_Graphics->GetDeviceCOM()->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT );	m_Graphics->GetDeviceCOM()->SetTextureStageState(1, D3DTSS_COLOROP,   D3DTOP_MODULATE2X);	m_Graphics->GetDeviceCOM()->SetTextureStageState(1, D3DTSS_MAGFILTER, D3DTEXF_LINEAR);	m_Graphics->GetDeviceCOM()->SetTextureStageState(1, D3DTSS_MINFILTER, D3DTEXF_LINEAR);	m_Graphics->GetDeviceCOM()->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);	m_Graphics->GetDeviceCOM()->SetTextureStageState(1, D3DTSS_ALPHAARG1, D3DTA_CURRENT);	m_Graphics->GetDeviceCOM()->SetTextureStageState(1, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);	m_Graphics->GetDeviceCOM()->SetTextureStageState(1, D3DTSS_RESULTARG, D3DTA_CURRENT);	m_Graphics->GetDeviceCOM()->SetTextureStageState(1, D3DTSS_ADDRESSU, D3DTADDRESS_WRAP);	m_Graphics->GetDeviceCOM()->SetTextureStageState(1, D3DTSS_ADDRESSV, D3DTADDRESS_WRAP);	m_Graphics->GetDeviceCOM()->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);		m_Graphics->EnableZBuffer(TRUE);	m_Graphics->EnableAlphaBlending(FALSE);		// Set index/vertex stream	m_Graphics->GetDeviceCOM()->SetIndices(m_WaterIB,0);	m_Graphics->GetDeviceCOM()->SetStreamSource(0,m_WaterVB,sizeof(sVertex));		// Set vertex shader	m_Graphics->GetDeviceCOM()->SetVertexShader(m_shader_handle);		// Set textures	m_Graphics->GetDeviceCOM()->SetTexture(0, Reflection->GetTextureCOM());	m_Graphics->GetDeviceCOM()->SetTexture(1, m_WaterTexture.GetTextureCOM());	// Render water	m_Graphics->GetDeviceCOM()->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,(m_NumVertsX*m_NumVertsY),0, ((m_NumVertsX-1)*(m_NumVertsY-1))*3);	// Disable projective texturing	m_Graphics->GetDeviceCOM()->SetTextureStageState( 0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE );


Next is my vertex shader :
vs.1.1;c0 = view * proj matrix;c8 = view * proj * remap matrix;c16 = fog parametersdp4 r0.x, v0, c0 ;emit projected positiondp4 r0.y, v0, c1 ;emit projected positiondp4 r0.z, v0, c2 ;emit projected positiondp4 r0.w, v0, c3 ;emit projected positionmov oPos, r0 ; Set vertex positionsdp4 r10.x, c8, v0;dp4 r10.y, c9, v0;dp4 r10.z, c10, v0;dp4 r10.w, c11, v0; multiply view * proj * remap matrix with vertex position mov oT0, r10; output texture coordinates for reflectionadd oT1.xy, v7.xy, c23.z; add texture scroll modifier to tex coords for water texturemov oD0, v5; output diffuse colour; Scale by fog parameters :; c16.x = fog start; c16.y = fog end; c16.z = 1/range; c16.w = fog maxdp4 r2, v0, c2 ; r2 = distance to cameraadd r3.x, c16.y, -r2.x; (end - distance )mul oFog.x, c16.z, r3.x ; Normalized distance * (end-distance) 


Finally, for good measure, here is another screenshot showing an error... hope that helps!



Yann L
Yann L
I'd say the artifacts you get are clipping errors. Not clipping objects that go through the water plane can create some really weird and unpredictable visual errors.

Have you tried some clipping algorithm yet ?
Mephs
Mephs
Thanks for the reply :)

I have implemented clipping now, however I'm using the stencil buffer rather than the oblique frustum technique. The stencil buffer is working pretty well, with only a couple of tiny errors which I think will be unnoticeable once I add a bumpmap.

I transposed my projection matrix so that I could modify it just like an OpenGL matrix, and rewrote the code on the provided page so that it worked for DirectX, and finally tranposed the resulting matrix back to a RH matrix. I found though that it didn't seem to work at all, instead, the projected texture seemed to move with the view, and nothing was being clipped at all. I'm pretty sure my conversion of the code was fine, but can post it later just to be sure.

My main problem now is improving the framerate, as I've not been writing optimized code, but rather just attempting to get it to work, so my performance hit is quite large. However, I'm going to attempt to only update the reflection every few frames or so, so that I'm not contantly rendering twie the gemoetry I need to.

The other bonus with using the stencil buffer is that it should work, in theory, with the water plane even when I am simulating the movement of the water surface (ie when it is not a flat plane), which clipping planes and oblique frustums would not allow for, so I think this is the method I'm going to stick with.

I'll post additional code and screenshots of the small errors later so anyone with similar problems can see my solution if they need to.

Thanks,

Steve

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.