本文效果图:
基于次表面散射(SSS)原理介绍请参考上一遍,求模型厚度的时候,本文采用渲染模型正面和背面的深度图,模型渲染代码如下:
Shader "Custom/JadeRender"
{
Properties{
_Diffuse("Diffuse", Color) = (1, 1, 1, 1)
_Specular("Specular",Color) = (1.0,1.0,1.0,1.0)
_Base("BaseColor",Color) = (1.0,1.0,1.0,1.0)
_Shinness("Shinness",Range(8,256)) = 128
_Wrap("Wrap",Range(0,1)) = 0.5
_ScatterWidth("_ScatterWidth",Vector) = (0,0,0,0)
_ScatterFactor("_ScatterFactor",Range(0,1)) = 0.75
_MainTex("MainTex",2D) = "white"{}
_ScatterTex("_ScatterTex",2D) = "white"{}
}
SubShader{
Tags{ "RenderType" = "Opaque" "Queue" = "Geometry" }
GrabPass
{
}
Pass{
Tags{ "LightMode" = "ForwardBase" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdbase
#include "Lighting.cginc"
fixed4 _Diffuse;
float _Wrap;
sampler2D _MainTex;
float4 _MainTex_ST;
float4 _ScatterWidth;
float _ScatterFactor;
sampler2D _ScatterTex;
float4 _ScatterTex_ST;
float4 _Specular;
float4 _Base;
float _Shinness;
sampler2D _BackDepthTex;
sampler2D _GrabTex;
float4x4 _WolrdtoLightMatrix;
struct a2v {
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 tangent:TANGENT;
float2 texcoord:TEXCOORD0;
};
struct v2f {
float4 pos : SV_POSITION;
float3 wNormal : TEXCOORD0;
float4 wPos:TEXCOORD1;
float4 uv:TEXCOORD2;
float4 scrPos:TEXCOORD3;
float4 Pz:TEXCOORD4;
};
v2f vert(a2v v) {
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.wNormal = mul(v.normal, (float3x3)unity_WorldToObject);
o.scrPos = ComputeScreenPos(o.pos);
o.wPos = mul(unity_ObjectToWorld,v.vertex);
o.uv.xy = TRANSFORM_TEX(v.texcoord,_MainTex);
o.uv.zw = TRANSFORM_TEX(v.texcoord,_ScatterTex);
o.Pz.xy = o.pos.zw;
return o;
}
fixed4 frag(v2f i) : SV_Target{
float frontDepth = LinearEyeDepth(i.Pz.x/i.Pz.y);
float4 backDepthColor = tex2D(_BackDepthTex, i.scrPos.xy / i.scrPos.w);
float4 grabTex = tex2D(_GrabTex, i.scrPos.xy / i.scrPos.w);
float backDepth = 40*Linear01Depth(DecodeFloatRGBA(backDepthColor));//LinearEyeDepth
float depth = (backDepth-frontDepth);
if (depth < 0.2)
depth = 0.2;
float3 scattering = exp(-_ScatterWidth.xyz*depth);
float3 N = normalize(i.wNormal);
float4 texcol = tex2D(_MainTex, i.uv.xy);
fixed3 albedo = _Diffuse.rgb; // texcol.rgb*_Diffuse.rgb;
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz*albedo;
float3 L = normalize(UnityWorldSpaceLightDir(i.wPos));
float3 V = normalize(UnityWorldSpaceViewDir(i.wPos));
float3 H = normalize(L + V);
float wrap = (dot(L,N) + _Wrap) / (1 + _Wrap);
float wrap_diff = max(0,wrap);
fixed3 diffuse = _LightColor0.rgb * wrap_diff*albedo;
float s = pow(max(0,dot(N,H)),_Shinness);
float3 specular = _LightColor0.rgb *_Specular.rgb*s;
float3 scatterTex = tex2D(_ScatterTex,i.uv.zw);
float4 finCol;
finCol = float4(backDepth, backDepth, backDepth,1.0);
finCol = float4(1.0, 0.0, 0.0, 1.0);
float3 back = float3(frontDepth, frontDepth, frontDepth);
finCol.rgb = scattering *_Base*(diffuse + ambient)+ specular;// *0.5 + 0.5*tex.rgb;// lerp(ambient + diffuse, scattering, _ScatterFactor) + specular;
float factor = depth;
if (factor > 1.0f)//此处模拟透明,透明属性应该保存在纹理的alpha中,但是本人没有玉石纹理和对应alpha设置,这里根据深度来计算透明度
factor = 1.0f;
if (factor < 0.6f)
factor = 0.6f;
finCol.rgb = lerp(grabTex, finCol, factor);
//finCol.a = texcol.a;
return finCol;
}
ENDCG
}
}
// FallBack "Diffuse"
}
源码地址: