组件
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[ExecuteInEditMode]
public class ProjectorAndDecal : MonoBehaviour
{
/// 近平面
public float nearClipPlane = 0.1f;
/// 远平面
public float farClipPlane = 100;
/// 横纵比
public float aspectRatio = 1;
/// 正交投影框大小
public float size = 10;
/// 材质
public Material material;
/// 视图盒
private Transform viewBox;
/// 自身的网格处理器
private MeshFilter meshFilter;
/// 自身的渲染器
private MeshRenderer meshRenderer;
private void OnValidate()
{
GenerateViewBox();
}
/// 生成投影范围
private void GenerateViewBox()
{
viewBox = transform.Find("ViewBox");
if (viewBox == null)
{
viewBox = GameObject.CreatePrimitive(PrimitiveType.Cube).transform;
DestroyImmediate(viewBox.GetComponent());
viewBox.SetParent(transform);
viewBox.name = "ViewBox";
}
if (viewBox != null)
{
meshFilter = viewBox.GetComponent();
meshRenderer = viewBox.GetComponent();
if (material != null)
{
meshRenderer.sharedMaterial = material;
}
}
viewBox.localScale = new Vector3(aspectRatio * size, size, farClipPlane - nearClipPlane);
viewBox.localPosition = new Vector3(0, 0, farClipPlane * 0.5f + nearClipPlane * 0.5f);
}
private void OnDrawGizmos()
{
if (meshFilter != null)
{
Gizmos.color = Color.red;
Gizmos.DrawSphere(transform.position, size * 0.05f);
Gizmos.color = Color.white;
Gizmos.DrawWireMesh(meshFilter.sharedMesh, viewBox.position, viewBox.rotation, viewBox.localScale);
}
}
}
Shader
法一:根据流水线求交互物体的UV
Shader "LSQ/EffectAchievement/ProjectorAndDecal_2"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
Tags
{
"RenderType"="Transparent"
"Queue"="Transparent"
"IgnoreProjector"="true"
"DisableBatching"="true"
}
Blend SrcAlpha OneMinusSrcAlpha
ZWrite Off
Cull Off
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
};
struct v2f
{
float4 vertex : SV_POSITION;
float4 screenPos : TEXCOORD0;
};
sampler2D _MainTex;
sampler2D _CameraDepthTexture;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.screenPos = ComputeScreenPos(o.vertex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed2 screenPos = i.screenPos.xy / i.screenPos.w;
//视图空间的深度值
float depth = tex2D(_CameraDepthTexture, screenPos).r;
//根据深度值重建世界坐标:直接逆着流水线求世界坐标
//裁剪空间
fixed4 clipPos = fixed4(screenPos.x * 2 - 1, screenPos.y * 2 - 1, -depth * 2 + 1, 1) * LinearEyeDepth(depth);
//还原回相机空间
float4 viewPos = mul(unity_CameraInvProjection, clipPos);
//还原回世界空间 unity_MatrixInvV = UNITY_MATRIX_I_V unity_CameraToWorld
float4 worldPos = mul(unity_MatrixInvV, viewPos);
//转为相对于本物体的局部坐标(变换矩阵都被抵消了)
float3 objectPos = mul(unity_WorldToObject, worldPos).xyz;
//立方体本地坐标-0.5~0.5
clip(0.5 - abs(objectPos));
//本地坐标中心点为0,而UV为0.5
objectPos += 0.5;
fixed4 col = tex2D(_MainTex, objectPos.xy);
return col;
}
ENDCG
}
}
}
法二:根据摄像机位置求交互物体的UV
Shader "LSQ/EffectAchievement/ProjectorAndDecal_1"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
Tags
{
"RenderType"="Transparent"
"Queue"="Transparent"
"IgnoreProjector"="true"
"DisableBatching"="true"
}
Blend SrcAlpha OneMinusSrcAlpha
ZWrite Off
Cull Off
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
};
struct v2f
{
float4 vertex : SV_POSITION;
float4 screenPos : TEXCOORD0;
float3 ray : TEXCOORD1;
};
sampler2D _MainTex;
sampler2D _CameraDepthTexture;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.screenPos = ComputeScreenPos(o.vertex);
o.ray = mul(unity_ObjectToWorld, v.vertex) - _WorldSpaceCameraPos;
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed2 screenPos = i.screenPos.xy / i.screenPos.w;
//视图空间的深度值
float depth = LinearEyeDepth(tex2D(_CameraDepthTexture, screenPos).r);
//根据深度值重建世界坐标
float3 worldRay = normalize(i.ray);
//float3 worldPos = _WorldSpaceCameraPos + worldRay * depth;
//裁剪空间的线性深度值和视图空间的不一致
worldRay /= dot(worldRay, -UNITY_MATRIX_V[2].xyz);
float3 worldPos = _WorldSpaceCameraPos + worldRay * depth;
//转为相对于本物体的局部坐标(变换矩阵都被抵消了)
float3 objectPos = mul(unity_WorldToObject, float4(worldPos,1)).xyz;
//立方体本地坐标-0.5~0.5
clip(0.5 - abs(objectPos));
//本地坐标中心点为0,而UV为0.5
objectPos += 0.5;
fixed4 col = tex2D(_MainTex, objectPos.xy);
return col;
}
ENDCG
}
}
}



