一、Directional Lights
物体的光照(Lighting) = Surface(材质表面属性) 与 Light 的交互
- BRDF 解释 surface 与 light 交互过程中有多少光线被反射出去,即将 surface.color 分解成 diffuse 和 specular
- 入射能量 = 反射光线能量 + 漫反射光线能量
- 最终反射进入人眼睛的反射光线 = 反射光线能量 和 观察方向有关(公式见下图 【Unity 高光强度计算公式】)
- 金属材质会完全反射光线,非金属则基本上不会反射光线,介点介质影响(大概反射0.04)
- PBR金属工作流程,Albedo = 非金属 diffuse 颜色 + 金属 Specular 颜色
unity 高光的计算公式

管线中可见光获取
NativeArray<VisibleLight> visibleLights = cullingResults.visibleLights;
可变长度的 For 循环在 OpenGL ES 2.0 and WebGL 1.0 graphics APIs 中不支持
#pragma target 3.5
完整代码
- Lighting.hlsl
#ifndef CUSTOM_LIGHTING_INCLUDED
#define CUSTOM_LIGHTING_INCLUDED
bool RenderingLayersOverlap (Surface surface, Light light)
{
//OpenGL ES 2.0 及以下不支持位操作,其他支持
return (surface.renderingLayerMask & light.renderingLayerMask) != 0;
}
float3 IncomingLight(Surface surface, Light light)
{
return saturate(dot(surface.normal, light.direction)) * light.attenuation * light.color;
}
float3 GetLighting(Surface surface, BRDF brdf, Light light)
{
return IncomingLight(surface, light) * DirectBRDF(surface, brdf, light);
}
float3 GetLighting(Surface surfaceWS, BRDF brdf, GI gi)
{
ShadowData shadowData = GetShadowData(surfaceWS);
shadowData.shadowMask = gi.shadowMask;
float3 color = IndirectBRDF(surfaceWS, brdf, gi.diffuse, gi.specular);
for (int i = 0; i < GetDirectionalLightCount(); i++)
{
Light light = GetDirectionLight(i, surfaceWS, shadowData);
if (RenderingLayersOverlap(surfaceWS, light))
{
color += GetLighting(surfaceWS, brdf, light);
}
}
return color;
}
#endif
- BRDF.hlsl
#ifndef CUSTOM_BRDF_INCLUDED
#define CUSTOM_BRDF_INCLUDED
#define MIN_REFLECTIVITY 0.04
struct BRDF
{
float3 diffuse;
float3 specular;
float roughness;
float perceptualRoughness;
float fresnel;
};
float OneMinusReflectivity(float metallic)
{
float range = 1.0 - MIN_REFLECTIVITY;
return (range - metallic * range);
}
BRDF GetBRDF(Surface surface, bool applyAlphaToDiffuse = false)
{
BRDF brdf = (BRDF)0;
float oneMinusReflectivity = OneMinusReflectivity(surface.metallic);
brdf.diffuse = surface.color * oneMinusReflectivity;
if (applyAlphaToDiffuse)
{
//通过下面的方法,解决高光反射也会在 blend 中减淡的问题
//更改blend srcAlpha oneMinusSrcAlpha 为 Blend One oneMinusSrcAlpha。并且 premultiplied alpha
brdf.diffuse *= surface.alpha;
}
//因为金属基本没有diffuse,金属会影响高光颜色,不同金属会有不同的高光颜色。金属工作流程中,surface.color 金属部分绘制的是高光颜色
//非金属的反射颜色为白色,白色 * MIN_REFLECTIVITY(非金属最小的反射率) = MIN_REFLECTIVITY
brdf.specular = lerp(MIN_REFLECTIVITY, surface.color, surface.metallic);
brdf.perceptualRoughness = PerceptualSmoothnessToPerceptualRoughness(surface.smoothness);
brdf.roughness = PerceptualRoughnessToRoughness(brdf.perceptualRoughness); //matches the Disney lighting model
brdf.fresnel = saturate(surface.smoothness + 1.0 - oneMinusReflectivity);
return brdf;
}
float SpecularStrength(Surface surface, BRDF brdf, Light light)
{
float3 h = SafeNormalize(light.direction + surface.viewDirection);
float nh2 = Square(saturate(dot(surface.normal, h)));
float lh2 = Square(saturate(dot(light.direction, h)));
float r2 = Square(brdf.roughness);
float d2 = Square(nh2 * (r2 - 1.0) + 1.00001);
float normalization = brdf.roughness * 4 + 2;
return r2 / (d2 * max(0.1, lh2) * normalization);
}
float3 DirectBRDF(Surface surface, BRDF brdf, Light light)
{
return SpecularStrength(surface, brdf, light) * brdf.specular + brdf.diffuse;
}
float3 IndirectBRDF(Surface surface, BRDF brdf, float3 diffuse, float3 specular)
{
float fresnelStrength = surface.fresnelStrength * Pow4(1.0 - saturate(dot(surface.normal, surface.viewDirection)));
float3 reflection = specular * lerp(brdf.specular, brdf.fresnel, fresnelStrength);
reflection /= brdf.roughness * brdf.roughness + 1.0;
return (diffuse * brdf.diffuse + reflection) * surface.occlusion;
}
#endif
二、Custom Shader GUI
结构:
using UnityEditor;
using UnityEngine;
using UnityEngine.Rendering;
public class CustomShaderGUI : ShaderGUI
{
private MaterialEditor _editor;
private Object[] _materials;
private MaterialProperty[] _properties;
public override void OnGUI (MaterialEditor materialEditor, MaterialProperty[] properties)
{
base.OnGUI(materialEditor, properties);
_editor = materialEditor;
_materials = materialEditor.targets;
_properties = properties;
}
}
判断某个属性是否存在
private bool HasProperty(string name)
{
return FindProperty(name, _properties, false) != null;
}
设置属性
private bool SetProperty(string name, float value)
{
MaterialProperty property = FindProperty(name, _properties, false);
if (property != null)
{
property.floatValue = value;
return true;
}
return false;
}
显示多个不同值的情况
EditorGUI.showMixedValue = property.hasMultipleDifferentValues;
显示自发光属性
_editor.LightmapEmissionProperty();
Shader 中启用
Shader "CustomRP/Lit"
{
Properties{...}
SubShader{...}
CustomEditor "CustomRP.Editor.CustomShaderGUI"
}