做影视网站用的封面/举例网络营销的例子
ShadowMap的原理就是在灯光空间渲染出一张RenderTexture 记录物体顶点在灯光空间中的深度值,在渲染地面的时候 使用顶点计算在灯光空间中的深度 ,再与深度图中的值进行比较>则是阴影
1、渲染深度图使用的shader——一定要放在Resources
Shader "ZLY/DeapthTextureShader"
{SubShader{Tags { "RenderType"="Opaque" }LOD 100Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"struct appdata{float4 vertex : POSITION;};struct v2f{float4 vertex : SV_POSITION;float2 depth:TEXCOORD1;};sampler2D _MainTex;float4 _MainTex_ST;float4x4 zly_ProjectionMatrix;v2f vert (appdata v){v2f o;o.vertex = UnityObjectToClipPos(v.vertex);//模型空间转裁剪空间//o.depth=o.vertex.zw; 坐标空间转换后会产生深度误差 所以使用相同的深度转换方式zly_ProjectionMatrix = mul(zly_ProjectionMatrix, unity_ObjectToWorld); o.depth = mul(zly_ProjectionMatrix,v.vertex).zw;return o;}fixed4 frag (v2f i) : SV_Target{float depth =i.depth.x/i.depth.y;
#if defined(UNITY_REVERSED_Z)depth = 1.0f - depth;//转成齐次空间坐标 [1,0]变成[0,1]
#endiffixed4 col = EncodeFloatRGBA(depth);// float四个字节 存RGBreturn col;}ENDCG}}
}
2、顶点深度比较 放在要渲染的物体上
Shader "ZLY/ShadowOnShader"
{Properties{_MainTex ("Texture", 2D) = "white" {}}SubShader{Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"sampler2D _MainTex;float4 _MainTex_ST;// sampler2D unity_Lightmap;//若开启光照贴图,系统默认填值// float4 unity_LightmapST;//与上unity_Lightmap同理struct v2f {float4 pos:SV_POSITION;float2 uv:TEXCOORD0;float2 uv2:TEXCOORD1; float4 proj : TEXCOORD3;};float4x4 zly_ProjectionMatrix;//世界空间转灯关空间矩阵sampler2D zly_DepthTexture;//深度图v2f vert(appdata_full v){v2f o;o.pos = UnityObjectToClipPos(v.vertex);//动态阴影zly_ProjectionMatrix = mul(zly_ProjectionMatrix, unity_ObjectToWorld);//模型空间转世界空间转灯关空间o.proj = mul(zly_ProjectionMatrix, v.vertex);//--------------------------------------------------o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);//偏移压缩后的像素取点位置o.uv2 = v.texcoord1.xy * unity_LightmapST.xy + unity_LightmapST.zw; return o;}fixed4 frag(v2f v) : COLOR{//解密光照贴图计算公式float3 lightmapColor = DecodeLightmap(UNITY_SAMPLE_TEX2D(unity_Lightmap,v.uv2));fixed4 col = tex2D(_MainTex, v.uv);col.rgb *= lightmapColor;float depth = v.proj.z/v.proj.w;//齐次坐标深度值
#if defined(UNITY_REVERSED_Z)depth = 1.0f - depth;//转成齐次空间坐标 [1,0]变成[0,1]
#endiffixed4 dcol = tex2Dproj(zly_DepthTexture, v.proj);//转齐次坐标后uvfloat d = DecodeFloatRGBA(dcol);//RGB转floatfloat shadowScale = 1;if(depth > d){shadowScale = 0.55;}return col*shadowScale;}ENDCG}}
}
3、调用Shader的脚本
using UnityEngine;
using System.Collections;/// <summary>
/// 创建depth相机
/// by lijia
/// </summary>
public class DepthTextureCamera : MonoBehaviour
{private static DepthTextureCamera _inst;public static DepthTextureCamera Instance() { return _inst; }private Transform _target;public Camera _camera;private RenderTexture _rt;/// <summary>/// 光照的角度/// </summary>//public Transform lightTrans;Matrix4x4 sm = new Matrix4x4();private float _xOffset = 0f;private float _yOffset = 20f;private float _zOffset = 20f;void Awake(){_inst = this;}void Start(){//_camera = new GameObject().AddComponent<Camera>();//_camera.name = "DepthCamera";//_camera.depth = 0;//_camera.clearFlags = CameraClearFlags.SolidColor;//_camera.backgroundColor = new Color(1, 1, 1, 0);//_camera.cullingMask = LayerMask.GetMask("Player");//_camera.aspect = 1;//_camera.transform.parent = lightTrans.transform;//_camera.transform.localPosition = Vector3.left * 15;//_camera.transform.localEulerAngles = Vector3.up*30;//_camera.orthographic = true;//_camera.orthographicSize = 10;sm.m00 = 0.5f;sm.m11 = 0.5f;sm.m22 = 0.5f;sm.m03 = 0.5f;sm.m13 = 0.5f;sm.m23 = 0.5f;sm.m33 = 1;_rt = new RenderTexture(2048, 2048, 0);_rt.wrapMode = TextureWrapMode.Clamp;_camera.targetTexture = _rt;_camera.SetReplacementShader(Shader.Find("ZLY/DeapthTextureShader"), "RenderType");} void Update(){if(_target==null){return;}HELPER_VEC.Set(_target.position.x + _xOffset, _target.position.y + _yOffset,_target.position.z + _zOffset);this.transform.position = HELPER_VEC;//transform.LookAt(_target.position);//世界顶点坐标转换到_camera裁剪空间坐标矩阵 sm[-1,1]转换到[0,1]转换矩阵Matrix4x4 tm = GL.GetGPUProjectionMatrix(_camera.projectionMatrix, false) * _camera.worldToCameraMatrix;tm = sm * tm;Shader.SetGlobalMatrix("zly_ProjectionMatrix", tm);}private static Vector3 HELPER_VEC = new Vector3();public void SetTarget(Transform target,ushort mapID) { _target = target;HELPER_VEC.Set(60, -123, 0);//设置光照方向 transform.position = _target.position;transform.eulerAngles = HELPER_VEC;transform.position -= transform.forward * 40;_xOffset = transform.position.x - _target.position.x;_yOffset = transform.position.y - _target.position.y;_zOffset = transform.position.z - _target.position.z;Matrix4x4 tm = GL.GetGPUProjectionMatrix(_camera.projectionMatrix, false) * _camera.worldToCameraMatrix;tm = sm * tm;Shader.SetGlobalMatrix("zly_ProjectionMatrix", tm);Shader.SetGlobalTexture("zly_DepthTexture", _rt);Shader.SetGlobalFloat("zly_Shadow", 1);}
}
在顶点坐标从模型空间转换到灯光空间时,深度会发生偏移,不同的相机旋转角度offset不同
使用:
o.vertex = UnityObjectToClipPos(v.vertex);//o.depth=o.vertex.zw;
改为使用:——此方法会产生偏移
//世界顶点坐标转换到_camera裁剪空间坐标矩阵 sm[-1,1]转换到[0,1]转换矩阵Matrix4x4 tm = GL.GetGPUProjectionMatrix(_camera.projectionMatrix, false) * _camera.worldToCameraMatrix;tm = sm * tm;Shader.SetGlobalMatrix("zly_ProjectionMatrix", tm);zly_ProjectionMatrix = mul(zly_ProjectionMatrix, unity_ObjectToWorld); o.depth = mul(zly_ProjectionMatrix,v.vertex).zw;
是为了使比较的depth使用相同的空间转换方式 产生相同的差值