summaryrefslogtreecommitdiff
path: root/materialsystem/stdshaders/ParticleSphere.vsh
blob: b2d83849c83081e46d5f586b744436c6e47bcf94 (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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
vs.1.1

# DYNAMIC: "DOWATERFOG"				"0..1"

#include "macros.vsh"

$cQuarter = "c91.x";

;------------------------------------------------------------------------------
; Constants specified by the app
;    c0      = (0, 1, 2, 0.5)
;	 c1		 = (1/2.2, 0, 0, 0)
;    2      = camera position *in world space*
;    c4-c7   = modelViewProj matrix	(transpose)
;    c8-c11  = ViewProj matrix (transpose)
;    c12-c15 = model->world matrix (transpose)
;	 c16	 = [fogStart, fogEnd, fogRange, undefined]
;	 c17-c20 = model->view matrix (transpose)
;
; The ParticleSphere lighting equation is:
; A + [N dot ||L - P||] * C * r / |L - P|^2
;
; where:
; A = ambient light color
; N = particle normal (stored in the texture)
; L = directional light position
; P = point on surface
; C = directional light color
; r = directional light intensity
;
; This shader just does the |L - P| part and the pixel shader does the rest.
;
; Vertex components
;   $vPos		= Position
;	$vSpecular		= Directional light color
;	$vColor		= Ambient color (and alpha)
;	$vTexCoord0		= Texture coordinates for normal map
;	$vTexCoord0.z	= Index into the light list for light info



;------------------------------------------------------------------------------
; Constant registers
;------------------------------------------------------------------------------

;------------------------------------------------------------------------------
; Vertex blending
;------------------------------------------------------------------------------

&AllocateRegister( \$projPos );

; Transform position from object to projection space
dp4 $projPos.x, $vPos, $cModelViewProj0
dp4 $projPos.y, $vPos, $cModelViewProj1
dp4 $projPos.z, $vPos, $cModelViewProj2
dp4 $projPos.w, $vPos, $cModelViewProj3

mov oPos, $projPos

;------------------------------------------------------------------------------
; Fog
;------------------------------------------------------------------------------

alloc $worldPos
if( $DOWATERFOG == 1 )
{
	; Get the worldpos z component only since that's all we need for height fog
	dp4 $worldPos.z, $vPos, $cModel2
}
&CalcFog( $worldPos, $projPos );
free $worldPos

&FreeRegister( \$projPos );

;------------------------------------------------------------------------------
; Setup to index our directional light.
;------------------------------------------------------------------------------
mov		a0.x, $vTexCoord0.z


;------------------------------------------------------------------------------
; Copy texcoords for the normal map texture
;------------------------------------------------------------------------------

mov		oT0, $vTexCoord0
mov		oT2.xyz, $vColor

; FIXME : the rest of this needs to use AllocateRegister

;------------------------------------------------------------------------------
; Generate a tangent space and rotate L.
; This can be thought of as rotating the normal map to face the viewer.
;
; This is useful when a particle is way off to the side of the screen.
; You should be looking at the half-sphere with a normal pointing from the
; particle to the viewer. Instead, you're looking at the half-sphere with
; a normal along Z. This tangent space builder code fixes the problem.
;
; Note that since the model and view matrices are identity, the coordinate
; system has X=right, Y=up, and Z=behind you  (negative Z goes into the screen).
;------------------------------------------------------------------------------
								; r5 (forward) = normalized P
dp3		r1, $vPos, $vPos
rsq		r5, r1
mul		r5, r5, $vPos
mov		r5.z, -r5.z				; This basis wants Z positive going into the screen
								; so flip it here.

								; r1 (up) = r5 x c24
mul		r1, r5.xzyw, $SHADER_SPECIFIC_CONST_0; (This effectively does a cross product with [1,0,0,0]
								; You wind up with [0, r5.z, -r5.y, 1]
dp3		r2, r1, r1
rsq		r2, r2
mul		r1, r1, r2

								; r2 (right) = r1 x r5
mul		r2,  r1.yzxw, r5.zxyw	
mad		r2, -r1.zxyw, r5.yzxw, r2

sub		r3, c[45 + a0.x], $vPos    ; r3 = L - P

; transposed matrix mul
mul		r0, r2, r3.xxxx			;   x * right
mad		r0, r1, r3.yyyy, r0		; + y * up
mad		r0, r5, r3.zzzz, r0		; + z * forward


;------------------------------------------------------------------------------
; Put ||L - P|| into t1
;------------------------------------------------------------------------------
dp3		r2, r0, r0			; r2 = Length(L - P)^2
rsq		r3, r2				; r3 = 1 / Length(L - P)
mul		r8, r0, r3			; r8 = Normalize(L - P)
mul		r9, r8, $cQuarter		; r9 = Normalize(L - P) * 0.25
add		oT1, r9, c0.w		; oT1 = Normalize(L - P) * 0.25 + 0.5


;------------------------------------------------------------------------------
; Setup the diffuse light color (C * r / ||L - P||^2)
;------------------------------------------------------------------------------

mul		r8, c[46 + a0.x], $vSpecular	; r8 = C * r
rcp		r7, r2					; r7 = 1 / Length(L - P)^2

; rescale the color if necessary
mul		r8,  r8, r7				; r8 = C * r / Length(L - P)^2

; We're doing both parts of an if statement here, with each part scaled by 0 or 1.
mul		r9,  r7, c[46 + a0.x]	; r9 = r / Length(L - P)^2

; If the light intensity scales the color > 1
	sge		r10, r9.xxxx, $cOne	; r10.x = 1 if the color's max component > 1
	rcp		r6,  r9.xxxx			
	mul		r6,  r6, r10.xxxx		; r6 = 1 / max_component or [0,0,0,0] if max_component < 1
	mul		r2,  r8, r6				; rescaled color (all zeros if no component was > 1)
; else
	slt		r11, r9.xxxx, $cOne	; r11.x = 1 if the color's max component < 1
	mad		oD0.xyz, r8, r11, r2	; if it was rescaled, then r8*r11 = 0
									; if not, then r8*r11 = the original color

mov		oD0.a, $vColor.a				; Pass in vertex alpha so the pixel shader can use it.