|
|
|
|
|
|
// Example shader for a scriptable render loop that calculates multiple lights |
|
|
|
// in a single forward-rendered shading pass. |
|
|
|
// in a single forward-rendered shading pass. Uses same PBR shading model as the |
|
|
|
// Standard shader. |
|
|
|
// |
|
|
|
// The parameters and inspector of the shader are the same as Standard shader, |
|
|
|
// for easier experimentation. |
|
|
|
Shader "RenderLoop/Basic/Standard" |
|
|
|
|
|
|
ZWrite[_ZWrite] |
|
|
|
|
|
|
|
CGPROGRAM |
|
|
|
|
|
|
|
#pragma shader_feature _METALLICGLOSSMAP |
|
|
|
#include "UnityStandardBRDF.cginc" |
|
|
|
#include "UnityStandardUtils.cginc" |
|
|
|
|
|
|
|
|
|
|
|
// Global lighting data (setup from C# code once per frame). |
|
|
|
CBUFFER_START(GlobalLightData) |
|
|
|
|
|
|
CBUFFER_END |
|
|
|
|
|
|
|
|
|
|
|
struct v2f |
|
|
|
// Surface inputs for evaluating Standard BRDF |
|
|
|
struct SurfaceInputData |
|
|
|
float2 uv : TEXCOORD0; |
|
|
|
float3 positionWS : TEXCOORD1; |
|
|
|
float3 normalWS : TEXCOORD2; |
|
|
|
float4 hpos : SV_POSITION; |
|
|
|
half3 diffColor, specColor; |
|
|
|
half oneMinusReflectivity, smoothness; |
|
|
|
float4 _MainTex_ST; |
|
|
|
|
|
|
|
v2f vert(appdata_base v) |
|
|
|
{ |
|
|
|
v2f o; |
|
|
|
o.uv = TRANSFORM_TEX(v.texcoord,_MainTex); |
|
|
|
o.hpos = UnityObjectToClipPos(v.vertex); |
|
|
|
o.positionWS = mul(unity_ObjectToWorld, v.vertex).xyz; |
|
|
|
o.normalWS = UnityObjectToWorldNormal(v.normal); |
|
|
|
return o; |
|
|
|
} |
|
|
|
|
|
|
|
// Compute illumination from one light, given attenuation |
|
|
|
half3 ComputeLighting(int idx, half3 dirToLight, half3 normalWS, half4 diffuseAlbedo, float atten) |
|
|
|
{ |
|
|
|
half NdotL = max(dot(normalWS, dirToLight), 0.0); |
|
|
|
// diffuse |
|
|
|
half3 color = NdotL * diffuseAlbedo.rgb * globalLightColor[idx].rgb; |
|
|
|
return color * atten; |
|
|
|
} |
|
|
|
|
|
|
|
half3 ComputeOneLight(int idx, float3 positionWS, half3 normalWS, half4 diffuseAlbedo) |
|
|
|
half3 EvaluateOneLight(int idx, float3 positionWS, half3 normalWS, half3 eyeVec, SurfaceInputData s) |
|
|
|
// direction to light |
|
|
|
float3 dirToLight = globalLightPos[idx].xyz; |
|
|
|
dirToLight -= positionWS * globalLightPos[idx].w; |
|
|
|
// distance attenuation |
|
|
|
|
|
|
if (globalLightPos[idx].w != 0 && distSqr > globalLightAtten[idx].w) att = 0.0; // set to 0 if outside of range |
|
|
|
distSqr = max(distSqr, 0.000001); // don't produce NaNs if some vertex position overlaps with the light |
|
|
|
dirToLight *= rsqrt(distSqr); |
|
|
|
// spot angle attenuation |
|
|
|
// spotlight angular attenuation |
|
|
|
return min(ComputeLighting(idx, dirToLight, normalWS, diffuseAlbedo, att), 1.0); |
|
|
|
// Super simple diffuse lighting instead of PBR would be this: |
|
|
|
//half ndotl = max(dot(normalWS, dirToLight), 0.0); |
|
|
|
//half3 color = ndotl * s.diffColor * globalLightColor[idx].rgb; |
|
|
|
//return color * att; |
|
|
|
|
|
|
|
// Fill in light & indirect structures, and evaluate Standard BRDF |
|
|
|
UnityLight light; |
|
|
|
light.color = globalLightColor[idx].rgb * att; |
|
|
|
light.dir = dirToLight; |
|
|
|
UnityIndirect indirect; |
|
|
|
indirect.diffuse = 0; |
|
|
|
indirect.specular = 0; |
|
|
|
half4 c = BRDF1_Unity_PBS(s.diffColor, s.specColor, s.oneMinusReflectivity, s.smoothness, normalWS, -eyeVec, light, indirect); |
|
|
|
return c.rgb; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{ |
|
|
|
half3 res; |
|
|
|
half4 normal = half4(n, 1); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return res; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Vertex shader |
|
|
|
struct v2f |
|
|
|
{ |
|
|
|
float2 uv : TEXCOORD0; |
|
|
|
float3 positionWS : TEXCOORD1; |
|
|
|
float3 normalWS : TEXCOORD2; |
|
|
|
float4 hpos : SV_POSITION; |
|
|
|
}; |
|
|
|
return res; |
|
|
|
float4 _MainTex_ST; |
|
|
|
|
|
|
|
v2f vert(appdata_base v) |
|
|
|
{ |
|
|
|
v2f o; |
|
|
|
o.uv = TRANSFORM_TEX(v.texcoord,_MainTex); |
|
|
|
o.hpos = UnityObjectToClipPos(v.vertex); |
|
|
|
o.positionWS = mul(unity_ObjectToWorld, v.vertex).xyz; |
|
|
|
o.normalWS = UnityObjectToWorldNormal(v.normal); |
|
|
|
return o; |
|
|
|
|
|
|
|
sampler2D _MetallicGlossMap; |
|
|
|
float _Metallic; |
|
|
|
float _Glossiness; |
|
|
|
// Main pixel shader |
|
|
|
// Fragment shader |
|
|
|
i.normalWS = normalize(i.normalWS); |
|
|
|
half3 eyeVec = normalize(i.positionWS - _WorldSpaceCameraPos); |
|
|
|
|
|
|
|
// Sample textures |
|
|
|
half2 metalSmooth; |
|
|
|
#ifdef _METALLICGLOSSMAP |
|
|
|
metalSmooth = tex2D(_MetallicGlossMap, i.uv).ra; |
|
|
|
#else |
|
|
|
metalSmooth.r = _Metallic; |
|
|
|
metalSmooth.g = _Glossiness; |
|
|
|
#endif |
|
|
|
|
|
|
|
// Fill in surface input structure |
|
|
|
SurfaceInputData s; |
|
|
|
s.diffColor = DiffuseAndSpecularFromMetallic(diffuseAlbedo.rgb, metalSmooth.x, s.specColor, s.oneMinusReflectivity); |
|
|
|
s.smoothness = metalSmooth.y; |
|
|
|
color.rgb += EvaluateSH(i.normalWS) * diffuseAlbedo.rgb; |
|
|
|
UnityLight light; |
|
|
|
light.color = 0; |
|
|
|
light.dir = 0; |
|
|
|
UnityIndirect indirect; |
|
|
|
indirect.diffuse = EvaluateSH(i.normalWS); |
|
|
|
indirect.specular = 0; |
|
|
|
color.rgb += BRDF1_Unity_PBS(s.diffColor, s.specColor, s.oneMinusReflectivity, s.smoothness, i.normalWS, -eyeVec, light, indirect); |
|
|
|
color.rgb += ComputeOneLight(il, i.positionWS, i.normalWS, diffuseAlbedo); |
|
|
|
color.rgb += EvaluateOneLight(il, i.positionWS, i.normalWS, eyeVec, s); |
|
|
|
} |
|
|
|
return color; |
|
|
|
} |
|
|
|