Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to write the code of Unity lighting system based on ShaderLab

2025-01-28 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

Today, I will talk to you about how to write the code of Unity lighting system based on ShaderLab, which may not be well understood by many people. In order to make you understand better, the editor has summarized the following content for you. I hope you can get something according to this article.

Shader 1. Vertex slice element shader

Divided into vertex shaders and chip element shaders, corresponding to the vertex transformation and chip element shading phases of the rendering pipeline

The simplest vertex slice element shader:

Shader "MyShader/VertexFragmentShader" {Properties {_ MainColor ("MainColor", Color) = (1 RenderType 1)} SubShader {Tags {"RenderType" = "Opaque"} Pass {CGPROGRAM # pragma vertex vert # pragma fragment frag float4 _ MainColor Float4 vert (float4 v:POSITION): SV_POSITION {return UnityObjectToClipPos (v);} fixed4 frag (): SV_Target {return _ MainColor;} ENDCG}} 2. Surface shader

Another layer of encapsulation of vertex and element shaders

Control reflectivity, smoothness, transparency, etc., by surface function

Select the lighting model to be used through the lighting function

Surface shaders provide convenience, but also reduce degrees of freedom

What surface shaders can achieve, vertex chip shaders can be realized, but vertex chip shaders have higher maneuverability and better performance.

Simple surface shader:

Shader "MyShader/SurfaceShader" {SubShader {Tags {"RenderType" = "Opaque"} CGPROGRAM / / surface shader, using Lambert illumination # pragma surface surf Lambert struct Input {float4 color: COLOR;}; void surf (Input IN,inout SurfaceOutput o) {o.Albedo = 1 } ENDCG} Fallback "Diffuse"} 3. Fixed function shader

It has been basically abandoned and not analyzed.

Second, lighting model 1. Illumination per vertex (Gourand Shading)

The illumination is calculated in the vertex shader; the number of vertices is less than that of the chip, and the amount of calculation is also less, and the illumination of each pixel is obtained by linear interpolation.

So there will be an error in nonlinear lighting calculation-- highlights (which will be written later)

V2f vert (a2v v) {v2fo; / transform vertices to crop space o.pos = UnityObjectToClipPos (v.vertex); / / Ambient fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz; / / normal fixed3 worldNormal = normalize in world space (mul (v.unitywritten WorldToObject)) / / fixed3 worldLight = normalize (_ WorldSpaceLightPos0.xyz) in world space; / / diffuse direction is obtained by point illumination and normal, satruate takes a range of 0-1; fixed3 diffuse = _ LightColor0.rgb * _ Diffuse.rgb * saturate (dot (worldNormal, worldLight)); / / ambient light + diffuse o.color = ambient + diffuse; return o;} 2. Piece by piece meta-illumination (Phong Shading)

The illumination is calculated in the chip shader; the illumination is calculated according to the normal of each element; the effect is good and the amount of calculation is large, which is also called phong interpolation.

V2f vert (a2v) {v2f o; / vertex transformation to crop space o.pos = UnityObjectToClipPos (v.vertex); / / pass world coordinate normals to the chip element shader o.worldNormal = mul (v.unityunityworldToObject); return o;} fixed4 frag (v2f v): SV_Target {/ / ambient fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz / / Normalized world normal fixed3 worldNormal = normalize (v.worldNormal); / / Normalized world space fixed3 worldLight = normalize (_ WorldSpaceLightPos0.xyz); / / diffuse fixed3 diffuse = _ LightColor0.rgb * _ Diffuse.rgb * saturate (dot (worldNormal, worldLight)) / / add ambient light and diffuse fixed3 color = ambient + diffuse; return fixed4 (color,1.0);}

This is also the algorithm of Lambert illumination model.

3.HalfLambert illumination

V Society uses a standard for half-life, calculating the result of diffuse reflection + 0 ~ 5; this has a great optimization for the dark part.

/ / HalfLambertParmafixed halfLambert = dot (worldNormal, worldLight) * 0.5 + 0.5 halfLambert / use halfLambert to calculate diffuse fixed3 diffuse = _ LightColor0.rgb * _ Diffuse.rgb * halfLambert

4. Highlight per vertex

The calculation of light per vertex mentioned above will make an error to the nonlinear light.

The highlight is caused by reflection and is related to the direction of observation and light; the specific relationship refers to the basis of graphics.

Add to the vertex shader function:

/ / calculate the reflection direction fixed3 reflectDir = normalize (reflect (- worldLight, worldNormal)) using the reflect method according to the normal and ray direction; / / calculate the viewing direction, camera position-vertex position (also in the world coordinate system) fixed3 viewDir = normalize (_ WorldSpaceCameraPos.xyz-mul (unity_ObjectToWorld, v.vertex) .xyz) / / Specular calculation formula in Phong illumination model: _ Specular color, _ Gloss roughness, _ LightColor0 system parameter illumination color fixed3 specular = _ LightColor0.rgb * _ Specular.rgb * pow (saturate (reflectDir (reflectDir, viewDir)), _ Gloss); o.color = ambient + diffuse + specular;5. Pixel-by-pixel highlight

Issue the per-vertex highlight code for execution in the chip element shader

6.Bline-Phong illumination model

Both the per-vertex and per-pixel highlights above use the Phong lighting model.

When calculating highlights, use reflect function to calculate reflection vector, which is relatively large.

Bline-Phong uses (ray direction + view direction) instead of reflection vector

/ / the middle direction between the world light direction and the viewing direction; fixed3 halfDir = normalize (worldLight + viewDir); / / use halfDir to calculate specular fixed3 specular = _ LightColor0.rgb * _ Specular.rgb * pow (max (0, dot (worldNormal, halfDir), _ Gloss); fixed3 color = ambient + diffuse + specular

Third, texture map 1. Single texture

Use texture sampling instead of solid color, sample the texture map in the chip shader, and modify the pixel color

_ MainTexture_ST controls the scaling and offset of the map (Scale,Translate)

V2f vert (a2v v) {/ / uv is passed to the chip element shader, which can be passed to the element shader using the macro command TRANSFORM_TEX o.uv = v.texcoord.xy * _ MainTexture_ST.xy + _ MainTexture_ST.zw; / / o.uv = TRANSFORM_TEX } fixed4 farg (v2f v): SV_Target {/ / texture sampling, surface color-texture fixed3 albedo = tex2D (_ MainTexture, v.uv). Rgb * _ Color.rgb; / / ambient light * surface color fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo; fixed halfLambert = dot (worldNormal, worldLight) * 0.5 + 0.5 / / diffuse * Surface color fixed3 diffuse = _ LightColor0.rgb * albedo.rgb * halfLambert;} 2. Normal textur

There are two ways to calculate normals:

Transform the ray and observation vector to tangent space

Transform normal into world space under tangent space

Tangent space calculation is less efficient because of matrix transformation in vertex shader.

Because of cognition, or other needs, we also calculate normals in world space.

-normal texture tangent space calculation

V2f vert (a2v v) {v2fo; o.pos = UnityObjectToClipPos (v.vertex); o.uv.xy = v.texcoord.xy * _ MainTexture_ST.xy + _ MainTexture_ST.zw; / / o.uv = TRANSFORM_TEX (v.texcoordBumpMap); o.uv.zw = TRANSFORM_TEX (v.texcoordBumpMap) / / Macro definition, find the world space-tangent space transformation matrix rotation TANGENT_SPACE_ROTATION; o.lightDir = mul (rotation,ObjSpaceLightDir (v.vertex)) .xyz; o.viewDir = mul (rotation,ObjSpaceViewDir (v.vertex)) .xyz; return o;} fixed4 frag (v2f v): SV_Target {/ / tangent space-ray direction fixed3 tangentLightDir = normalize (v.lightDir) / / tangent space-viewing direction fixed3 tangentViewDir = normalize (v.viewDir); / / normal mapping format is NormalMap, decompressed with UnpackNormal, and sampled to get normal fixed3 tangentNormal = UnpackNormal (tex2D (_ BumpMap,v.uv.zw)) in tangent space; / / normal scaling tangentNormal.xy * = _ BumpScale / / normal map compression method, z value can be calculated, Pythagorean theorem, the following is a simplified formula tangentNormal.z = sqrt (1.0-saturate (dot (tangentNormal.xy,tangentNormal.xy); / / diffuse highlights are calculated using tangentNormal}

-normal texture world space calculation

V2f vert (a2v v) {v2fo; o.pos = UnityObjectToClipPos (v.vertex); / / reduce the use of registers, xy records the main texture uv,zw recording normal uv o.uv.xy = v.texcoord.xy * _ MainTexture_ST.xy + _ MainTexture_ST.zw; o.uv.zw = TRANSFORM_TEX (v.texcoordGravity BumpMap) / find normal, tangent and sub-tangent in world space float3 worldPos = mul (unity_ObjectToWorld,v.vertex) .xyz; fixed3 worldNormal = UnityObjectToWorldNormal (v.normal); fixed3 worldTangent = UnityObjectToWorldDir (v.tangent.xyz); fixed3 worldBinnormal = cross (worldNormal,worldTangent) * v.tangent.w / / normal, tangent and sub-tangent constitute the tangent space transformation matrix. The w value trick stores the vertex coordinates of the world coordinate system o.Ttow0 = float4 (worldTangent.x,worldBinnormal.x,worldNormal.x,worldPos.x); o.Ttow1 = float4 (worldTangent.y,worldBinnormal.y,worldNormal.y,worldPos.y); o.Ttow2 = float4 (worldTangent.z,worldBinnormal.z,worldNormal.z,worldPos.z). Return o;} fixed4 frag (v2f v): SV_Target {. / / normal mapping format is NormalMap. Decompress it with UnpackNormal and sample to get tangent space normal fixed3 tangentNormal = UnpackNormal (tex2D (_ BumpMap,v.uv.zw)); / / normal scaling tangentNormal.xy * = _ BumpScale / / normal map compression method, z value can be calculated, Pythagorean theorem, the following is the simplified formula tangentNormal.z = sqrt (1.0-saturate (dot (tangentNormal.xy,tangentNormal.xy) / / the normal of the world space tangentNormal = normalize is obtained by matrix transformation (dot (v.Ttow0.xyzgradentNormal), dot (v.Ttow1.xyzgraveTangentNormal), dot (v.Ttow2.xyzmentangentNormal)); / / diffuse highlights are all calculated using tangentNormal}.

3. Gradient textur

The above diffuse colors are all light colors, or light colors are mixed with surface textured colors.

Sometimes the color of diffuse reflection varies according to the size of the reflection angle, such as cartoon rendering

This requires the use of gradient texture RampTexture

/ / Vertex shader converts uv fixed4 frag (v2f I) of RampTex: SV_Target {fixed halfLambert = 0.5 * dot (worldNormal,worldLightDir) + 0.5; / / samples RampTex textures according to halfLambert reflection direction fixed3 diffuseColor = tex2D (_ RampTex, fixed2 (halfLambert, halfLambert)). Rgb*_Color.rgb; fixed3 diffuse = _ LightColor0.rgb * diffuseColor;}

Three different Ramp textures:

4. Mask textur

Some parts of the highlight effect is too strong, man-made hope that some parts are darker, etc., you can use the mask texture Mask

Add to the element shader:

/ / reflection direction fixed3 halfDir = normalize (tangentLightDir + tangentViewDir); / / uv sampled specular mask texture * highlight range fixed3 specularMask = tex2D (_ SpecularMask,i.uv). R * _ SpecularScale;// results in mixed mask texture fixed3 specular = _ LightColor0.rgb * _ Specular.rgb * pow (max (0Magnum dot (tangentNormal,halfDir)), _ Gloss) * specularMask

Effect comparison:

4. Transparent objects 1. Transparency test

AlphaTest only decides whether to paint, and does not mix colors. Given a threshold of _ Cutoff, transparency is not drawn if it is less than this value.

Transparency testing requires turning off back cropping, as well as adding three suites of transparency testing

Tags {"Queue" = "AlphaTest"IgnoreProjector" = "True"RenderType" = "Transparent"}

/ / rendering queue, ignore the projector, render type Tags {"Queue" = "AlphaTest"IgnoreProjector" = "True"RenderType" = "Transparent"} / / close clipping Cull OffPass {. Fixed4 frag (v2f I): SV_Target {. / / alpha values less than _ Cutoff do not draw clip (texColor.a-_ Cutoff);.}.}

The effect of changing the size of the Culloff value:

two。 Transparent color blending

AlphaBlend transparent mixing should turn off deep writing, otherwise it will be eliminated.

To choose blending mode at the same time, multiple blending modes are a bit like transparent layer overlay in ps.

/ / three kits Tags {"Queue" = "Transparent"IgnoreProjector" = "True"RenderType" = "Transparent"} Pass {/ / turn off deep inhalation, turn on depth test, and select color mixing mode Tags {"LightMode" = "ForwardBase"} ZWrite Off Blend SrcAlpha OneMinusSrcAlpha. Fixed4 frag (v2f I): SV_Target {. / / returns shading yes, plus transparency return fixed4 (ambient + diffuse,texColor.a*_AlphaScale);}}

3. Complex model double Pass color mixing

When the model is complex, you will have your own problem; solve it with double Pass, the first pass will write deeply in advance and only do deep entry.

Pass {ZWrite On ColorMask 0 / / RGBA any |, select the channel to be written, only do depth buffering, 0 does not output color}

4. Transparent blend rendering double-sided

The same transparent object, I need to see the back of the transparent object from the front.

Use two Pass;, one Cull Front and one Cull Back

Draw the back and the front separately, draw the back first, mix the front and the back

Fifth, complex light treatment 1. Complex illumination

Unity light source is divided into vertical light, point light, conical spotlight, surface light and searchlight.

Ordinary Forwad forward rendering in Unity. No more light needs to be processed separately by adding a Pass.

Deffer delay rendering, multiple lights also refer to rendering once. A G-Buffer stores the image and processes the lighting on the G-Buffer.

Point light, conical spotlight-the direction of light from the light source to the vertex; the attenuation of the light is also different.

The point light source and the light attenuation texture map of the conical spotlight provided by the Unity system reduce the calculation.

Tags {"LightMode" = "ForwardAdd"} # pragma multi_compile_fwdadd#include "Lighting.cginc" # include "AutoLight.cginc" fixed4 frag (v2f I): SV_Target {fixed3 worldNormal = normalize (i.worldNormal); / / deal with different light,get worldLightDir; # ifdef USING_DIRECTIONAL_LIGHT fixed3 worldLightDir = normalize (_ WorldSpaceLightPos0.xyz); fixed atten = 1.0 # else fixed3 worldLightDir = normalize (_ WorldSpaceLightPos0.xyz-i.worldPos.xyz); / / Get light attenuation # if defined (POINT) float3 lightCoord = mul (unity_WorldToLight, float4 (i.worldPos, 1)) .xyz; fixed atten = tex2D (_ LightTexture0, dot (lightCoord, lightCoord) .rr). UNITY_ATTEN_CHANNEL # elif defined (SPOT) float4 lightCoord = mul (unity_WorldToLight, float4 (i.worldPos, 1)); fixed atten = (lightCoord.z > 0) * tex2D (_ LightTexture0, lightCoord.xy / lightCoord.w + 0.5). W * tex2D (_ LightTextureB0, dot (lightCoord, lightCoord) .rr). UNITY_ATTEN_CHANNEL; # else fixed atten = 1.0 # endif # endif... Return fixed4 ((diffuse+specular) * atten,1.0);}

two。 Shadow processing

There are two options on the MeshRender component in Untiy:

Whether CastShadows-- casts shadows and double-sided casting

Receive Shadows-- accepts shadows cast by other objects

Requires that the vertex coordinate variable name in V2f must be pos

A shaded shader must FallBack a pass with LightMode set to ShadowCaster

Of course, you can also implement this Pass by yourself.

Tags {"LightMode" = "ForwardBase"} CGPROGRAM#pragma multi_compile_fwdbase#include "Lighting.cginc" # include "AutoLight.cginc" struct v2f {float4 pos: SV_POSITION; SHADOW_COORDS (2)}; v2f vert (appdata v) {v2f o; o.pos = UnityObjectToClipPos (v.vertex); TRANSFER_SHADOW (o); return o;} fixed4 frag (v2f I): SV_Target {fixed atten = 1.0 Fixed shadow = SHADOW_ATTENUATION (I); return fixed4 ((ambient+ diffuse + specular) * atten*shadow,1.0);}

3. Shadow processing of transparent objects

Just change CastShadows-- to Two Sides.

Life is too short for so much sorrow.

After reading the above, do you have any further understanding of how to write the code for Unity to implement the lighting system based on ShaderLab? If you want to know more knowledge or related content, please follow the industry information channel, thank you for your support.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report