浏览代码

- Optimized tangetToWorld matrix multiplication

- Moved SH code to use builtin shader constansts. (SHA, SHB, SHC)
/vr_sandbox
Felipe Lira 8 年前
当前提交
db6e8103
共有 3 个文件被更改,包括 55 次插入96 次删除
  1. 4
      Assets/LowEndRenderLoop/LowEndPipeline.asset
  2. 100
      Assets/LowEndRenderLoop/LowEndRenderLoopShader.shader
  3. 47
      Assets/LowEndRenderLoop/LowEndRenderPipeline.cs

4
Assets/LowEndRenderLoop/LowEndPipeline.asset


m_EditorClassIdentifier:
m_SupportsVertexLight: 0
m_EnableLightmaps: 1
m_ShadowAtlasWidth: 2048
m_ShadowAtlasHeight: 2048
m_EnableAmbientProbe: 1
m_ShadowAtlasResolution: 2048

100
Assets/LowEndRenderLoop/LowEndRenderLoopShader.shader


#pragma fragment frag
#pragma shader_feature _SPECGLOSSMAP
#pragma shader_feature _NORMALMAP
#pragma shader_feature _EMISSION
#pragma multi_compile _ LIGHTMAP_ON
#pragma multi_compile _ LIGHTMAP_ON
//#pragma enable_d3d11_debug_symbols
#include "UnityCG.cginc"
#include "UnityStandardBRDF.cginc"

float4 globalLightPos[MAX_LIGHTS];
half4 globalLightSpotDir[MAX_LIGHTS];
half4 globalLightAtten[MAX_LIGHTS];
// Global ambient/SH probe, similar to unity_SH* built-in variables.
float4 globalSH[7];
sampler2D g_tShadowBuffer;
half4x4 _WorldToShadow[MAX_SHADOW_CASCADES];

