[XNA] Water reflection problems

Started by
4 comments, last by Mavix_2008 16 years, 1 month ago
I am quite new to XNA, and I have been following Riemers tutorials. Once I completed those, I started on my own project. All has been going well so far, except I can't get the reflection on the water to work. Then I realized that I was missing some code to create the matrix for the reflection method. So it works. Sort of. The reflection does not reflect properly. This image is the reflection texture that XNA generated: http://i209.photobucket.com/albums/bb101/Mavix_2007/reflection.jpg This already explains my problem, because there is no grass above the water, or next to it if I'm in the middly of the lake. Using this reflection texture, I will try to explain what happens on the water. First, three screenshots with me panning the camera down: http://i209.photobucket.com/albums/bb101/Mavix_2007/01.jpg http://i209.photobucket.com/albums/bb101/Mavix_2007/02.jpg http://i209.photobucket.com/albums/bb101/Mavix_2007/03.jpg If I keep the camera at the same rotation as in picture two, and I move forward quickly, then it looks as if the terrain underneath has been inverted and is moving on the water. Its almost as if its reflecting whats underneath the water, which is obvious looking at the reflection texture. I have used exactly the code that Reimers uses. Does anyone know whats going on?
Advertisement
You said you started your own project, do you use the Y-axis as default "Up"? Because Riemers tutorials use Z as up, which is not the default for XNA.
I agree with FoxHunter2, a lot of people are having trouble with the Up vector being Z.

Is your shader the exact same as Riemer's?

Can you post the water drawing function and the code segment where you get your Reflection Texture?
I use Z as the up vector. The water code is the same as Riemers, and his series four code works perfectly. I've taken some new screenshots to give you a better idea of whats going on(Once again panning down the camera):

Photobucket

Photobucket

Photobucket

My shader code is exactly the same as Riemers.

Here's the water code:

//From Game1.cs
protected override void Draw(GameTime gameTime)
{
map.DrawReflectionMap(camera, device, this);
map.DrawRefractionMap(camera, device, this);

graphics.GraphicsDevice.Clear(Color.SkyBlue);

map.DrawMap(camera, device);
map.DrawWater(camera, device, this);

objectNodes.drawObjects(camera);

base.Draw(gameTime);
}

public void DrawEverythingExceptWater()
{
map.DrawMap(camera, device);
objectNodes.drawObjects(camera);
}

//From mapHandler.cs
public void DrawWater(CameraHandler camera, GraphicsDevice device, Game1 game)
{
waterEffect.CurrentTechnique = waterEffect.Techniques["Water"];

Matrix worldMatrix = Matrix.Identity;
waterEffect.Parameters["xWorld"].SetValue(worldMatrix);
waterEffect.Parameters["xView"].SetValue(camera.viewMatrix);
waterEffect.Parameters["xReflectionView"].SetValue(reflectionViewMatrix);
waterEffect.Parameters["xProjection"].SetValue(camera.projectionMatrix);
waterEffect.Parameters["xReflectionMap"].SetValue(reflectionMap);
waterEffect.Parameters["xRefractionMap"].SetValue(refractionMap);
waterEffect.Parameters["xWaterBumpMap"].SetValue(waterBumpMap);
waterEffect.Parameters["xWaveLength"].SetValue(0.1f);
waterEffect.Parameters["xWaveHeight"].SetValue(0.3f);
waterEffect.Parameters["xCamPos"].SetValue(camera.cameraPosition);
waterEffect.Parameters["xTime"].SetValue(game.elapsedTime);
waterEffect.Parameters["xWindForce"].SetValue(20.0f);

Matrix windDirection = Matrix.CreateRotationZ(MathHelper.PiOver2);
waterEffect.Parameters["xWindDirection"].SetValue(windDirection);

waterEffect.Begin();
foreach (EffectPass pass in waterEffect.CurrentTechnique.Passes)
{
pass.Begin();
device.VertexDeclaration = new VertexDeclaration(device, VertexPositionTexture.VertexElements);
device.DrawUserPrimitives(PrimitiveType.TriangleList, waterVertices, 0, 2);
pass.End();
}
waterEffect.End();
}

public void DrawReflectionMap(CameraHandler camera, GraphicsDevice device, Game1 game)
{
Vector3 planeNormalDirection = new Vector3(0, 0, 1);
planeNormalDirection.Normalize();
Vector4 planeCoefficients = new Vector4(planeNormalDirection, -waterHeight);

Matrix camMatrix = reflectionViewMatrix * camera.projectionMatrix;
Matrix invCamMatrix = Matrix.Invert(camMatrix);
invCamMatrix = Matrix.Transpose(invCamMatrix);

planeCoefficients = Vector4.Transform(planeCoefficients, invCamMatrix);
Plane reflectionClipPlane = new Plane(planeCoefficients);

device.ClipPlanes[0].Plane = reflectionClipPlane;
device.ClipPlanes[0].IsEnabled = true;

device.SetRenderTarget(0, reflectionRenderTarget);
device.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.SkyBlue, 1.0f, 0);
game.DrawEverythingExceptWater();
device.ResolveRenderTarget(0);
reflectionMap = reflectionRenderTarget.GetTexture();
device.SetRenderTarget(0, null);

device.ClipPlanes[0].IsEnabled = false;
}

public void UpdateReflectionCamera(CameraHandler camera, Game1 game)
{
float reflectionCamZCoord = -camera.cameraPosition.Z + 2 * waterHeight;
Vector3 reflectionCamPosition = new Vector3(camera.cameraPosition.X, camera.cameraPosition.Y, reflectionCamZCoord);

float reflectionTargetZCoord = -camera.targetPos.Z + 2 * waterHeight;

Vector3 reflectionCamTarget = new Vector3(camera.targetPos.X, camera.targetPos.Y, reflectionTargetZCoord);

Vector3 forwardVector = reflectionCamTarget - reflectionCamPosition;
Vector3 sideVector = Vector3.Transform(new Vector3(1, 0, 0), camera.cameraRotation);
Vector3 reflectionCamUp = Vector3.Cross(sideVector, forwardVector);

reflectionViewMatrix = Matrix.CreateLookAt(reflectionCamPosition, reflectionCamTarget, reflectionCamUp);
}
I notice you're not passing the 'reflectionViewMatrix' Matrix into the Map.DrawMap function. I believe Reimer passes the 'reflectionViewMatrix' in when drawing the terrain and sky onto the reflection texture for use as the View Matrix.

        private void DrawTerrain(Matrix currentViewMatrix)        {           .           .           .            Matrix worldMatrix = Matrix.Identity;            effect.Parameters["xWorld"].SetValue(worldMatrix);            effect.Parameters["xView"].SetValue(currentViewMatrix);         private void DrawReflectionMap()         {           .           .           .             DrawTerrain(reflectionViewMatrix);             DrawSkyDome(reflectionViewMatrix);


[Edited by - Mr Explody on March 6, 2008 11:59:25 PM]
Thanks, that fixed it.

This topic is closed to new replies.

Advertisement