forked from microsoft/MixedRealityToolkit-Unity
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathLuminousUnity.shader
556 lines (455 loc) · 18.2 KB
/
LuminousUnity.shader
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
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.
// Unity port of HoloFX Shell shader
//
// v0.1 Mathew Lamb
// based upon work by Doug Service
//
// This shader implements the surface properties of the Prototype Shader, implemented in
// the Fulcrum render engine. It does so shackled by Unity's lighting engine which limits the
// number and type of lights used in a render pass.
//
// It is a two pass shader, the first pass computes the major Directional light and all additive
// sources (emission, reflection etc), the second pass captures the first 4 spot lights.
//
// All computation based upon lighting is code-identical to the HLSL equivalent.
//
// To Do:
// - implement lights as parameters to the shader and wrap filling in the relevant values with a script
// run from within Unity
Shader "Custom/MayaHLSL4" {
Properties {
_fDiffuseIntensity("Diffuse Intensity", Float) = 1
_cAlbedo("Albedo Color", Color) = (0.0,0.0,0.0)
_txAlbedo("Albedo Texture (RGB Texture)", 2D) = "white" {}
_bEnableHalfLambert("Half Lambert Toggle",Range(0,1)) = 0
_fHalfLambertExp("Half Lambert Exponent", Float) = 1
_cSpecular("Specular Color", Color) = (0.0,0.0,0.0)
_txSpecular("Specular Texture (RGB Texture)", 2D) = "white" {}
_fSpecularPower("Specular Power", Float) = 1
_bEnableFresnel("Fresnel Toggle",Range(0,1)) = 0
_bEnableAlphaFresnel("Alpha Fresnel Toggle",Range(0,1)) = 0
_fFresnelExp("Fresnel Exponent", Float) = 1
_fFresnelMin("Fresnel Minimum", Float) = 1
_cReflection("Reflection Color", Color) = (0.0,0.0,0.0)
_txReflection("Reflection Texture (RGB Cubemap)", Cube) = "white" {}
_cEmission("Emission Color", Color) = (0.0,0.0,0.0)
_txEmission("Emission Texture (RGB Texture)", 2D) = "white" {}
_cAmbient("Ambient Color", Color) = (0.0,0.0,0.0)
_txAmbient("Ambient Texture (RGB Cubemap)", Cube) = "white" {}
_fAlphaScale("Alpha Scale", Float) = 1
_txAlpha("Alpha Texture (RGB Texture)", 2D) = "white" {}
_txOcclusion("Occlusion Texture (RGB Texture)", 2D) = "white" {}
_txNormal("Normal Texture (RGB Texture)", 2D) = "white" { TexGen CubeNormal }
}
SubShader {
Tags {
"Queue" = "Transparent"
"RenderType" = "Transparent"
}
// 1 directional light and 4 point lights go with this pass
// total Unity nastiness
// all reflective and emissive terms are here as this pass is only evaluated once
Pass {
Tags {
"LightMode" = "ForwardBase"
}
Cull Back
Lighting On
ZWrite On
ZTest LEqual
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma only_renderers d3d11
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdbase
#pragma target 5.0
#include "UnityCG.cginc"
#include "AutoLight.cginc"
uniform float4 _LightColor0; // color of light source - from Lighting.cginc
uniform float3 _cEmission;
uniform float3 _cAmbient;
uniform float3 _cAlbedo;
uniform float3 _cSpecular;
uniform float3 _cReflection;
uniform float _fDiffuseIntensity;
uniform float _fSpecularPower;
uniform float _fHalfLambertExp;
uniform float _fFresnelMin;
uniform float _fFresnelExp;
uniform float _fAlphaScale;
uniform bool _bEnableFresnel;
uniform bool _bEnableAlphaFresnel;
uniform bool _bEnableHalfLambert;
uniform sampler2D _txEmission;
uniform samplerCUBE _txAmbient;
uniform sampler2D _txOcclusion;
uniform sampler2D _txAlbedo;
uniform sampler2D _txNormal;
uniform sampler2D _txSpecular;
uniform samplerCUBE _txReflection;
uniform sampler2D _txAlpha;
struct VsIn {
float4 vPosition : POSITION;
float4 vTangent : TANGENT;
float3 vNormal : NORMAL;
float4 vTexCoord0 : TEXCOORD0;
};
struct Vs2Ps {
float4 vPosition : SV_POSITION;
float3 vWorldPosition : TEXCOORD0;
float3 vToEye : TEXCOORD1;
float3 vWorldNormal : TEXCOORD2;
float3 vWorldTangent : TEXCOORD3;
float3 vWorldBitangent : TEXCOORD4;
float2 vTexCoord0 : TEXCOORD5;
};
Vs2Ps vert(in VsIn vsIn)
{
Vs2Ps vsOut;
// vertex from model space to view space and world space
// normally a geometry shader would come next, in which case we would only go to world space
vsOut.vPosition = UnityObjectToClipPos(vsIn.vPosition);
vsOut.vWorldPosition = mul(unity_ObjectToWorld,vsIn.vPosition).xyz;
vsOut.vToEye = normalize(WorldSpaceViewDir(vsIn.vPosition));
// tangent space basis vector from model space to view space
// normally a geometry shader would come next, in which case we would only go to world space
vsOut.vWorldNormal = normalize(mul((float3x3)unity_ObjectToWorld,vsIn.vNormal));
vsOut.vWorldTangent = normalize(mul((float3x3)unity_ObjectToWorld,vsIn.vTangent));
float3 BiTangent = cross(vsIn.vNormal,vsIn.vTangent.xyz) * vsIn.vTangent.w;
vsOut.vWorldBitangent = normalize(mul((float3x3)unity_ObjectToWorld,BiTangent));
// pass through the texture coordinates
vsOut.vTexCoord0 = vsIn.vTexCoord0;
return vsOut;
}
//
// wrap-around lambertian
//
float HalfLambert(float nDotL)
{
return saturate((nDotL + _fHalfLambertExp) / ((1 + _fHalfLambertExp) * (1 + _fHalfLambertExp)));
}
//
// this class is the per-light computation of the illuminance
//
class Material
{
// Material properties used in lighting calculation.
float fFresnelMin;
float fFresnelExp;
float fSpecPower;
float3 cSpecular;
float3 cAlbedo;
float3 cOcclusion;
float3 cResult;
void Illuminate(
in float3 nVertex, // Iterated world space vertex normal
in float3 nLight, // World space surface normal for lighting
in float3 vToLight, // Direction to light.
in float3 vToEye, // Direction to the eye.
in float3 cIrradiance // Light irradiance.
)
{
//
// this next piece of code is the fulcrum illuminance loop
//
float nDotL = dot(nLight,vToLight); // normal due to the normal map
float nDotLVert = dot(nVertex,vToLight); // interpolated vertex normal
// calculate the reflection vector from the light
float3 vReflect = 2.0f * nDotL * nLight - vToLight;
// Calculate the diffuse intensity and clamp lighting
// on backside normal map normals.
float fBackClamp = 1.0;
float fIDiffuse = 0.0;
if (_bEnableHalfLambert)
{
fBackClamp = HalfLambert(nDotLVert);
fIDiffuse = _fDiffuseIntensity * fBackClamp;
}
else
{
fBackClamp = step(0, nDotLVert);
fIDiffuse = fBackClamp * _fDiffuseIntensity * saturate(nDotL);
}
// Calculate the Fresnel term for the light.
float2 vCoeff = float2(1, 1);
if (_bEnableFresnel)
{
float fReflect = _fFresnelMin + (1.0 - _fFresnelMin) * pow(1.0 - fIDiffuse, _fFresnelExp);
vCoeff = float2(1 - fReflect, fReflect);
}
// Calculate the specular intensity.
float fISpecular = fBackClamp* pow(saturate(dot(vReflect, vToEye)), _fSpecularPower);
//
// bring the two color computations together
//
cResult = cOcclusion * cIrradiance * (vCoeff.x * fIDiffuse * cAlbedo + vCoeff.y * fISpecular * cSpecular);
}
};
float4 frag(in Vs2Ps psIn) : SV_TARGET
{
float gamma = 1.0;
//
// the following code is more-or-less lifted straight from the fulcrum shader
// cubemap implementation differs
//
// read emissive, ambient, diffuse and specular maps
// correct gamma to linear
float3 ctEmission = pow(tex2D(_txEmission, psIn.vTexCoord0).rgb, gamma);
float3 ctOcclusion = pow(tex2D(_txOcclusion, psIn.vTexCoord0).rgb, gamma);
float3 ctAlbedo = pow(tex2D(_txAlbedo, psIn.vTexCoord0).rgb, gamma);
float3 ctSpecular = pow(tex2D(_txSpecular, psIn.vTexCoord0).rgb, gamma);
// read normal map and Eye, Normal, Tangent and Bitangent vectors
// from the vertex shader data structure
float3 vtNormal = tex2D(_txNormal, psIn.vTexCoord0).rgb;
float3 vToEye = normalize(psIn.vToEye);
float3 nVertex = normalize(psIn.vWorldNormal);
float3 nTangent = normalize(psIn.vWorldTangent);
float3 nBitangent = normalize(psIn.vWorldBitangent);
// convert the normal map from normalized range [0,1] to [-1,1]
vtNormal.xyz = 2 * vtNormal - 1;
// build the tangent space to world space transform and transform
// the normal map normal from tangent space to world space
float3x3 mTangentToWorld = { nTangent, nBitangent, nVertex };
float3 nLight = mul(vtNormal, mTangentToWorld);
nLight = normalize(nLight);
// get the ambient illumination along the normal
float3 ctAmbient = pow(texCUBE(_txAmbient, nLight).rgb, gamma);
// calculate the eye reflection vector and get reflection map color
float3 vEyeReflect = 2.0f * dot(nLight,vToEye) * nLight - vToEye;
float3 ctReflection = pow(texCUBE(_txReflection,vEyeReflect).rgb, gamma);
// add the emissive and ambient irradiance colorized by albedo
float3 cOut = _cEmission * ctEmission + _cAmbient * ctAmbient * ctOcclusion * _cAlbedo * ctAlbedo;
// at this point in the fulcrum shader the illuminance loop is called
// due to the idiosyncrasies of Unity at this point we sample the one light that is known to be calling
// this shader - a single directional light
// additional (spot) lights are computed in the next pass
// in this pass we compute the light due to the directional and all non-light related quantities
// work with the directional light (if it exists) - compute its direction and attenuation
float3 L;
float atten;
if (0.0 == _WorldSpaceLightPos0.w) // directional light
{
atten = 1.0;
L = normalize(float3(_WorldSpaceLightPos0.xyz));
}
else
{
L = float3(_WorldSpaceLightPos0 - psIn.vWorldPosition);
float dist = length(L);
atten = 1.0 / dist;
L = normalize(L);
}
// hide the material characteristics in class and call its Illuminate() method
// to light it
Material obj;
obj.fFresnelMin = _fFresnelMin;
obj.fFresnelExp = _fFresnelExp;
obj.fSpecPower = _fSpecularPower;
obj.cSpecular = ctSpecular * _cSpecular;
obj.cAlbedo = ctAlbedo * _cAlbedo;
obj.cOcclusion = ctOcclusion;
obj.cResult = float3(0,0,0);
obj.Illuminate(nVertex,nLight,L,vToEye,float3(_LightColor0.rgb) * atten);
cOut = cOut + obj.cResult;
// transparency - modulated by the 'r' channel of the Alpha texture
float alpha = _fAlphaScale * tex2D(_txAlpha,psIn.vTexCoord0).r;
// calculate the Fresnel term for the reflected light
float fFresnelReflect = lerp(1.0f, _fFresnelMin + (1.0f - _fFresnelMin) *
pow(1.0f - saturate(dot(vEyeReflect,nLight)), _fFresnelExp), _bEnableFresnel);
cOut += fFresnelReflect * ctSpecular * _cReflection * ctReflection;
return float4(cOut,alpha);
}
ENDCG
}
// additional light sources
// and all light sources with cookies - i.e. spot lights - for these use cookies to achieve the correct angle
Pass {
Tags {
"LightMode" = "ForwardAdd"
}
Blend One One // additive blending for additional lights
CGPROGRAM
#pragma only_renderers d3d11
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdbase
#pragma target 5.0
#include "UnityCG.cginc"
#include "AutoLight.cginc"
uniform float4 _LightColor0; // color of light source - from Lighting.cginc
uniform float3 _cAlbedo;
uniform float3 _cSpecular;
uniform float _fDiffuseIntensity;
uniform float _fSpecularPower;
uniform float _fHalfLambertExp;
uniform float _fFresnelMin;
uniform float _fFresnelExp;
uniform float _fAlphaScale;
uniform bool _bEnableFresnel;
uniform bool _bEnableAlphaFresnel;
uniform bool _bEnableHalfLambert;
uniform sampler2D _txOcclusion;
uniform sampler2D _txAlbedo;
uniform sampler2D _txNormal;
uniform sampler2D _txSpecular;
uniform sampler2D _txAlpha;
struct VsIn {
float4 vPosition : POSITION;
float4 vTangent : TANGENT;
float3 vNormal : NORMAL;
float4 vTexCoord0 : TEXCOORD0;
};
struct Vs2Ps {
float4 vPosition : SV_POSITION;
float3 vWorldPosition : TEXCOORD0;
float3 vToEye : TEXCOORD1;
float3 vWorldNormal : TEXCOORD2;
float3 vWorldTangent : TEXCOORD3;
float3 vWorldBitangent : TEXCOORD4;
float2 vTexCoord0 : TEXCOORD5;
LIGHTING_COORDS(6,7)
};
Vs2Ps vert(in VsIn vsIn)
{
Vs2Ps vsOut;
// vertex from model space to view space and world space
// normally a geometry shader would come next, in which case we would only go to world space
vsOut.vPosition = UnityObjectToClipPos(vsIn.vPosition);
vsOut.vWorldPosition = mul(unity_ObjectToWorld,vsIn.vPosition).xyz;
vsOut.vToEye = normalize(WorldSpaceViewDir(vsIn.vPosition));
// tangent space basis vector from model space to view space
// normally a geometry shader would come next, in which case we would only go to world space
vsOut.vWorldNormal = normalize(mul((float3x3)unity_ObjectToWorld,vsIn.vNormal));
vsOut.vWorldTangent = normalize(mul((float3x3)unity_ObjectToWorld,vsIn.vTangent));
float3 BiTangent = cross(vsIn.vNormal,vsIn.vTangent.xyz) * vsIn.vTangent.w;
vsOut.vWorldBitangent = normalize(mul((float3x3)unity_ObjectToWorld,BiTangent));
// pass through the texture coord
vsOut.vTexCoord0 = vsIn.vTexCoord0;
return vsOut;
}
// wrap-around lambertian
float HalfLambert(float nDotL)
{
return saturate((nDotL + _fHalfLambertExp) / ((1 + _fHalfLambertExp) * (1 + _fHalfLambertExp)));
}
//
// this class is the per-light computation of the illuminance
//
class Material
{
// Material properties used in lighting calculation.
float fFresnelMin;
float fFresnelExp;
float fSpecPower;
float3 cSpecular;
float3 cAlbedo;
float3 cOcclusion;
float3 cResult;
void Illuminate(
in float3 nVertex, // Iterated world space vertex normal
in float3 nLight, // World space surface normal for lighting
in float3 vToLight, // Direction to light.
in float3 vToEye, // Direction to the eye.
in float3 cIrradiance // Light irradiance.
)
{
// this next piece of code is the fulcrum illuminance loop
float nDotL = dot(nLight,vToLight); // normal due to the normal map
float nDotLVert = dot(nVertex,vToLight); // interpolated vertex normal
// calculate the reflection vector from the light
float3 vReflect = 2.0f * nDotL * nLight - vToLight;
// Calculate the diffuse intensity and clamp lighting
// on backside normal map normals.
float fBackClamp = 1.0;
float fIDiffuse = 0.0;
if (_bEnableHalfLambert)
{
fBackClamp = HalfLambert(nDotLVert);
fIDiffuse = _fDiffuseIntensity * fBackClamp;
}
else
{
fBackClamp = step(0, nDotLVert);
fIDiffuse = fBackClamp * _fDiffuseIntensity * saturate(nDotL);
}
// Calculate the Fresnel term for the light.
float2 vCoeff = float2(1, 1);
if (_bEnableFresnel)
{
float fReflect = _fFresnelMin + (1.0 - _fFresnelMin) * pow(1.0 - fIDiffuse, _fFresnelExp);
vCoeff = float2(1 - fReflect, fReflect);
}
// Calculate the specular intensity.
float fISpecular = fBackClamp * pow(saturate(dot(vReflect, vToEye)), _fSpecularPower);
// bring the two color computations together
cResult = cOcclusion * cIrradiance * (vCoeff.x * fIDiffuse * _cAlbedo + vCoeff.y * fISpecular * _cSpecular);
}
};
float4 frag(in Vs2Ps psIn) : SV_TARGET
{
// the following code is more-or-less lifted straight from the fulcrum shader
// cubemap implementation differs
// read emissive, ambient, diffuse and specular maps
// correct gamma to linear
float3 ctOcclusion = pow(tex2D(_txOcclusion, psIn.vTexCoord0).rgb, 2.2);
float3 ctAlbedo = pow(tex2D(_txAlbedo, psIn.vTexCoord0).rgb, 2.2);
float3 ctSpecular = pow(tex2D(_txSpecular, psIn.vTexCoord0).rgb, 2.2);
// read normal map and Eye, Normal, Tangent and Bitangent vectors
// from the vertex shader data structure
float3 vtNormal = tex2D(_txNormal, psIn.vTexCoord0).rgb;
float3 V = normalize(psIn.vToEye);
float3 nVertex = normalize(psIn.vWorldNormal);
float3 nTangent = normalize(psIn.vWorldTangent);
float3 nBitangent = normalize(psIn.vWorldBitangent);
// convert the normal map from normalized range [0,1] to [-1,1]
vtNormal.xyz = 2 * vtNormal - 1;
// build the tangent space to world space transform and transform
// the normal map normal from tangent space to world space
float3x3 mTangentToWorld = { nTangent, nBitangent, nVertex };
float3 N = mul(vtNormal, mTangentToWorld);
N = normalize(N);
// calculate the eye reflection vector and get reflection map color
float3 vEyeReflect = 2.0f * dot(N,V) * N - V;
// at this point in the fulcrum shader the illuminance loop is called
// due to the idiosyncrasies of Unity at this point we sample the one light that is known to be calling
// this shader - a single directional light
// additional (spot) lights are computed in the next pass
// in this pass we compute the light due to the directional and all non-light related quantities
// work with the directional light (if it exists) - compute its direction and attenuation
float3 L;
float atten;
if (0.0 == _WorldSpaceLightPos0.w) // directional light
{
atten = 1.0;
L = normalize(float3(_WorldSpaceLightPos0.xyz));
}
else
{
L = float3(_WorldSpaceLightPos0 - psIn.vWorldPosition);
float dist = length(L);
atten = 1.0 / dist;
L = normalize(L);
}
// hide the material characteristics in class and call its Illuminate() method
// to light it
Material obj;
obj.fFresnelMin = _fFresnelMin;
obj.fFresnelExp = _fFresnelExp;
obj.fSpecPower = _fSpecularPower;
obj.cSpecular = ctSpecular * _cSpecular;
obj.cAlbedo = ctAlbedo * _cAlbedo;
obj.cOcclusion = ctOcclusion;
obj.cResult = float3(0,0,0);
obj.Illuminate(nVertex,N,L,V,float3(_LightColor0.rgb) * atten);
float3 cOut = obj.cResult;
// transparency - modulated by the 'r' channel of the Alpha texture
float alpha = _fAlphaScale * tex2D(_txAlpha,psIn.vTexCoord0).r;
//cOut=float3(0,0,0);
return float4(cOut,alpha);
}
ENDCG
}
}
}