Jump to content


D3D10 water rendering


70 replies to this topic

#1 XVincentX

    Valued Member

  • Members
  • PipPipPip
  • 115 posts

Posted 19 September 2008 - 02:22 PM

Hello.
After, finally, completed the shadow volume example, now, before make a journey in long shadow mapping way, i would like to make a little water example.

I'm reading the ShaderX2 article, i will explain you what am i doing, hoping that someone will find the error.

Quote

Rendering the Underwater Scene (First Render Pass)
We want to simulate a close-to-reality view into the water. The seabed and objects
like fish or plants should be distortable by faked bumps (see the section “Animated
Surface Bumping”). So, we have to render the underwater scene view each
frame again into a render-target texture. For this job, we use the original camera.
A clip plane cuts off the invisible part of the scene above the water surface

For this, i created another texture and, after getting the backbuffer, i made a CopyResource and it works. So, no render target it's needed (i hope)

The second pass it's the
Modifications Dependent on Water Depth
It say to use a vertex and pixel shader, but i did not understand where. On the water-grid mesh? Anyway, if i use it, i can't see the plane on the screen.

The shader is


// VERTEX SHADER (for DX9 hardware and better) VS-1

// FUNCTION: Modifies underwater scene texture

//

// INPUT:

// v0 = position (3 floats)

// c0 - c3 = world/view/proj matrix

// version instruction

vs 2 0

210

Advanced Water Effects

Figure 4: Reduction formula exp ( –d *  )

// declare registers

dcl position v0

// transform position into projection space

dp4 oPos.x, v0, c0 // c0 = first row of transposed world/view/proj-matrix.

dp4 oPos.y, v0, c1 // c1 = second row of transposed world/view/proj-matrix.

dp4 oPos.z, v0, c2 // c2 = third row of transposed world/view/proj-matrix.

dp4 oPos.w, v0, c3 // c3 = forth row of transposed world/view/proj-matrix.

// transfer position to pixel shader

mov oT0, v0 // We pass the vertex position to the pixel shader as tex coord.




I traslated it in this way.


float4x4	ViewMatrix;

float4x4	WorldMatrix;

float4x4	ProjMatrix;

float4		LightDirection;

float4		MaterialColor;

float3		EyePosition;

texture2D	Texture;

texture2D	CurrentBackbuffer;


SamplerState SamplText

{

    Filter = MIN_MAG_MIP_LINEAR;

    AddressU = Wrap;

    AddressV = Wrap;

};



struct VS_INPUT

{

	float4	Pos	:	POSITION;

	float3	Tex	:	TEXCOORD;

	float3	Nor	:	NORMAL;

};


struct PS_INPUT

{

	float4	Pos	:	SV_POSITION;

	float4	WorldPos:	WORLDPOSITION;

	float3	Tex	:	TEXCOORD;

	float3	Nor	:	NORMAL;

};


PS_INPUT vs_main(VS_INPUT Input)

{

	PS_INPUT Out = (PS_INPUT)0;

	Out.Pos = mul(mul(mul(Input.Pos,WorldMatrix),ViewMatrix),ProjMatrix);

	Out.WorldPos = mul(Input.Pos,WorldMatrix);

	Out.Tex = Input.Tex;

	Out.Nor = mul(Input.Nor,WorldMatrix);

	return Out;

}


PS_INPUT vs_plane(VS_INPUT input)

{

	PS_INPUT output = (PS_INPUT)0;

	

	output.Pos = mul(input.Pos, transpose(WorldMatrix));

	output.Pos = mul(output.Pos, transpose(ViewMatrix));

	output.Pos = mul(output.Pos, transpose(ProjMatrix));

	

	output.Nor = mul( input.Nor, WorldMatrix );


	output.Tex = float3(output.Pos.x,output.Pos.y,output.Pos.z);

	return output;

}


float4 ps_plane(PS_INPUT input)	:	SV_TARGET

{

	return CurrentBackbuffer.Sample(SamplText,saturate(input.Tex));

}


float4 ps_main(PS_INPUT In)	:	SV_TARGET

{

		return Texture.Sample(SamplText,In.Tex);

}



technique10 WaterEffect