half4 spotDir;
};
// Evaluate 2nd order spherical harmonics, given normalized world space direction.
// Similar to ShadeSH9 in UnityCG.cginc
half3 EvaluateSH(half3 n)
{
half3 res;
half4 normal = half4(n, 1);
// Linear (L1) + constant (L0) polynomial terms
res.r = dot(globalSH[0], normal);
res.g = dot(globalSH[1], normal);
res.b = dot(globalSH[2], normal);
// 4 of the quadratic (L2) polynomials
half4 vB = normal.xyzz * normal.yzzx;
res.r += dot(globalSH[3], vB);
res.g += dot(globalSH[4], vB);
res.b += dot(globalSH[5], vB);
// Final (5th) quadratic (L2) polynomial
half vC = normal.x*normal.x - normal.y*normal.y;
res += globalSH[6].rgb * vC;
return res;
}
inline int ComputeCascadeIndex(half eyeZ)
{
// PSSMDistance is set to infinity for non active cascades. This way the comparison for unavailable cascades will always be zero.

half3 halfVec = normalize(lightDir + viewDir);
half NdotH = saturate(dot(normal, halfVec));
half3 lightColor = lightInput.color.rgb * lightAtten;
half3 lightColor = lightInput.color.rgb * lightAtten;
half3 diffuse = diffuseColor * lightColor * NdotL;
half3 specular = specularColor * lightColor * pow(NdotH, 128.0f) * _Glossiness;
return diffuse + specular;

float3 shadowCoord = mul(_WorldToShadow[cascadeIndex], float4(posWorld.xyz, 1.0));
shadowCoord.z = saturate(shadowCoord.z);
// TODO: Apply proper bias considering NdotL
half bias = 0.0005;
shadowAttenuation = step(shadowDepth - bias, shadowCoord.z);
shadowAttenuation = step(shadowDepth, shadowCoord.z);
shadowAttenuation = step(shadowCoord.z - bias, shadowDepth);
shadowAttenuation = step(shadowCoord.z, shadowDepth);
#endif
#if DEBUG_CASCADES

{
float4 uv01 : TEXCOORD0; // uv01.xy: uv0, uv01.zw: uv1
float4 posWS : TEXCOORD1; // xyz: posWorld, w: eyeZ
half4 normalWS : TEXCOORD2;// xyz: normal, w: fresnel term
half3 tangentWS : TEXCOORD3;
half3 binormalWS : TEXCOORD4;
#if _NORMALMAP
half3 tangentToWorld[3] : TEXCOORD2; // tangentToWorld matrix
#else
half3 normal : TEXCOORD2;
#endif
half4 viewDir : TEXCOORD5; // xyz: viewDir, w: grazingTerm;
UNITY_FOG_COORDS_PACKED(6, half4) // x: fogCoord, yzw: vertexColor
float4 hpos : SV_POSITION;

#if !GLOSSMAP
o.viewDir.w = GRAZING_TERM;
#endif
o.normalWS.xyz = UnityObjectToWorldNormal(v.normal);
o.normalWS.w = FRESNEL_TERM(o.normalWS.xyz, o.viewDir.xyz);
half3 normal = normalize(UnityObjectToWorldNormal(v.normal));
half fresnelTerm = FRESNEL_TERM(normal, o.viewDir.xyz);
o.tangentWS = UnityObjectToWorldDir(v.tangent);
o.binormalWS = cross(o.normalWS.xyz, o.tangentWS) * v.tangent.w;
half3 tangent = normalize(UnityObjectToWorldDir(v.tangent));
half3 binormal = cross(normal, tangent) * v.tangent.w;
// Initialize tangetToWorld in column-major to benefit from better glsl matrix multiplication code
o.tangentToWorld[0] = half3(tangent.x, binormal.x, normal.x);
o.tangentToWorld[1] = half3(tangent.y, binormal.y, normal.y);
o.tangentToWorld[2] = half3(tangent.z, binormal.z, normal.z);
#else
o.normal = normal;
#endif
half3 diffuseAndSpecularColor = half3(1.0, 1.0, 1.0);

INITIALIZE_LIGHT(lightInput, lightIndex);
o.fogCoord.yzw += EvaluateOneLight(lightInput, diffuseAndSpecularColor, diffuseAndSpecularColor, o.normalWS, o.posWS.xyz, o.viewDir.xyz);
o.fogCoord.yzw += EvaluateOneLight(lightInput, diffuseAndSpecularColor, diffuseAndSpecularColor, normal, o.posWS.xyz, o.viewDir.xyz);
#ifndef LIGHTMAP_ON
o.fogCoord.yzw += max(half3(0, 0, 0), ShadeSH9(half4(normal, 1)));
#endif
o.fogCoord.x = 1.0;
UNITY_TRANSFER_FOG(o, o.hpos);
return o;

{
#if _NORMALMAP
half3 normalmap = UnpackNormal(tex2D(_BumpMap, i.uv01.xy));
// TODO: This will generate unoptimized code from the glsl compiler. Store the transpose matrix and compute dot manually
half3x3 tangentToWorld = half3x3(i.tangentWS, i.binormalWS, i.normalWS.xyx);
half3 normal = mul(normalmap, tangentToWorld);
// glsl compiler will generate underperforming code by using a row-major pre multiplication matrix: mul(normalmap, i.tangentToWorld)
// i.tangetToWorld was initialized as column-major in vs and here dot'ing individual for better performance.
// The code below is similar to post multiply: mul(i.tangentToWorld, normalmap)
half3 normal = half3(dot(normalmap, i.tangentToWorld[0]), dot(normalmap, i.tangentToWorld[1]), dot(normalmap, i.tangentToWorld[2]));
half3 normal = normalize(i.normalWS.xyz);
half3 normal = normalize(i.normal);
half3 diffuse = diffuseAlbedo.rgb * _Color.rgb;
half3 diffuse = diffuseAlbedo.rgb *_Color.rgb;
half alpha = diffuseAlbedo.a * _Color.a;
half4 specGloss = SpecularGloss(i.uv01.xy);

half oneMinusReflectivity;
// Note: UnityStandardCoreForwardSimple is not energy conserving. The lightmodel from LDPipeline will appear
// slither darker when comparing to Standard Simple due to this.
UnityIndirect giIndirect;
half3 indirectDiffuse;
giIndirect.diffuse = DecodeLightmap(UNITY_SAMPLE_TEX2D(unity_Lightmap, i.uv01.zw));
indirectDiffuse = DecodeLightmap(UNITY_SAMPLE_TEX2D(unity_Lightmap, i.uv01.zw)) * diffuse;
giIndirect.diffuse = half3(0, 0, 0);
indirectDiffuse = i.fogCoord.yzw * diffuse;
giIndirect.specular = half3(0, 0, 0);
half3 indirectColor = BRDF3_Indirect(diffuse, specular, giIndirect, i.posWS.w, i.normalWS.w);
half3 directColor = i.fogCoord.yzw * diffuseAlbedo.rgb;
// Compute direct contribution from main directional light.
// Only a single directional shadow caster is supported.
LightInput mainLight;

return half4(EvaluateMainLight(mainLight, diffuse, specular, normal, i.posWS, viewDir), 1.0);
#endif
directColor += EvaluateMainLight(mainLight, diffuse, specular, normal, i.posWS, viewDir);
half3 directColor = EvaluateMainLight(mainLight, diffuse, specular, normal, i.posWS, viewDir);
// Compute direct contribution from additional lights.
for (int lightIndex = 1; lightIndex < globalLightCount.x; ++lightIndex)

directColor += EvaluateOneLight(additionalLight, diffuse, specular, normal, posWorld, viewDir);
}
half3 color = directColor + indirectColor + _EmissionColor;
half3 color = directColor + indirectDiffuse + _EmissionColor;
UNITY_APPLY_FOG(i.fogCoord, color);
return half4(color, diffuseAlbedo.a);
};

#include "UnityCG.cginc"
float4 vert(float4 position : POSITION) : SV_POSITION
{
return UnityObjectToClipPos(position);
float4 clipPos = UnityObjectToClipPos(position);
return UnityApplyLinearShadowBias(clipPos);
}
half4 frag() : SV_TARGET

47
Assets/LowEndRenderLoop/LowEndRenderPipeline.cs


if (m_Asset.EnableLightmap)
settings.rendererConfiguration = settings.rendererConfiguration | RendererConfiguration.PerObjectLightmaps;
if (m_Asset.EnableAmbientProbe)
settings.rendererConfiguration = settings.rendererConfiguration | RendererConfiguration.PerObjectLightProbe;
context.DrawRenderers(ref settings);
context.DrawSkybox(camera);

{
m_ShadowSettings = ShadowSettings.Default;
m_ShadowSettings.directionalLightCascadeCount = QualitySettings.shadowCascades;
m_ShadowSettings.shadowAtlasWidth = m_Asset.ShadowAtlasWidth;
m_ShadowSettings.shadowAtlasHeight = m_Asset.ShadowAtlasHeight;
m_ShadowSettings.shadowAtlasWidth = m_Asset.ShadowAtlasResolution;
m_ShadowSettings.shadowAtlasHeight = m_Asset.ShadowAtlasResolution;
m_ShadowSettings.maxShadowDistance = QualitySettings.shadowDistance;
m_ShadowSettings.maxShadowLightsSupported = 1;
m_ShadowSettings.shadowType = ShadowSettings.ShadowType.LIGHTSPACE;

}
}
// ambient lighting spherical harmonics values
const int kSHCoefficients = 7;
Vector4[] shConstants = new Vector4[kSHCoefficients];
SphericalHarmonicsL2 ambientSH = RenderSettings.ambientProbe * RenderSettings.ambientIntensity;
GetShaderConstantsFromNormalizedSH(ref ambientSH, shConstants);
CommandBuffer cmd = new CommandBuffer() { name = "SetupShadowShaderConstants" };
cmd.SetGlobalVectorArray("globalLightPos", lightPositions);
cmd.SetGlobalVectorArray("globalLightColor", lightColors);

