阴影实现
Posted 就当笔记吧
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了阴影实现相关的知识,希望对你有一定的参考价值。
最终效果
1) 两个阴影重叠的时候,正常
2) 在斜坡上,阴影正常
3) 在平地上遇到障碍物,阴影正常
4) 在平台边缘,镂空的地方,阴影正常
5) 没有做阴影衰减
6) 阴影抗锯齿没做(pcf)
原理
ShadowMap阴影是一种实时阴影,其原理其实也很简单,就2步:1、投射阴影,2、接收阴影
1) 投射阴影,就是哪些物体会产生阴影,会把这些物体的深度保存到一张深度图中,这张深度图就叫ShadowMap。在光源位置放一个同方向的相机,就能生成这个深度图了。
2) 接收阴影,就是哪些物体在阴影中,会在其表面显示阴影。所以,核心就是判断物体是否在阴影中,物体自身的深度值 > ShadowMap中的深度值就说明在阴影中, 就会在表面绘制阴影。
实现
投射阴影用shader
Shader "My/Shadow/MyShadowCaster" SubShader Tags "RenderType" = "Opaque" Pass ZWrite On ZTest LEqual Cull Front CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct a2v float4 vertex : POSITION; ; struct v2f float4 pos : SV_POSITION; ; v2f vert(a2v v) v2f o; o.pos = UnityObjectToClipPos(v.vertex); //模型空间转换为裁剪空间 return o; fixed4 frag(v2f i) : SV_Target float depth = i.pos.z / i.pos.w; //w不为1时: 保证z在[-1, 1]范围内 #if defined(SHADER_TARGET_GLSL) depth = depth * 0.5 + 0.5; #elif defined(UNITY_REVERSED_Z) //DX11, DX12等这样的平台上, depth从1到0(解决浮点数精度和分布造成的Z-Fight闪烁问题) depth = 1 - depth; #endif return EncodeFloatRGBA(depth); ENDCG
相机生成ShadowMap逻辑
using UnityEngine; [RequireComponent(typeof(Camera))] public class ShadowMapCamera : MonoBehaviour public Transform m_DirLight; public Shader m_ShadowCaster; //负责将阴影信息投射到shadowMap public Transform m_Player; //跟随玩家 private Vector3 m_LastPlayerPos; [Range(0, 1)] public float m_ShadowStrength = 0; [Range(0, 2)] public float m_ShadowBias = 0; private Camera m_LightCamera; private RenderTexture m_ShadowMapTexture; private void Awake() m_LightCamera = GetComponent<Camera>(); if (null == m_ShadowCaster) m_ShadowCaster = Shader.Find("My/Shadow/MyShadowCaster"); void Start() ResetCamera(m_LightCamera); CreateShadowMapTexture(); m_LightCamera.transform.rotation = m_DirLight.rotation; //假定运行过程中光角度不变 Shader.SetGlobalFloat("_shadowBias", m_ShadowBias); Shader.SetGlobalFloat("_shadowStrength", m_ShadowStrength); UpdateLightCameraVPMatrix(); private void UpdateLightCameraVPMatrix() Matrix4x4 projMatrix = GL.GetGPUProjectionMatrix(m_LightCamera.projectionMatrix, false); Matrix4x4 vpMatrix = projMatrix * m_LightCamera.worldToCameraMatrix; //矩阵左乘 Shader.SetGlobalMatrix("_worldToShadow", vpMatrix); void Update() if (m_Player) var diff = m_Player.position - m_LastPlayerPos; if (diff.sqrMagnitude > 0) m_LastPlayerPos = m_Player.position; m_LightCamera.transform.position = m_LastPlayerPos; UpdateLightCameraVPMatrix(); m_LightCamera.RenderWithShader(m_ShadowCaster, ""); //使用阴影投射shader渲染视野范围内的所有物体 private void ResetCamera(Camera lightCamera) lightCamera.backgroundColor = Color.white; lightCamera.clearFlags = CameraClearFlags.SolidColor; lightCamera.orthographic = true; lightCamera.orthographicSize = 6f; lightCamera.nearClipPlane = -10; lightCamera.farClipPlane = 10f; lightCamera.enabled = false; lightCamera.allowMSAA = false; lightCamera.allowHDR = false; lightCamera.cullingMask = -1; private void UpdateShadowMapTexture() if (null != m_ShadowMapTexture) m_LightCamera.targetTexture = null; RenderTexture.ReleaseTemporary(m_ShadowMapTexture); m_ShadowMapTexture = null; CreateShadowMapTexture(); private void CreateShadowMapTexture() m_ShadowMapTexture = new RenderTexture(1024, 1024, 16, RenderTextureFormat.RGFloat); m_ShadowMapTexture.name = "Shadowmap_RGFloat"; m_ShadowMapTexture.hideFlags = HideFlags.DontSave; m_ShadowMapTexture.wrapMode = TextureWrapMode.Clamp; m_ShadowMapTexture.filterMode = FilterMode.Bilinear; m_LightCamera.targetTexture = m_ShadowMapTexture; Shader.SetGlobalTexture("_MyShadowMapTexture", m_ShadowMapTexture);
加了接收阴影逻辑的shader
Shader "My/Shadow/DiffusePerPixel_ShadowReceive" Properties _MainTex("Main Tex", 2D) = "white" _Color("Tint", Color) = (1, 1, 1, 1) //贴图颜色色调 SubShader Pass Tags "LightMode" = "ForwardBase" //设置了LightMode=ForwardBase时, 内置变量_WorldSpaceLightPos0才被赋值 CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" #include "Lighting.cginc" struct appdata float4 vertex : POSITION; float3 normal : NORMAL; //顶点法线 float2 texcoord : TEXCOORD0; ; struct v2f float4 pos : SV_POSITION; float2 uv : TEXCOORD0; float3 worldNormal : TEXCOORD1; float4 worldPos : TEXCOORD2; float4 shadowCoord : TEXCOORD3; ; sampler2D _MainTex; float4 _MainTex_ST; fixed4 _Color; //********** 用于阴影Receive float4x4 _worldToShadow; sampler2D _MyShadowMapTexture; //shadowMap贴图 float _shadowStrength; //阴影强度 float _shadowBias; //Shadow Acne问题需要 //********** v2f vert(appdata v) v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); o.worldNormal = UnityObjectToWorldNormal(v.normal); o.worldPos = mul(unity_ObjectToWorld, v.vertex); o.shadowCoord = mul(_worldToShadow, o.worldPos); //LightCamera的VP_Matrix return o; float hardShadow(float4 shadowCoord) float2 uv = shadowCoord.xy / shadowCoord.w; uv = uv * 0.5 + 0.5; float depth = shadowCoord.z / shadowCoord.w; //w不为1时: 保证z在[-1, 1]范围内 #if defined(SHADER_TARGET_GLSL) depth = depth * 0.5 + 0.5; #elif defined(UNITY_REVERSED_Z) depth = 1 - depth; #endif float4 orignDepth = tex2D(_MyShadowMapTexture, uv); float sampleDepth = DecodeFloatRGBA(orignDepth); return (sampleDepth + _shadowBias) < depth ? _shadowStrength : 1; //shadowMap中z值更远就不在阴影中, 返回1 fixed4 frag(v2f i) : SV_Target fixed3 worldNormal = normalize(i.worldNormal); fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz); //主光源方向 fixed4 c = tex2D(_MainTex, i.uv); fixed3 albedo = c.rgb * _Color.rgb; fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo; //环境光 fixed lambert = max(0, dot(worldNormal, worldLightDir)); //漫反射计算公式 fixed3 diffuse = _LightColor0.rgb * albedo * lambert; fixed atten = 1.0; //这边没处理衰减, 暂时固定1 float shadow = 1.0; shadow = hardShadow(i.shadowCoord); return fixed4(ambient + diffuse * shadow * atten, 1.0); ENDCG
相关设置
相关链接
实时渲染-阴影渲染实现(Unity) - 知乎 (zhihu.com)
阴影进阶,实现更加的立体的阴影效果!
CSS 阴影的存在,让物体看上去更加有型立体。 然而,在最简单的阴影使用之上,我们可以实现更多有意思且更加立体的阴影效果。 本文将带大家看看如何使用 CSS 实现几类比普通阴影更加立体的阴影效果。 CSS 阴影基础 CSS 中,明面上可以实现阴影的有三个属性: box-shadow - 盒阴影 te
以上是关于阴影实现的主要内容,如果未能解决你的问题,请参考以下文章