{

	Pass PositionTextured

	{

        SetVertexShader( CompileShader( vs_4_0, vs_main() ) );

        SetGeometryShader(NULL);

        SetPixelShader( CompileShader( ps_4_0, ps_main() ) );

	}

	

	Pass Plane

	{

        SetVertexShader( CompileShader( vs_4_0, vs_plane() ) );

        SetGeometryShader(NULL);

        SetPixelShader( CompileShader( ps_4_0, ps_plane() ) );

	}

}



The second part of the article say modification of the texture depend of water depth.
Ok, but where have i to apply the texture? On the grid plane mesh?
Anyway, if yes or not, the second pass make this, but it seems to not work.

Hints?

#2 rouncer

    Senior Member

  • Members
  • PipPipPipPip
  • 2722 posts

Posted 19 September 2008 - 03:28 PM

I know the algorythm your talking about, your kicking a bit of but if you get this into your game, it looks pretty cool, i imagine it looks really nice with specular.
i havent implemented it myself yet, ive only got a rough idea in my head how it works, so i cant really help ya.
good going tho, hope you get it into your game system.

#3 starstutter

    Senior Member

  • Members
  • PipPipPipPip
  • 1039 posts

Posted 19 September 2008 - 04:20 PM

I'm sorry, but It's not entirley clear to me what your problem is. You're trying to realistic water when your view-point is above the water right (or just not under the water surface).

I'm also not totally familiar with that wording the book is using. I do know exactly the technique your talking about though, and it was MUCH easier to implement than I had predicted (much less complicated than shadow volumes anyway).

So is your first problem that you need to get the image of the refraction (underwater scene) onto the water itself? That involves a much simpler concept than the book may have you belive.



Your current code is:

PS_INPUT vs_plane(VS_INPUT input)

{

	PS_INPUT output = (PS_INPUT)0;

	

	output.Pos = mul(input.Pos, transpose(WorldMatrix));

	output.Pos = mul(output.Pos, transpose(ViewMatrix));

	output.Pos = mul(output.Pos, transpose(ProjMatrix));

	

	output.Nor = mul( input.Nor, WorldMatrix );


	output.Tex = float3(output.Pos.x,output.Pos.y,output.Pos.z);

	return output;

}


float4 ps_plane(PS_INPUT input)	:	SV_TARGET

{

	return CurrentBackbuffer.Sample(SamplText,saturate(input.Tex));

}


I can kind of see where you thought that may be right, placing the texture coordinates according to the world space, but I can;t mathematicly see how that would work and that's certainly more complicated than the way I did it.



//modify PS_INPUT to include another float4 called Pos2


PS_INPUT vs_plane(VS_INPUT input)

{

	PS_INPUT output = (PS_INPUT)0;

	

	output.Pos = mul(input.Pos, transpose(WorldMatrix));

	output.Pos = mul(output.Pos, transpose(ViewMatrix));

	output.Pos = mul(output.Pos, transpose(ProjMatrix));

	

             output.Pos2 = output.Pos;


	output.Nor = mul( input.Nor, WorldMatrix );


             //this line does nothing important, you can remove it

	//output.Tex = float3(output.Pos.x,output.Pos.y,output.Pos.z);

	return output;

}


float4 ps_plane(PS_INPUT input)	:	SV_TARGET

{

float2 ViewTexC = 0.5 * input.Pos2.xy / input.Pos2.w + float2( 0.5, 0.5 );

ViewTexC.y	=	1.0f - ViewTexC.y;


	return CurrentBackbuffer.Sample(SamplText,ViewTexC);

//the "saturate" instruction is not needed because the projective texture coords cannot go past 0-1

}



It's funny you should mention shadow-maps because both of these techniques use the same concept, that is, projective texturing. The camera is essentially projecting the image from your view point onto the water surface. All it takes to modify it is a += or -=, and there are literally hundereds of ways to do that.

EDIT: btw, what's with the "transpose" commands? The raw matricies themselves should correctly transform the geometry.
(\__/)
(='.'=)
This is Bunny. Copy and paste bunny into
(")_(") your signature to help him gain world domination.
bunny also wants to fight spam: Click Here Bots!