cmd.SetGlobalVectorArray("globalSH", shConstants);
context.ExecuteCommandBuffer(cmd);
cmd.Dispose();
}

context.ExecuteCommandBuffer(setupShadow);
setupShadow.Dispose();
}
private void GetShaderConstantsFromNormalizedSH(ref SphericalHarmonicsL2 ambientProbe, Vector4[] outCoefficients)
{
for (int channelIdx = 0; channelIdx < 3; ++channelIdx)
{
// Constant + Linear
// In the shader we multiply the normal is not swizzled, so it's normal.xyz.
// Swizzle the coefficients to be in { x, y, z, DC } order.
outCoefficients[channelIdx].x = ambientProbe[channelIdx, 3];
outCoefficients[channelIdx].y = ambientProbe[channelIdx, 1];
outCoefficients[channelIdx].z = ambientProbe[channelIdx, 2];
outCoefficients[channelIdx].w = ambientProbe[channelIdx, 0] - ambientProbe[channelIdx, 6];
// Quadratic polynomials
outCoefficients[channelIdx + 3].x = ambientProbe[channelIdx, 4];
outCoefficients[channelIdx + 3].y = ambientProbe[channelIdx, 5];
outCoefficients[channelIdx + 3].z = ambientProbe[channelIdx, 6] * 3.0f;
outCoefficients[channelIdx + 3].w = ambientProbe[channelIdx, 7];
}
// Final quadratic polynomial
outCoefficients[6].x = ambientProbe[0, 8];
outCoefficients[6].y = ambientProbe[1, 8];
outCoefficients[6].z = ambientProbe[2, 8];
outCoefficients[6].w = 1.0f;
}
#endregion
}
#endregion

#region PipelineAssetSettings
public bool m_SupportsVertexLight = true;
public bool m_EnableLightmaps = true;
public int m_ShadowAtlasWidth = 1024;
public int m_ShadowAtlasHeight = 1024;
public bool m_EnableAmbientProbe = true;
public int m_ShadowAtlasResolution = 1024;
public int ShadowAtlasWidth { get { return m_ShadowAtlasWidth; } private set { m_ShadowAtlasWidth = value; } }
public int ShadowAtlasHeight { get { return m_ShadowAtlasHeight; } private set { m_ShadowAtlasHeight = value; } }
public bool EnableAmbientProbe { get { return m_EnableAmbientProbe;} private set { m_EnableAmbientProbe = value; } }
public int ShadowAtlasResolution { get { return m_ShadowAtlasResolution; } private set { m_ShadowAtlasResolution = value; } }
#endregion
}
正在加载...
取消
保存