Advertisement Jump to content
Sign in to follow this  

Screen space fluids

This topic is 776 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 guys,


I have been looking at the GDC paper about screen space fluids and I've been trying to imitate it.

As of now, I have been stuck for quite a while.

I am trying to create billboarding quads from a pointlist and make them look like spheres so I can write the depth of those spheres to the rendertarget.

However somewhere in the calculation of the depth, there is a mistake and I can't seem to figure it out.

In the paper, the eyePosition is calculated but I don't understand why. I don't understand why I can't just do the ViewProjection transformation in the pixelshader like you would in the vertexshader.

Is there someone experienced with this?

The full shader is below (HLSL)

float3 gLightDirection = float3(-0.577f, -0.577f, 0.577f);
float gScale = 1.0f;
float4x4 gViewProj : VIEWPROJ;
float4x4 gViewInv : VIEWINV;

struct VS_DATA
	float3 pos : POSITION;

struct GS_DATA
	float4 pos : SV_POSITION;
	float3 wPos : WORLDPOS;
	float2 texCoord: TEXCOORD0;

DepthStencilState DSS
	DepthEnable = TRUE;
	DepthWriteMask = ALL;

SamplerState samLinear
	AddressU = Wrap;
	AddressV = Wrap;

RasterizerState RS
	CullMode = BACK;

VS_DATA Main_VS(VS_DATA input)
	return input;

void CreateVertex(inout TriangleStream<GS_DATA> triStream, float3 pos, float3 offset, float2 texCoord)
	GS_DATA data = (GS_DATA)0;
	offset = mul(offset, (float3x3)gViewInv);
	float3 cornerPos = pos + offset;
	data.wPos = pos;
	data.pos = mul(float4(cornerPos, 1.0f), gViewProj);
	data.texCoord = texCoord;


void Main_GS(point VS_DATA vertex[1], inout TriangleStream<GS_DATA> triStream)
	float3 topLeft, topRight, bottomLeft, bottomRight;

	topLeft = float3(-gScale / 2.0f, gScale / 2.0f, 0.0f);
	topRight = float3(gScale / 2.0f, gScale / 2.0f, 0.0f);
	bottomLeft = float3(-gScale / 2.0f, -gScale / 2.0f, 0.0f);
	bottomRight = float3(gScale / 2.0f, -gScale / 2.0f, 0.0f);

	CreateVertex(triStream, vertex[0].pos, bottomLeft, float2(0, 1));
	CreateVertex(triStream, vertex[0].pos, topLeft, float2(0, 0));
	CreateVertex(triStream, vertex[0].pos, bottomRight, float2(1, 1));
	CreateVertex(triStream, vertex[0].pos, topRight, float2(1, 0));

float4 Main_PS(GS_DATA input) : SV_TARGET
	//Calculate the normal
	float3 normal;
	normal.xy = input.texCoord * 2.0f - 1.0f;
	float r2 = dot(normal.xy, normal.xy);
	//Clip if the pixel falls out the sphere
	clip(r2 > 1.0f ? -1 : 1);
	normal.z = sqrt(1.0f - r2);

	//calculate the depth
	float4 worldPos = float4(input.wPos + normalize(normal) * gScale, 1.0f);
	float4 clipPos = mul(worldPos, gViewProj);
	float d = clipPos.z / clipPos.w;
	return float4(d, 0, 0, 1);

technique11 Default
	pass P0
		SetDepthStencilState(DSS, 0);

		SetVertexShader(CompileShader(vs_4_0, Main_VS()));
		SetGeometryShader(CompileShader(gs_4_0, Main_GS()));
		SetPixelShader(CompileShader(ps_4_0, Main_PS()));

Thanks in advance!

Share this post

Link to post
Share on other sites

so it seems that they do it in diffrent space, eye position can be either in lightspace, worldspace, or whatever else, seems like they use camera space, and eye pos 'could' be always in straight line onto z_near.


but lets consider wolrdspace example:



we have a set of vertices they are somewhere you have view matrix and projection matrix (world matrix stays identity)


so you end up only with view*projection matrix lets name it mvp


so each time you multiply mvp * vertex; you will get some sort of -1..1 garbage


you need to bias it (only z in your case)


    //calculate the depth not to mention the hell is this: normal.xy = input.texCoord * 2.0f - 1.0f;
    float4 worldPos = float4(input.wPos + normalize(normal) * gScale, 1.0f); //you could transform screen pos here to world position of the vertex (since i started with worldspace case, and in code you have screen space i dont see any sense now [see PS1]
    float4 clipPos = mul(worldPos, gViewProj); //dont know hlsl so i wont say if thats in the correct order.
    float d = clipPos.z / clipPos.w; //this bias is good as far as other two are good


and here i see a bug     float4 worldPos = float4(input.wPos + normalize(normal) * gScale, 1.0f); looks weird



if you are defining billboard positions in screen space (in pixels) then in vs you should place your depth) and draw reddish depth in ps


consider this


whenver Vpos is a pixel on screen and sw=screen width, sh=screen height then

float x = -1.0 + (Vpos.x / sw) * 2.0;
float y = -1.0 + (Vpos.y / sh) * 2.0;
gl_Position = vec4(vec2(x,y), 0.0, 1.0);
third value should be your depth, and you dont even have to use any matrix math, you define your own depth here.
sorry if i didnt help :P im just bored waiting for answers in my thread

Share this post

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

  • Advertisement

Important Information

By using, you agree to our community Guidelines, Terms of Use, and Privacy Policy. is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!