#4 XVincentX

    Valued Member

  • Members
  • PipPipPip
  • 115 posts

Posted 19 September 2008 - 05:04 PM

Finally someone that can help me!
Thank you, at first!!!

I will try now to explain the problem.
At first, the ShaderX2 book it's free for download: you can take a look in the article downloading it at this link http://www.gamedev.n...h_DirectX_9.pdf

Now if you read article, he divides the effect in some Passes:

Rendering the Underwater Scene (First Render Pass)
I make this by using CopyResource function from backbuffer, without use a RenderTarget and render again the same geometry.

Modifications Dependent on Water Depth
(Second Render Pass)

This is what i do not understand. As he say from the shader:

// VERTEX SHADER (for DX9 hardware and better) VS-1

// FUNCTION: Modifies underwater scene texture

//

// INPUT:

// v0 = position (3 floats)

// c0 - c3 = world/view/proj matrix

// version instruction

vs 2 0

210

Advanced Water Effects

Figure 4: Reduction formula exp ( –d *  )

// declare registers

dcl position v0

// transform position into projection space

dp4 oPos.x, v0, c0 // c0 = first row of transposed world/view/proj-matrix.

dp4 oPos.y, v0, c1 // c1 = second row of transposed world/view/proj-matrix.

dp4 oPos.z, v0, c2 // c2 = third row of transposed world/view/proj-matrix.

dp4 oPos.w, v0, c3 // c3 = forth row of transposed world/view/proj-matrix.

// transfer position to pixel shader

mov oT0, v0 // We pass the vertex position to the pixel shader as tex coord.


So, even if i did not understand the shader, i decided to use transposed version of matrix.

And here is the problem...for other information, just ask for them!

I made a D3D10 Example of Shadow Volume, no Shadow Map!

#5 starstutter

    Senior Member

  • Members
  • PipPipPipPip
  • 1039 posts

Posted 19 September 2008 - 06:51 PM

well unfortunatley I'm not good at reading assembly language =/

I looked at that article... and this is ****ing rediculous. I've never understood why the people who write those articles have to take the simplest tasks and stretch them out into the most impossible to understand jibberish.

Personally, I would just forget the article and start over in your own words, because they are making it WAY more complicated to take in than it needs to be.

Here are some ground rules for rendering water, and this is the way I do it:

1. Render the water plane normally, no wierd transformations, no "transposing", no inverting, ect. Just render it like you do everything else.

2. In the vertex shader, add the semantic that I did (the position2 variable) and make it equal to the final output of position1 (after all matrix transformations)

Now, this should give you just a flat, normal water plane

3. In the pixel shader, use the position2 parameter in the equasion described to calculate the ViewTexC vector. These are the texture coordinates that you will use to sample the refraction image (the copied back-buffer)
note: if you're wondering why you need a second parameter for position2, I actually have no idea. The shader simply won't compile if you use the output position.

4. Now the water should become "invisible". If it's not invisible you did something wrong. The image will be perfectly projected onto the plane and therefore you it should be like a window. To make the plane visible again, darken the colors a slight bit (or raise if you're doing HDR, totally up to you).

5. There are lots of ways you can make realsitic water. Personally I stretch a normal-map across the plane and modify the ViewTexC coordinates by those and fresnel effects
(\__/)
(='.'=)
This is Bunny. Copy and paste bunny into
(")_(") your signature to help him gain world domination.
bunny also wants to fight spam: Click Here Bots!

#6 XVincentX

    Valued Member

  • Members
  • PipPipPip
  • 115 posts

Posted 19 September 2008 - 08:37 PM

starstutter said:

well unfortunatley I'm not good at reading assembly language =/

Me too. I really do not understand nothing in that language.

Quote

I looked at that article... and this is ****ing rediculous. I've never understood why the people who write those articles have to take the simplest tasks and stretch them out into the most impossible to understand jibberish.

Personally, I would just forget the article and start over in your own words, because they are making it WAY more complicated to take in than it needs to be.

Yes, i noticed it. And the same thing happens when reading the GPUGems articles...they are considered as the Byble of gems programming, but in my opinion, people who write articles should better use words...anyway...

Quote

