要点
- 这边只涉及光源的漫反射和高光。
- 漫反射(Diffuse)使用了Lambert方法来计算,高光(Specular)使用了Blin-Phone方法来计算,参考:Shader入门精要笔记 - CH6_最简单的逐像素Blinn-Phong光照
公式中的相关变量的获取:
1) 顶点法线方向
VertexNormalInputs normalInputs = GetVertexNormalInputs(IN.normalOS.xyz);
OUT.normalWS = normalInputs.normalWS;
2) 光线方向
Light light = GetMainLight();
float3 lightDirWS = light.direction;
3) 视角方向
VertexPositionInputs positionInputs = GetVertexPositionInputs(IN.positionOS.xyz);
OUT.viewDirWS = GetCameraPositionWS() - positionInputs.positionWS;
Shader "My/URP_SimpleLit" {Properties {_BaseMap("Texture", 2D) = "white" {} //主贴图_BaseColor("Tint Color", Color) = (1, 1, 1, 1) //混合颜色 _Specular("Specular", Color) = (1, 1, 1, 1) //高光反射颜色_Gloss("Gloss", Range(8.0, 256)) = 20 //高光区域大小 }SubShader {Tags {"RenderPipeline" = "UniversalPipeline" //用于URP的shader"Queue" = "Geometry" //URP中不再决定渲染顺序(以前是序号越小越先渲染), 而仅仅是一个类别id"RenderType" = "Opaque"}HLSLINCLUDE#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"//所有属性都要缓存到CBuffer中, 这样才能兼容SRP Batcher CBUFFER_START(UnityPerMaterial)float4 _BaseMap_ST;float4 _BaseColor;float4 _Specular;float _Gloss;CBUFFER_ENDENDHLSLPass {Tags { "LightMode" = "UniversalForward" } //该pass为渲染pass HLSLPROGRAM#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"#pragma vertex vert //指定顶点着色器函数#pragma fragment frag //指定片元着色器函数struct Attributes { //程序传入顶点着色器的数据float4 positionOS : POSITION; //用模型空间顶点坐标填充该变量float4 normalOS : NORMAL; //用模型空间法线方向填充该变量float2 uv : TEXCOORD0; //用模型的第一套纹理坐标(uv)填充该变量 };struct Varings { //顶点着色器传入片元着色器的数据float4 positionCS : SV_POSITION; //该变量存放了裁剪空间的顶点坐标 float2 uv : TEXCOORD0;float3 positionWS : TEXCOORD1;float3 viewDirWS : TEXCOORD2;float3 normalWS : TEXCOORD3;};//变量 TEXTURE2D(_BaseMap);SAMPLER(sampler_BaseMap);Varings vert(Attributes IN) { //顶点着色器 Varings OUT;VertexPositionInputs positionInputs = GetVertexPositionInputs(IN.positionOS.xyz); //顶点坐标从模型空间转其他空间OUT.positionCS = positionInputs.positionCS;OUT.positionWS = positionInputs.positionWS;OUT.viewDirWS = GetCameraPositionWS() - positionInputs.positionWS; //视角方向 VertexNormalInputs normalInputs = GetVertexNormalInputs(IN.normalOS.xyz);OUT.normalWS = normalize(normalInputs.normalWS); //法线方向 OUT.uv = TRANSFORM_TEX(IN.uv, _BaseMap); //应用贴图的tiling和offsetreturn OUT;}float4 frag(Varings IN) : SV_Target { //片元着色器(逐像素)//计算主光(逐像素)Light light = GetMainLight();float3 lightDirWS = light.direction;half3 diffuse = LightingLambert(light.color, lightDirWS, IN.normalWS); //lambert方法计算漫反射比例half3 specular = LightingSpecular(light.color, lightDirWS, normalize(IN.normalWS), normalize(IN.viewDirWS), _Specular, _Gloss); //Blinn-Phong方法计算高光//计算附加光照(逐像素)uint pixelLightCount = GetAdditionalLightsCount();for (uint lightIndex = 0; lightIndex < pixelLightCount; ++lightIndex) {Light light = GetAdditionalLight(lightIndex, IN.positionWS);//叠加附加光照diffuse += LightingLambert(light.color, light.direction, IN.normalWS);specular += LightingSpecular(light.color, light.direction, normalize(IN.normalWS), normalize(IN.viewDirWS), _Specular, _Gloss);}half4 texColor = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, IN.uv); //根据纹理坐标获取像素颜色half3 albedo = texColor.rgb * _BaseColor.rgb; //物体本身颜色的最大反射率half3 c = albedo * diffuse + specular;return float4(c, 1);}ENDHLSL} // Pass} // SubShader }
参考
URP基础光照 - 简书
【Unity Shader】在URP里写Shader(三):URP简单光照Shader - 知乎