/
SpaceTransforms.hlsl
347 lines (293 loc) · 11.1 KB
/
SpaceTransforms.hlsl
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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
#ifndef UNITY_SPACE_TRANSFORMS_INCLUDED
#define UNITY_SPACE_TRANSFORMS_INCLUDED
#if SHADER_API_MOBILE || SHADER_API_GLES3 || SHADER_API_SWITCH || defined(UNITY_UNIFIED_SHADER_PRECISION_MODEL)
#pragma warning (disable : 3205) // conversion of larger type to smaller
#endif
// Caution: For HDRP, adding a function in this file requires adding the appropriate #define in PickingSpaceTransforms.hlsl
// Return the PreTranslated ObjectToWorld Matrix (i.e matrix with _WorldSpaceCameraPos apply to it if we use camera relative rendering)
float4x4 GetObjectToWorldMatrix()
{
return UNITY_MATRIX_M;
}
float4x4 GetWorldToObjectMatrix()
{
return UNITY_MATRIX_I_M;
}
float4x4 GetPrevObjectToWorldMatrix()
{
return UNITY_PREV_MATRIX_M;
}
float4x4 GetPrevWorldToObjectMatrix()
{
return UNITY_PREV_MATRIX_I_M;
}
float4x4 GetWorldToViewMatrix()
{
return UNITY_MATRIX_V;
}
float4x4 GetViewToWorldMatrix()
{
return UNITY_MATRIX_I_V;
}
// Transform to homogenous clip space
float4x4 GetWorldToHClipMatrix()
{
return UNITY_MATRIX_VP;
}
// Transform to homogenous clip space
float4x4 GetViewToHClipMatrix()
{
return UNITY_MATRIX_P;
}
// This function always return the absolute position in WS
float3 GetAbsolutePositionWS(float3 positionRWS)
{
#if (SHADEROPTIONS_CAMERA_RELATIVE_RENDERING != 0)
positionRWS += _WorldSpaceCameraPos.xyz;
#endif
return positionRWS;
}
// This function return the camera relative position in WS
float3 GetCameraRelativePositionWS(float3 positionWS)
{
#if (SHADEROPTIONS_CAMERA_RELATIVE_RENDERING != 0)
positionWS -= _WorldSpaceCameraPos.xyz;
#endif
return positionWS;
}
real GetOddNegativeScale()
{
// FIXME: We should be able to just return unity_WorldTransformParams.w, but it is not
// properly set at the moment, when doing ray-tracing; once this has been fixed in cpp,
// we can revert back to the former implementation.
return unity_WorldTransformParams.w >= 0.0 ? 1.0 : -1.0;
}
float3 TransformObjectToWorld(float3 positionOS)
{
#if defined(SHADER_STAGE_RAY_TRACING)
return mul(ObjectToWorld3x4(), float4(positionOS, 1.0)).xyz;
#else
return mul(GetObjectToWorldMatrix(), float4(positionOS, 1.0)).xyz;
#endif
}
float3 TransformWorldToObject(float3 positionWS)
{
#if defined(SHADER_STAGE_RAY_TRACING)
return mul(WorldToObject3x4(), float4(positionWS, 1.0)).xyz;
#else
return mul(GetWorldToObjectMatrix(), float4(positionWS, 1.0)).xyz;
#endif
}
float3 TransformWorldToView(float3 positionWS)
{
return mul(GetWorldToViewMatrix(), float4(positionWS, 1.0)).xyz;
}
float3 TransformViewToWorld(float3 positionVS)
{
return mul(GetViewToWorldMatrix(), float4(positionVS, 1.0)).xyz;
}
// Transforms position from object space to homogenous space
float4 TransformObjectToHClip(float3 positionOS)
{
// More efficient than computing M*VP matrix product
return mul(GetWorldToHClipMatrix(), mul(GetObjectToWorldMatrix(), float4(positionOS, 1.0)));
}
// Transforms position from world space to homogenous space
float4 TransformWorldToHClip(float3 positionWS)
{
return mul(GetWorldToHClipMatrix(), float4(positionWS, 1.0));
}
// Transforms position from view space to homogenous space
float4 TransformWViewToHClip(float3 positionVS)
{
return mul(GetViewToHClipMatrix(), float4(positionVS, 1.0));
}
// Normalize to support uniform scaling
float3 TransformObjectToWorldDir(float3 dirOS, bool doNormalize = true)
{
#ifndef SHADER_STAGE_RAY_TRACING
float3 dirWS = mul((float3x3)GetObjectToWorldMatrix(), dirOS);
#else
float3 dirWS = mul((float3x3)ObjectToWorld3x4(), dirOS);
#endif
if (doNormalize)
return SafeNormalize(dirWS);
return dirWS;
}
// Normalize to support uniform scaling
float3 TransformWorldToObjectDir(float3 dirWS, bool doNormalize = true)
{
#ifndef SHADER_STAGE_RAY_TRACING
float3 dirOS = mul((float3x3)GetWorldToObjectMatrix(), dirWS);
#else
float3 dirOS = mul((float3x3)WorldToObject3x4(), dirWS);
#endif
if (doNormalize)
return normalize(dirOS);
return dirOS;
}
// Transforms vector from world space to view space
real3 TransformWorldToViewDir(real3 dirWS, bool doNormalize = false)
{
float3 dirVS = mul((real3x3)GetWorldToViewMatrix(), dirWS).xyz;
if (doNormalize)
return normalize(dirVS);
return dirVS;
}
// Transforms vector from view space to world space
real3 TransformViewToWorldDir(real3 dirVS, bool doNormalize = false)
{
float3 dirWS = mul((real3x3)GetViewToWorldMatrix(), dirVS).xyz;
if (doNormalize)
return normalize(dirWS);
return dirWS;
}
// Transforms normal from world space to view space
real3 TransformWorldToViewNormal(real3 normalWS, bool doNormalize = false)
{
// assuming view matrix is uniformly scaled, we can use direction transform
return TransformWorldToViewDir(normalWS, doNormalize);
}
// Transforms normal from view space to world space
real3 TransformViewToWorldNormal(real3 normalVS, bool doNormalize = false)
{
// assuming view matrix is uniformly scaled, we can use direction transform
return TransformViewToWorldDir(normalVS, doNormalize);
}
// Transforms vector from world space to homogenous space
real3 TransformWorldToHClipDir(real3 directionWS, bool doNormalize = false)
{
float3 dirHCS = mul((real3x3)GetWorldToHClipMatrix(), directionWS).xyz;
if (doNormalize)
return normalize(dirHCS);
return dirHCS;
}
// Transforms normal from object to world space
float3 TransformObjectToWorldNormal(float3 normalOS, bool doNormalize = true)
{
#ifdef UNITY_ASSUME_UNIFORM_SCALING
return TransformObjectToWorldDir(normalOS, doNormalize);
#else
// Normal need to be multiply by inverse transpose
float3 normalWS = mul(normalOS, (float3x3)GetWorldToObjectMatrix());
if (doNormalize)
return SafeNormalize(normalWS);
return normalWS;
#endif
}
// Transforms normal from world to object space
float3 TransformWorldToObjectNormal(float3 normalWS, bool doNormalize = true)
{
#ifdef UNITY_ASSUME_UNIFORM_SCALING
return TransformWorldToObjectDir(normalWS, doNormalize);
#else
// Normal need to be multiply by inverse transpose
float3 normalOS = mul(normalWS, (float3x3)GetObjectToWorldMatrix());
if (doNormalize)
return SafeNormalize(normalOS);
return normalOS;
#endif
}
real3x3 CreateTangentToWorld(real3 normal, real3 tangent, real flipSign)
{
// For odd-negative scale transforms we need to flip the sign
real sgn = flipSign * GetOddNegativeScale();
real3 bitangent = cross(normal, tangent) * sgn;
return real3x3(tangent, bitangent, normal);
}
// this function is intended to work on Normals (handles non-uniform scale)
// tangentToWorld is the matrix representing the transformation of a normal from tangent to world space
real3 TransformTangentToWorld(float3 normalTS, real3x3 tangentToWorld, bool doNormalize = false)
{
// Note matrix is in row major convention with left multiplication as it is build on the fly
real3 result = mul(normalTS, tangentToWorld);
if (doNormalize)
return SafeNormalize(result);
return result;
}
// this function is intended to work on Normals (handles non-uniform scale)
// This function does the exact inverse of TransformTangentToWorld() and is
// also decribed within comments in mikktspace.h and it follows implicitly
// from the scalar triple product (google it).
// tangentToWorld is the matrix representing the transformation of a normal from tangent to world space
real3 TransformWorldToTangent(real3 normalWS, real3x3 tangentToWorld, bool doNormalize = true)
{
// Note matrix is in row major convention with left multiplication as it is build on the fly
float3 row0 = tangentToWorld[0];
float3 row1 = tangentToWorld[1];
float3 row2 = tangentToWorld[2];
// these are the columns of the inverse matrix but scaled by the determinant
float3 col0 = cross(row1, row2);
float3 col1 = cross(row2, row0);
float3 col2 = cross(row0, row1);
float determinant = dot(row0, col0);
// inverse transposed but scaled by determinant
// Will remove transpose part by using matrix as the first arg in the mul() below
// this makes it the exact inverse of what TransformTangentToWorld() does.
real3x3 matTBN_I_T = real3x3(col0, col1, col2);
real3 result = mul(matTBN_I_T, normalWS);
if (doNormalize)
{
float sgn = determinant < 0.0 ? (-1.0) : 1.0;
return SafeNormalize(sgn * result);
}
else
return result / determinant;
}
// this function is intended to work on Vectors/Directions
// tangentToWorld is the matrix representing the transformation of a normal from tangent to world space
real3 TransformWorldToTangentDir(real3 dirWS, real3x3 tangentToWorld, bool doNormalize = false)
{
// Note matrix is in row major convention with left multiplication as it is build on the fly
real3 result = mul(tangentToWorld, dirWS);
if (doNormalize)
return SafeNormalize(result);
return result;
}
// this function is intended to work on Vectors/Directions
// This function does the exact inverse of TransformWorldToTangentDir()
// tangentToWorld is the matrix representing the transformation of a normal from tangent to world space
real3 TransformTangentToWorldDir(real3 dirWS, real3x3 tangentToWorld, bool doNormalize = false)
{
// Note matrix is in row major convention with left multiplication as it is build on the fly
float3 row0 = tangentToWorld[0];
float3 row1 = tangentToWorld[1];
float3 row2 = tangentToWorld[2];
// these are the columns of the inverse matrix but scaled by the determinant
float3 col0 = cross(row1, row2);
float3 col1 = cross(row2, row0);
float3 col2 = cross(row0, row1);
float determinant = dot(row0, col0);
// inverse transposed but scaled by determinant
// Will remove transpose part by using matrix as the second arg in the mul() below
// this makes it the exact inverse of what TransformWorldToTangentDir() does.
real3x3 matTBN_I_T = real3x3(col0, col1, col2);
real3 result = mul(dirWS, matTBN_I_T);
if (doNormalize)
{
float sgn = determinant < 0.0 ? (-1.0) : 1.0;
return SafeNormalize(sgn * result);
}
else
return result / determinant;
}
// tangentToWorld is the matrix representing the transformation of a normal from tangent to world space
real3 TransformTangentToObject(real3 dirTS, real3x3 tangentToWorld)
{
// Note matrix is in row major convention with left multiplication as it is build on the fly
real3 normalWS = TransformTangentToWorld(dirTS, tangentToWorld);
return TransformWorldToObjectNormal(normalWS);
}
// tangentToWorld is the matrix representing the transformation of a normal from tangent to world space
real3 TransformObjectToTangent(real3 dirOS, real3x3 tangentToWorld)
{
// Note matrix is in row major convention with left multiplication as it is build on the fly
// don't normalize, as normalWS will be normalized after TransformWorldToTangent
float3 normalWS = TransformObjectToWorldNormal(dirOS, false);
// transform from world to tangent
return TransformWorldToTangent(normalWS, tangentToWorld);
}
#if SHADER_API_MOBILE || SHADER_API_GLES3 || SHADER_API_SWITCH
#pragma warning (enable : 3205) // conversion of larger type to smaller
#endif
#endif