Unity3D之高階渲染-Shader Forge
阿新 • • 發佈:2019-01-02
筆者介紹:姜雪偉,IT公司技術合夥人,IT高階講師,CSDN社群專家,特邀編輯,暢銷書作者,國家專利發明人;已出版書籍:《手把手教你架構3D遊戲引擎》電子工業出版社和《Unity3D實戰核心技術詳解》電子工業出版社等。
在前面的部落格中給讀者介紹了關於使用Shader Forge的應用,Shader Forge這個元件使用起來還是非常方便的,尤其對於哪些對Shader程式設計不是很理解的開發者,使用它可以快速的搭建出一個Shader,這個跟虛幻的UE4引擎編輯器很類似,尤其做次世代遊戲非常好。下面給讀者展示一下它的威力,效果圖如下所示:
看一下上圖展示的效果,它就是用Shader Forge搭建出來的,使用了Diffuse,Normal,Gloss,Emisson等,不對比不知道,我們看一下使用Unity3D引擎自帶的Shade效果如下所示:
這個是同樣的環境下使用Unity3D引擎自帶的standardShader的效果,它的設定介面如下所示:
既然Unity3D引擎自帶的Shader無法滿足我們的需求,那就使用Shader Forge解決問題,Shader Forge提供了一個編輯器,在上篇部落格中給讀者介紹過關於材質之間的操作,Shader Forge編輯器也是利用這個原理操作的,效果如下:
在Unity3D編輯器中的表現如下圖所示:
引數的調整自己可以根據效果隨意調整,這個模型就實現了高光,法線以及自發光等效果,通過Shader Forge生成的Shader程式碼使用的是頂點著色器和片段著色器,將上圖轉化成Shader後,核心程式碼如下所示:
VertexOutput vert (VertexInput v) { VertexOutput o = (VertexOutput)0; o.uv0 = v.texcoord0; o.normalDir = UnityObjectToWorldNormal(v.normal); o.tangentDir = normalize( mul( unity_ObjectToWorld, float4( v.tangent.xyz, 0.0 ) ).xyz ); o.bitangentDir = normalize(cross(o.normalDir, o.tangentDir) * v.tangent.w); o.posWorld = mul(unity_ObjectToWorld, v.vertex); float3 lightColor = _LightColor0.rgb; o.pos = mul(UNITY_MATRIX_MVP, v.vertex ); UNITY_TRANSFER_FOG(o,o.pos); TRANSFER_VERTEX_TO_FRAGMENT(o) return o; } float4 frag(VertexOutput i) : COLOR { i.normalDir = normalize(i.normalDir); float3x3 tangentTransform = float3x3( i.tangentDir, i.bitangentDir, i.normalDir); float3 viewDirection = normalize(_WorldSpaceCameraPos.xyz - i.posWorld.xyz); float3 _normal_var = UnpackNormal(tex2D(_normal,TRANSFORM_TEX(i.uv0, _normal))); float3 normalLocal = _normal_var.rgb; float3 normalDirection = normalize(mul( normalLocal, tangentTransform )); // Perturbed normals float3 lightDirection = normalize(_WorldSpaceLightPos0.xyz); float3 lightColor = _LightColor0.rgb; float3 halfDirection = normalize(viewDirection+lightDirection); ////// Lighting: float attenuation = LIGHT_ATTENUATION(i); float3 attenColor = attenuation * _LightColor0.xyz; ///////// Gloss: float4 _gloss_diffuse_var = tex2D(_gloss_diffuse,TRANSFORM_TEX(i.uv0, _gloss_diffuse)); float gloss = (_gloss_diffuse_var.r*_gloss); float specPow = exp2( gloss * 10.0+1.0); ////// Specular: float NdotL = max(0, dot( normalDirection, lightDirection )); float4 _light_var = tex2D(_light,TRANSFORM_TEX(i.uv0, _light)); float3 specularColor = (_light_var.rgb*_light_slider); float3 directSpecular = (floor(attenuation) * _LightColor0.xyz) * pow(max(0,dot(halfDirection,normalDirection)),specPow)*specularColor; float3 specular = directSpecular; /////// Diffuse: NdotL = max(0.0,dot( normalDirection, lightDirection )); float3 directDiffuse = max( 0.0, NdotL) * attenColor; float3 indirectDiffuse = float3(0,0,0); indirectDiffuse += UNITY_LIGHTMODEL_AMBIENT.rgb; // Ambient Light float4 _df_var = tex2D(_df,TRANSFORM_TEX(i.uv0, _df)); float3 diffuseColor = (_df_var.rgb*_df_Color.rgb); float3 diffuse = (directDiffuse + indirectDiffuse) * diffuseColor; ////// Emissive: float4 _Emission_color_var = tex2D(_Emission_color,TRANSFORM_TEX(i.uv0, _Emission_color)); float3 emissive = (_Emission_color_var.rgb*_Emission_slider); /// Final Color: float3 finalColor = diffuse + specular + emissive; fixed4 finalRGBA = fixed4(finalColor,1); UNITY_APPLY_FOG(i.fogCoord, finalRGBA); return finalRGBA; }
這樣我們就實現了次世代效果渲染,是不是非常酷?很多人擔心其效能,其實在IOS端幀率還是可以的,滿幀30的情況下,能跑到25幀左右。