1. Render the water plane normally, no wierd transformations, no "transposing", no inverting, ect. Just render it like you do everything else.

Ok, even if i really would understand why all that things...

Quote

2. In the vertex shader, add the semantic that I did (the position2 variable) and make it equal to the final output of position1 (after all matrix transformations)

Now, this should give you just a flat, normal water plane

3. In the pixel shader, use the position2 parameter in the equasion described to calculate the ViewTexC vector. These are the texture coordinates that you will use to sample the refraction image (the copied back-buffer)
note: if you're wondering why you need a second parameter for position2, I actually have no idea. The shader simply won't compile if you use the output position.

Done.
I know about the Position as a inusable value...mabye becouse it's a System Value semantic ( : POSITION)

Quote

4. Now the water should become "invisible". If it's not invisible you did something wrong. The image will be perfectly projected onto the plane and therefore you it should be like a window. To make the plane visible again, darken the colors a slight bit (or raise if you're doing HDR, totally up to you).

Yes, it works, but i would better understand why have i to make that particular equation:


float2 ViewTexC = 0.5 * input.Pos2.xy / input.Pos2.w + float2( 0.5, 0.5 ); //what when why and becouse

ViewTexC.y	=	1.0f - ViewTexC.y; //Ok i understand it


I understand only the second line (becouse texture space it's different from projection space, ok)
But the first line?

Quote

5. There are lots of ways you can make realsitic water. Personally I stretch a normal-map across the plane and modify the ViewTexC coordinates by those and fresnel effects

Ok...links? Helps? resources?

#7 Reedbeta

    DevMaster Staff

  • Administrators
  • 5307 posts
  • LocationBellevue, WA

Posted 19 September 2008 - 10:10 PM

In that code snippet you posted, what's going on is pos2.xy / pos2.w is the perspective projection: dividing eye space x and y by eye space depth, stored in w, giving you screen space x and y. That gives you x and y both in the range of -1 to 1, but for a texture lookup you want them to be in the range of 0 to 1 instead. So, you multiply by 0.5 and add 0.5 to each component and that remaps them from [-1, 1] to [0, 1].
reedbeta.com - developer blog, OpenGL demos, and other projects

#8 starstutter

    Senior Member

  • Members
  • PipPipPipPip
  • 1039 posts

Posted 20 September 2008 - 02:47 AM

XVincentX said:

Ok...links? Helps? resources?

Well, unfortunatley I didn't ever find a resource that didn't have the same problems of all the other articles (that is, overly and necessarily complicated). Not that I have not quite completed my algorithem yet so this is simply a rough model to follow:

1. First thing is just something to keep in mind. The water plane is essentially an object, so treat it as such. You can apply normal mapping to it as you would any other object, this is the first step.

2. Use the normals to distort the image. I currently use a VERY rough approximation just to get the job done, I plan on modifying this later:

ViewTexC += (normals.xy * (1-VdotN) ) * .001;

or something like that... really you'll need to just play around with it.

3. Now for some primitive reflection. First off is lights. Obviously for this we would use a specular component (phong shading). Raise the power very high and adjust the intensity accordingly. The normal maps should be enough to provide very good lighting detail. As you can probably suspect, water doesn't really need a diffuse component unless it's really... nasty water... but that's kind of a different subject.

4. Now for world reflections. This early in, I would stick to cube maps. Just environment map it like you would anything else, and do a fresnel term ( pow(1-VdotN, 10) ). Tweek it to how you like.

Now, doing realtime and local reflections is not as an advanced of a topic as you might think. In essense you just flip the scene upside down and render it, along with some other steps, but its suprisingly hard to implement because of so many complications. So local reflections are awesome, but for now just stick to cube mapping and see where you get.
(\__/)
(='.'=)
This is Bunny. Copy and paste bunny into
(")_(") your signature to help him gain world domination.
bunny also wants to fight spam: Click Here Bots!

#9 starstutter

    Senior Member

  • Members
  • PipPipPipPip
  • 1039 posts

Posted 20 September 2008 - 03:03 AM

I figured I would show you what this algorithem would give you. Honestly I don't remember entirley if this is what it was because these pics are like... a year old. The first is showing more refraction and the second shows better realtime reflection.

Posted Image


(\__/)
(='.'=)
This is Bunny. Copy and paste bunny into
(")_(") your signature to help him gain world domination.
bunny also wants to fight spam: Click Here Bots!

#10 XVincentX

    Valued Member

  • Members
  • PipPipPip
  • 115 posts

Posted 20 September 2008 - 07:44 AM

Reedbeta said:

In that code snippet you posted, what's going on is pos2.xy / pos2.w is the perspective projection: dividing eye space x and y by eye space depth, stored in w, giving you screen space x and y. That gives you x and y both in the range of -1 to 1, but for a texture lookup you want them to be in the range of 0 to 1 instead. So, you multiply by 0.5 and add 0.5 to each component and that remaps them from [-1, 1] to [0, 1].


1)I do not understand yet...making the 3 matrix multiplication, should i have already got position in perspective position? Why have i to / pos.w?
2) Can't i use saturate or clamp instead add 0.5? (Just to understand)
3)What a nice rendering! I would reach the same result!!!
4)What can you say me about water movement?
5)I would avoid the use of cubemap, anyway today i will try so write some other code, thank you again!

