栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 游戏开发 > Unity3D

Unity 贴花/喷漆功能的原理、Projector组件的原理与优化

Unity3D 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Unity 贴花/喷漆功能的原理、Projector组件的原理与优化

组件

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
        }
    }
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/898419.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号