aboutsummaryrefslogtreecommitdiff
path: root/demo/d3d/shaders/ellipsoidDepthVS.hlsl
blob: f26317ecd9fa76ad2219c89fb36572bd4a053b0b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#include "shaderCommon.h"

cbuffer constBuf : register(b0)
{
	FluidShaderConst gParams;
};

// returns 1.0 for x==0.0 (unlike glsl)
float Sign(float x) { return x < 0.0 ? -1.0 : 1.0; }

bool solveQuadratic(float a, float b, float c, out float minT, out float maxT)
{
#if 0
	// for debugging
	minT = -0.5;
	maxT = 0.5;
	return true;
#else
	//minT = 0.0f;
	//maxT = 0.0f;
#endif

	if (a == 0.0 && b == 0.0)
	{
		minT = maxT = 0.0;
		return false;
	}

	float discriminant = b*b - 4.0*a*c;

	if (discriminant < 0.0)
	{
		return false;
	}

	float t = -0.5*(b + Sign(b)*sqrt(discriminant));
	minT = t / a;
	maxT = c / t;

	if (minT > maxT)
	{
		float tmp = minT;
		minT = maxT;
		maxT = tmp;
	}

	return true;
}

float DotInvW(float4 a, float4 b) { return a.x*b.x + a.y*b.y + a.z*b.z - a.w*b.w; }

FluidVertexOut ellipsoidDepthVS(FluidVertexIn input, uint instance : SV_VertexID)
{
	const float4 q1 = input.q1;
	const float4 q2 = input.q2;
	const float4 q3 = input.q3;

	const float4x4 modelViewProjectionMatrix = gParams.modelViewProjection;
	const float4x4 modelViewMatrixInverse = gParams.inverseModelView;

	float3 worldPos = input.position.xyz;
	
	// construct quadric matrix
	float4x4 q;
	q._m00_m10_m20_m30 = float4(q1.xyz*q1.w, 0.0);
	q._m01_m11_m21_m31 = float4(q2.xyz*q2.w, 0.0);
	q._m02_m12_m22_m32 = float4(q3.xyz*q3.w, 0.0);
	q._m03_m13_m23_m33 = float4(worldPos, 1.0);

	// transforms a normal to parameter space (inverse transpose of (q*modelview)^-T)
	float4x4 invClip = mul(modelViewProjectionMatrix, q);

	// solve for the right hand bounds in homogenous clip space
	float a1 = DotInvW(invClip[3], invClip[3]);
	float b1 = -2.0f*DotInvW(invClip[0], invClip[3]);
	float c1 = DotInvW(invClip[0], invClip[0]);

	float xmin;
	float xmax;
	solveQuadratic(a1, b1, c1, xmin, xmax);

	// solve for the right hand bounds in homogenous clip space
	float a2 = DotInvW(invClip[3], invClip[3]);
	float b2 = -2.0f*DotInvW(invClip[1], invClip[3]);
	float c2 = DotInvW(invClip[1], invClip[1]);

	float ymin;
	float ymax;
	solveQuadratic(a2, b2, c2, ymin, ymax);

	FluidVertexOut output;
	output.position = float4(worldPos.xyz, 1.0);
	output.bounds = float4(xmin, xmax, ymin, ymax);

	// construct inverse quadric matrix (used for ray-casting in parameter space)
	float4x4 invq;
	invq._m00_m10_m20_m30 = float4(q1.xyz / q1.w, 0.0);
	invq._m01_m11_m21_m31 = float4(q2.xyz / q2.w, 0.0);
	invq._m02_m12_m22_m32 = float4(q3.xyz / q3.w, 0.0);
	invq._m03_m13_m23_m33 = float4(0.0, 0.0, 0.0, 1.0);

	invq = transpose(invq);
	invq._m03_m13_m23_m33 = -(mul(invq, output.position));

	// transform a point from view space to parameter space
	invq = mul(invq, modelViewMatrixInverse);

	// pass down
	output.invQ0 = invq._m00_m10_m20_m30;
	output.invQ1 = invq._m01_m11_m21_m31;
	output.invQ2 = invq._m02_m12_m22_m32;
	output.invQ3 = invq._m03_m13_m23_m33;
	
	// compute ndc pos for frustrum culling in GS
	float4 projPos = mul(modelViewProjectionMatrix, float4(worldPos.xyz, 1.0));
	output.ndcPos = projPos / projPos.w;
	return output;
}