#11 rouncer

    Senior Member

  • Members
  • PipPipPipPip
  • 2722 posts

Posted 20 September 2008 - 09:23 AM

just learn environment mapped normal maps, then animate em, simply said.

thats how you do water like an old goon. like star stutter before he was old!

but a real goon sets up a grid of springs that only move up and down but pass
energy to each other then you just stick specular on the vertices!

then you get real ponds when things react apon it, and you dont need no
silluette super parralax mapping.

#12 starstutter

    Senior Member

  • Members
  • PipPipPipPip
  • 1039 posts

Posted 20 September 2008 - 02:35 PM

XVincentX said:

1)I do not understand yet...making the 3 matrix multiplication, should i have already got position in perspective position? Why have i to / pos.w?
I belive its because the X and Y coords output by the vertex shader are not divided by W yet, so they still have extremley high values. I think the W divide is done automaticly by the system. I could be wrong though. That's just a guess.

Quote

2) Can't i use saturate or clamp instead add 0.5? (Just to understand)
Saturate or clamp only restricts the values to 0-1, it doesn't move the coords. Doing this would cut off half the screen and give you a wierd "line" effect.

Anyway, really don't worry about why you need it. I didn't understand wht it did untill about a month after I started using it. I just knew that I needed it to work right. I think one mistake a lot of people make is they assume they need to understand everything about the method to use it properly. My experience has been that's a waste of time that just keeps you from your work. It's good to understand what they do, but that knowlege will just come to you as you continue working on it, and dwelling keeps you from moving on.

Quote

3)What a nice rendering! I would reach the same result!!!
Thanks! :)

Quote

4)What can you say me about water movement?
That's one I havent quite gotten yet. A while ago I implemented 2 techniques that I decided to use in parallel for level of detail.

One method was using an off-screen render target and drawing dynamic ripples on in the form of normal maps. Doing a little simple algebra it was possible to convert objects world-space positions into positions over the pool of water. From that I just used ripples like a particle system and emmited them from the body of the characters. The result was pretty damn cool.

It wasn't convincing though at steep angles, so up close I converted the water to a higher-tesselation mesh and then used a mass spring system. I also experimented with using texture reads in the vertex shader to animate, but this was not very cost effective as the tesselation had to be impractically high to get visually pleasing results. I admit though I never finished this implementation.

Quote

5)I would avoid the use of cubemap, anyway today i will try so write some other code, thank you again!
Well for things like small puddles you don't have much choice because realtime reflections would be totally impractical for those. One thing you should consider is using local reflections and cube maps.

You can use local reflections for moving objetcs and cube maps for the envrionment around them. The technique is pretty effective and cheap, it's currently being used by Mirrors-Edge I belive.
(\__/)
(='.'=)
This is Bunny. Copy and paste bunny into
(")_(") your signature to help him gain world domination.
bunny also wants to fight spam: Click Here Bots!

#13 Reedbeta

    DevMaster Staff

  • Administrators
  • 5307 posts
  • LocationBellevue, WA

