Sign in to follow this  
simco50

Screen space fluids

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
{
	Filter = MIN_MAG_MIP_LINEAR;
	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;

	triStream.Append(data);
}

[maxvertexcount(4)]
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
	{
		SetRasterizerState(RS);
		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

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this