Posted 20 September 2008 - 06:19 PM

starstutter said:

I belive its because the X and Y coords output by the vertex shader are not divided by W yet, so they still have extremley high values. I think the W divide is done automaticly by the system. I could be wrong though. That's just a guess.

If you use a projective texture function like tex2Dproj (TXP in assembly, I think) then it will do the divide by w for you. However, there's then a minor complication because you have to do the [-1, 1] to [0, 1] remapping. tex2Dproj does *not* do this remapping after it divides by w before looking up in the texture. So you have to tweak the coordinates slightly before you send them to tex2Dproj. It's not hard and can in fact be rolled into the projection matrix so it doesn't need a shader calculation at all.
reedbeta.com - developer blog, OpenGL demos, and other projects

#14 XVincentX

    Valued Member

  • Members
  • PipPipPip
  • 115 posts

Posted 21 September 2008 - 10:00 AM

Oh man, i'm very sorry but i can't understand all your sentences, even if i use a dictionary!! Sorry if i will repeat the same things, sometimes.

So, let's make a summary.

1)About the water movement, i found a shader code that mabye can work (i have not tested yet)
//---------------------------------------------
// Blending States
//---------------------------------------------
BlendState NoBlending
{
BlendEnable[0] = FALSE;
};

//---------------------------------------------
// Buffer Variables
//---------------------------------------------
Texture2D txDiffuse;
SamplerState samLinear
{
Filter = MIN_MAG_MIP_LINEAR;
AddressU = Wrap;
AddressV = Wrap;
};

// this lot are set in application
matrix World;
matrix ViewProjection;

float4 vLightDir;
float4 vLightColour;

float time_0_2PI; // cycle through 2PI using say step size of of 0.0025f every frame update
float rippleSpeed; // 20.0f is good
float distortion; // 0.0001f just a little

//----------------------------------------
struct VS_INPUT
{
float4 Pos : POSITION;
float3 Norm : NORMAL;
float2 Tex : TEXCOORD0;

};

struct PS_INPUT
{
float4 Pos : SV_POSITION; //system variable - homogeneous projection space
float3 Norm : TEXCOORD1;
float2 Tex : TEXCOORD0;

};

//--------------------------------------------
// Vertex Shader
//--------------------------------------------
PS_INPUT VS( VS_INPUT input )
{
PS_INPUT output = (PS_INPUT)0;

// compute distortion
input.Pos = input.Pos + distortion * sin(dot(input.Pos.xy, input.Pos.xy) + rippleSpeed * time_0_2PI) +
distortion * sin(dot(input.Pos.xz, input.Pos.xz) + rippleSpeed * time_0_2PI) +
distortion * sin(dot(input.Pos.yz, input.Pos.yz) + rippleSpeed * time_0_2PI);


output.Pos = mul( input.Pos, World );
output.Pos = mul( output.Pos, ViewProjection );

//Move the incoming normal into world space
output.Norm = mul( input.Norm, World );

output.Tex = input.Tex;
return output;
}


//--------------------------------------------
// Pixel Shader
//--------------------------------------------
float4 PS( PS_INPUT input ) : SV_Target
{

float4 finalColour = 0;

//do NdotL lighting
finalColour += saturate( dot( (float3)vLightDir,input.Norm) * vLightColour );

finalColour.a = 1;

// modulate against diffuse texture color
return (txDiffuse.Sample( samLinear, input.Tex )) * finalColour;

}


//----------------------------------------------
technique10 Render
{
pass P0
{
SetVertexShader( CompileShader( vs_4_0, VS() ) );
SetGeometryShader( NULL );
SetPixelShader( CompileShader( ps_4_0, PS() ) );
SetBlendState( NoBlending, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF );
}
}

Your solution seems good, but also expansive...or not?

2) I understand the texcoord question. Ok.

3) Leave the movement and continue on water effect.
Following the article, how can i make the light absorption?

#15 starstutter

    Senior Member

  • Members
  • PipPipPipPip
  • 1039 posts

Posted 21 September 2008 - 02:32 PM

Honestly I'm not real sure what that shader code is supposed to do... The only thing it's really doing is making waves in the water mesh, but it's not doing image distortion or anything.

Actually the methods really not expensive at all. It's just a few instructions more than regular lighting. The screenshots you saw (if I remember right) ran at about 240 fps on a Geforce 7900 GS. There's really nothing expensive about it.

Quote

Following the article, how can i make the light absorption?
What do you mean by absorbtion? Do you mean having the water be cloudy or dirty?

I'm going to assume that's it for a moment (but correct me if I'm wrong) but this involves a few more steps and it can get more expensive. For this, computing the fog effect is very simple. The code is literally:

occlusion = saturate(input.Pos2.z - sceneDepth) * 0.001;
color *= occlusion;

The complicated issue here is "sceneDepth". The only thing you need to know to calculate the fog is the amount of water between your eye and the surface your looking at. For this you need 2 pieces of info:

distance from eye to water (which is ->) input.Pos2.z
distance from eye to surface (which is ->) sceneDepth

To get the scene depth is a bit complicated though. What you need to do is draw the scene onto a render target in the format of D3DFMT_R32F. You're going to have to create a new shader as well. The vertex shader for this pass consists of just a normal world position tranformation, as in, just draw as you normally would, but forget about normals and texture coordinates. Also you need to include the Pos2 variable like with the water.

The pixel shader for it is one line:
color.x = input.Pos2.x;

Now once you've drawn this info onto the render target, use it as a texture in the water shader. The sceneDepth variable is filled by:

sceneDepth = txDiffuse.Sample( DepthTex, ViewTexC )

Now, keep in mind there is a feature that lets you acess depth information in the shader new to DirectX 10, but according to nVidia it disables early-z culling and that could cut your framerate in half.
(\__/)
(='.'=)
This is Bunny. Copy and paste bunny into
(")_(") your signature to help him gain world domination.
bunny also wants to fight spam: Click Here Bots!

#16 XVincentX

    Valued Member

  • Members
  • PipPipPip
  • 115 posts

Posted 21 September 2008 - 05:17 PM

Thank you again for your reply.
I'm really get confused by your ideas (that are very good) and the ShaderX article.

About the Z access in the Shader, the DepthStencil surface, in D3D10, it's managed as a Texture and, if it had god as bind option the D3D10_BIND_SHADER_RESOURCE it can be passed in a shader like a simple texture and manage for it.
So i may go on this way.

I have the completed "glass-effect" on my scene. Now, can you please make a todo-list, to proceed in the effect?

#17 starstutter

    Senior Member

  • Members
  • PipPipPipPip
  • 1039 posts

Posted 21 September 2008 - 07:54 PM

hmmm, well I would worry about basic distortion first.

1. get a normal map with the image of a wave (or ripple) pattern

2. use the texture coordinates from the mesh in the shader (the incoming UV's, not the screen projection. In other words, place the normal map on it just like any ordinary texture on any ordinary object. No special steps here.

3. modify the image (ViewTexC) coordinates so that the refraction in the water becomes wavy. Modify them (of course) becore you use them for the image lookup.

4. Animate the water. You do this by simply declaring a new float at the top and using it as a timer. Outside the shader you incriment it by 1, and then do the "SetFloat" function. In the shader, just modify the UV coordinates with this:
normal = tex2d(normalMap, input.uv + modify.xy);

this will give you a slow steady flow that will have you go "woah..." the first time you see it. :)
(\__/)
(='.'=)
This is Bunny. Copy and paste bunny into
(")_(") your signature to help him gain world domination.
bunny also wants to fight spam: Click Here Bots!

#18 XVincentX

    Valued Member

  • Members
  • PipPipPip
  • 115 posts

Posted 22 September 2008 - 11:15 AM

I tried your advices in your same order, giving this final shader code

float4x4	ViewMatrix;
float4x4	WorldMatrix;
float4x4	ProjMatrix;
float4		LightDirection;
float4		MaterialColor;
float3		EyePosition;
texture2D	Texture;
texture2D	CurrentBackbuffer;
texture2D	NormalMap;

SamplerState SamplText
{
    Filter = MIN_MAG_MIP_LINEAR;
    AddressU = Mirror;
    AddressV = Mirror;
};


struct VS_INPUT
{
	float4	Pos	:	POSITION;
	float3	Tex	:	TEXCOORD;
	float3	Nor	:	NORMAL;
};

struct PS_INPUT
{
	float4	Pos	:	SV_POSITION;
	float4	WorldPos:	WORLDPOSITION;
	float3	Tex	:	TEXCOORD;
	float3	Nor	:	NORMAL;
};

PS_INPUT vs_main(VS_INPUT Input)
{
	PS_INPUT Out = (PS_INPUT)0;
	Out.Pos = mul(mul(mul(Input.Pos,WorldMatrix),ViewMatrix),ProjMatrix);
	Out.WorldPos = mul(Input.Pos,WorldMatrix);
	Out.Tex = Input.Tex;
	Out.Nor = mul(Input.Nor,WorldMatrix);
	return Out;
}

PS_INPUT vs_plane(VS_INPUT input)
{
	PS_INPUT output = (PS_INPUT)0;

	output.Pos = mul(input.Pos,mul(mul(WorldMatrix,ViewMatrix),ProjMatrix));
	output.Nor = mul( input.Nor, WorldMatrix );
	output.Tex = input.Tex;
	output.WorldPos = output.Pos;

	return output;
}

float4 ps_plane(PS_INPUT input)	:	SV_TARGET
{
	float2 ViewTexC = 0.5 * input.WorldPos.xy / input.WorldPos.w + float2( 0.5, 0.5 );
	ViewTexC.y	=	1.0f - ViewTexC.y;
	return NormalMap.Sample(SamplText,input.Tex.xy + EyePosition.xy) * CurrentBackbuffer.Sample(SamplText,ViewTexC);

}

float4 ps_main(PS_INPUT In)	:	SV_TARGET
{
		return Texture.Sample(SamplText,In.Tex);
}


technique10 WaterEffect
{
	Pass PositionTextured
	{
        SetVertexShader( CompileShader( vs_4_0, vs_main() ) );
        SetGeometryShader(NULL);
        SetPixelShader( CompileShader( ps_4_0, ps_main() ) );
	}
	
	Pass WaterMovement
	{
        SetVertexShader( CompileShader( vs_4_0, vs_plane() ) );
        SetGeometryShader(NULL);
        SetPixelShader( CompileShader( ps_4_0, ps_plane() ) );
	}
}

And it works! Here is the result
Posted Image

It's not bad for basic water effect, even if the water looks like...so...dirty? Mabye it's a normal map problem?
Anyway, i would like, with your help, to go beyond and reach better results. The first issue i can see it's that not all surface it's watered...here is an example
Posted Image

So?
Thank you again

#19 starstutter

    Senior Member

  • Members
  • PipPipPipPip
  • 1039 posts

Posted 22 September 2008 - 07:41 PM

Quote

The first issue i can see it's that not all surface it's watered

Ummm, how much experience do you have in graphics programming? I think we need to get on the same page here.

Quote

It's not bad for basic water effect, even if the water looks like...so...dirty? Mabye it's a normal map problem?
Your outputting the normal map color, not the distorted image ;). So, as the question above suggests, do you know how to do normal mapping (tangent space normal mapping). If not, that's fine, there's other options, but stretching a normal map over a polygon is not normal mapping.
(\__/)
(='.'=)
This is Bunny. Copy and paste bunny into
(")_(") your signature to help him gain world domination.
bunny also wants to fight spam: Click Here Bots!

#20 XVincentX

    Valued Member

  • Members
  • PipPipPip
  • 115 posts

Posted 22 September 2008 - 08:18 PM

Quote

Ummm, how much experience do you have in graphics programming? I think we need to get on the same page here.

Not so much! I use Direct3D10 from less than a year, but i used D3D9 very years ago, so i forgot a lot of concepts. What about this, for example?

Quote

Your outputting the normal map color, not the distorted image . So, as the question above suggests, do you know how to do normal mapping (tangent space normal mapping). If not, that's fine, there's other options, but stretching a normal map over a polygon is not normal mapping.

Normal mapping...if i remember well, in normal mapping there was a particular multiplication with tangent, normal and binormal, even if, now, i do not remember why...i did it so time ago...
So, have we to stop for now?





1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users