【Unity3D】实现Decal贴花效果,模拟战旗游戏地形效果

news2025/1/29 21:29:23

目录

一、基础版

二、Post Process 辉光Bloom效果 + 矩形渐隐


涉及知识点:Decal贴花、屏幕后处理Bloom、屏幕空间构建世界空间、ChracterController物体移动、Terrain地形创建

一、基础版

Unity 2019.4.0f1 普通渲染管线(非URP、非HDRP)
URP HDRP 在Unity 2021.2以上均可直接使用内置的贴花系统,具体网上有说明。

贴花物体是一个个Cube立方体,我将它拉长了Y轴 便于能接触到地面。

其中角色物体胶囊体要进行设置渲染层级,GetComponent<MeshRenderer>().material.renderQueue = 3001; //将人物放到贴花物体之后渲染,不被贴花物体影响

如这个Cube长方体就是红色边缘的Cube贴花,贴花颜色是红色。

贴花物体是透明层,不写入深度和深度检测,以及裁剪正面,不裁剪背面。

可参考:贴花(Decal)效果在Shader里是如何实现的_哔哩哔哩_bilibili

核心代码是DepthToWorldPosition,屏幕空间反向构建世界空间,很类似全局雾效,注意摄像机要开启深度贴图。摄像机挂上这个如下脚本设置:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class OpenDepthTexture : MonoBehaviour
{
    public DepthTextureMode mode;
    private void Awake()
    {
        GetComponent<Camera>().depthTextureMode = mode;
    }
}

Shader "Unlit/SimpleDecal"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _Color ("Color", Color) = (1,1,1,1)
    }
    SubShader
    {
        Tags { "RenderType"="Transparent" "Queue"="Transparent" }
        LOD 100

        Pass
        {
            //Blend One DstAlpha
            Blend SrcAlpha OneMinusSrcAlpha
            //Blend One One
            ZWrite Off
            ZTest Off
            Cull Front 
            
            
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
                float4 screenPos : TEXCOORD3;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            sampler2D _CameraDepthTexture;
            fixed4 _Color;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                o.screenPos = ComputeScreenPos(o.vertex);
                return o;
            }

            float3 DepthToWorldPosition(float4 screenPos)
            {
                float depth = Linear01Depth(UNITY_SAMPLE_DEPTH(tex2Dproj(_CameraDepthTexture,screenPos)));//线性深度值
                float4 ndcPos = (screenPos/screenPos.w) * 2 - 1;  //除以w是归一化Unity提供的屏幕坐标[0,1]  *2-1操作 转[-1,1]得到ndc(仅有x,y有效位)
                float3 clipPos = float3(ndcPos.x, ndcPos.y, 1) * _ProjectionParams.z;  //ndc补z位,直接用1 远平面值,之后乘以far远平面距离得到裁剪坐标
                //clipPos还缺一个w,实际z值就是w值故完整clipPos是(clipPos.xyzz) 再直接转视图空间得到远平面的视图空间坐标点(即Depth为1的点)                
                float3 viewPos = mul(unity_CameraInvProjection, clipPos.xyzz).xyz * depth; //*depth相当于一个Lerp操作,depth是[0,1]范围的值,取到depth深度的视图点
                float3 worldPos = mul(UNITY_MATRIX_I_V,float4(viewPos, 1)).xyz; //视图转世界坐标
                return worldPos;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                float3 worldPos = DepthToWorldPosition(i.screenPos);
                float4 localPos = mul(unity_WorldToObject, float4(worldPos, 1.0));
                clip(float3(0.5,0.5,0.5) - abs(localPos.xyz));

                fixed2 decalUV = fixed2(localPos.x, localPos.z);
                decalUV = decalUV + 0.5; //模型空间 [-0.5,0.5] => [0,1] uv空间
                fixed4 color = tex2D(_MainTex, decalUV) * _Color;
                return color;
            }
            ENDCG
        }
    }
}

玩家胶囊体脚本:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Player3D : MonoBehaviour
{
    public GameObject greenPrefab;
    public GameObject redPrefab;
    public int size = 5;

    public Terrain terrain;

    private CharacterController characterController;
    private float h;
    private float v;
    private float verticalVelocity;
    public float moveSpeed = 1;


    // Start is called before the first frame update
    void Start()
    {
        Vector3 pos = transform.position;
        int halfSize = Mathf.FloorToInt(size / 2);
        for (int i = -halfSize; i <= halfSize; i++)
        {
            for (int j = -halfSize; j <= halfSize; j++)
            {
                int v = Mathf.Abs(i) + Mathf.Abs(j);
                if (v <= halfSize)
                {
                    GameObject go = GameObject.Instantiate(v == halfSize ? redPrefab : greenPrefab, transform);
                    go.transform.position = new Vector3(pos.x + i, pos.y, pos.z + j);
                }
            }
        }
        characterController = GetComponent<CharacterController>();

        GetComponent<MeshRenderer>().material.renderQueue = 3001; //将人物放到贴花物体之后渲染,不被贴花物体影响
    }



    private void Update()
    {
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");

        Vector3 moveDir = transform.forward * v + transform.right * h;

        if (!characterController.isGrounded)
        {
            verticalVelocity -= 9.8f * Time.deltaTime;
            moveDir.y = verticalVelocity;
        }
        else
        {
            verticalVelocity = -0.5f;
        }

        characterController.Move(moveDir * moveSpeed * Time.deltaTime);
    }
}

二、Post Process 辉光Bloom效果 + 矩形渐隐

Package Manager导入Post Processing


需确保摄像机开启HDR,查看相应的Graphics Settings设置

如果你的是安卓环境,那么就要去看安卓下的HDR是否开启,如果你是URP、HDRP,则是看对应管线资源的配置是否有开启HDR。

摄像机挂上后处理组件 Post-process Layer,并设置摄像机和Layer要勾选我们想要辉光效果的层级,例如自定义的HDR层

创建一个PostProcess空物体,添加如下图组件Post-process Volume,并且设置它的Layer为HDR

点击组件的New按钮会创建一个Profile资源,再点击Add effect... 添加Unity -> Bloom曝光效果

设置Intensity强度适当5~10左右
Threshold阈值[0,1]范围保持默认即可(如果你设置大于1会导致曝光效果几乎没有)
Soft Knee 软曝光?可以自定义
Diffusion 漫反射,当曝光的地形在有漫反射的物体上时会叠加漫反射的强度好像,反正我不需要拉到最左边即可(即1)其他请自行研究,如下图即可得到gif图效果,如果没有辉光说明Layer层级设置不对,所有需要辉光的物体都要设置Layer层级是HDR(由Post-process Layer指定的层级)

贴花Shader脚本修改如下:

Shader "Unlit/SimpleDecal"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        [HDR]
        _Color ("Color", Color) = (1,1,1,1)
        _Range ("Range", Range(0,0.5)) = 0.45
        _FadeIntensity ("Fade Intensity", float) = 2
    }
    SubShader
    {
        Tags { "RenderType"="Transparent" "Queue"="Transparent" }
        LOD 100

        Pass
        {
            Blend SrcAlpha OneMinusSrcAlpha
            ZWrite Off
            ZTest Off
            Cull Front
            
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
                float4 screenPos : TEXCOORD3;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            sampler2D _CameraDepthTexture;
            fixed4 _Color;
            float _Range;
            float _FadeIntensity;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                o.screenPos = ComputeScreenPos(o.vertex);
                return o;
            }

            float3 DepthToWorldPosition(float4 screenPos)
            {
                float depth = Linear01Depth(UNITY_SAMPLE_DEPTH(tex2Dproj(_CameraDepthTexture,screenPos)));//线性深度值
                float4 ndcPos = (screenPos/screenPos.w) * 2 - 1;  //除以w是归一化Unity提供的屏幕坐标[0,1]  *2-1操作 转[-1,1]得到ndc(仅有x,y有效位)
                float3 clipPos = float3(ndcPos.x, ndcPos.y, 1) * _ProjectionParams.z;  //ndc补z位,直接用1 远平面值,之后乘以far远平面距离得到裁剪坐标
                //clipPos还缺一个w,实际z值就是w值故完整clipPos是(clipPos.xyzz) 再直接转视图空间得到远平面的视图空间坐标点(即Depth为1的点)                
                float3 viewPos = mul(unity_CameraInvProjection, clipPos.xyzz).xyz * depth; //*depth相当于一个Lerp操作,depth是[0,1]范围的值,取到depth深度的视图点
                float3 worldPos = mul(UNITY_MATRIX_I_V,float4(viewPos, 1)).xyz; //视图转世界坐标
                return worldPos;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                float3 worldPos = DepthToWorldPosition(i.screenPos);
                float4 localPos = mul(unity_WorldToObject, float4(worldPos, 1.0));
                clip(float3(0.5,0.5,0.5) - abs(localPos.xyz));

                fixed2 decalUV = fixed2(localPos.x, localPos.z);
                decalUV = decalUV + 0.5; //模型空间 [-0.5,0.5] => [0,1] uv空间
                fixed4 color = tex2D(_MainTex, decalUV) * _Color;

                //由外到内渐隐 (圆形渐隐)
                //float2 center = float2(0.5, 0.5);
                //float alpha = lerp(0, distance(float2(0,0), center), distance(decalUV, center));
                //color.a *= alpha;

                //由外到内渐隐(矩形渐隐)
                fixed2 uv = decalUV - 0.5; //转[-0.5,0.5]空间 方便计算
                float x = abs(uv.x) - _Range;
                float y = abs(uv.y) - _Range;               
                //float sum = x+y ;//max(0, x) + max(0, y);
                float sum = max(x, y);
                //color.a *= smoothstep(0, (0.5 - _Range) * 2, sum);
                color.a *= smoothstep(0, (0.5 - _Range) * _FadeIntensity, sum);
                return color;
            }
            ENDCG
        }
    }
}

有些bug就是Scene场景看不到贴花地形了,暂时没研究处来是啥情况

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2285123.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

实践网络安全:常见威胁与应对策略详解

&#x1f4dd;个人主页&#x1f339;&#xff1a;一ge科研小菜鸡-CSDN博客 &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; 引言 在数字化转型的浪潮中&#xff0c;网络安全的重要性已达到前所未有的高度。无论是个人用户、企业&#xff0c;还是政府机构…

UART、I2C和SPI对比

UARTSPII2C英文Universal Asynchronous Receive/TransmitSerial Peripheral InterfaceInner Integrated Communication通讯速度115200、38400 bit/s高达100M bit/s 100k、400k、1M、3.4M bit/s时钟同/异步性时钟异步时钟同步时钟同步接线方式3线(Rx、Tx、GND) 4线(MISO、…

开源项目Umami网站统计MySQL8.0版本Docker+Linux安装部署教程

Umami是什么&#xff1f; Umami是一个开源项目&#xff0c;简单、快速、专注用户隐私的网站统计项目。 下面来介绍如何本地安装部署Umami项目&#xff0c;进行你的网站统计接入。特别对于首次使用docker的萌新有非常好的指导、参考和帮助作用。 Umami的github和docker镜像地…

KIMI K1.5:用大语言模型扩展强化学习(论文翻译)

文章目录 KIMI K1.5技术报告摘要 1. 引言2. 方法&#xff1a;基于大语言模型的强化学习2.1 强化学习提示集整理2.2 长思维链监督微调2.3 强化学习2.3.1 问题设定2.3.2 策略优化2.3.3 长度惩罚2.3.4 采样策略2.3.5 训练方法的更多细节 2.4 长到短&#xff1a;短思维链模型的上下…

思科交换机telnet配置案例

目录 1.telnet简述2.网络拓扑3.设备说明4.网络配置4.1 电脑PC ip设置4.2 网络交换机telnet配置 5.小结 1.telnet简述 Telnet是远程登录服务的一个协议&#xff0c;该协议定义了远程登录用户与服务器交互的方式。它允许用户在一台联网的计算机上登录到一个远程分时系统中&#…

计算机毕业设计Django+Tensorflow音乐推荐系统 机器学习 深度学习 音乐可视化 音乐爬虫 知识图谱 混合神经网络推荐算法 大数据毕设

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

基于蓝牙6.0的RSSI和UWB融合定位方法,可行性分析

融合RSSI&#xff08;接收信号强度指示&#xff09;和UWB&#xff08;超宽带&#xff09;两种技术进行蓝牙6.0定位是完全可行的&#xff0c;并且可以带来更高的定位精度和稳定性。本文给出分析和MATLAB仿真结果 文章目录 技术优势RSSIUWB融合的优势 实现方案数据融合算法硬件要…

【开源免费】基于Vue和SpringBoot的在线文档管理系统(附论文)

本文项目编号 T 038 &#xff0c;文末自助获取源码 \color{red}{T038&#xff0c;文末自助获取源码} T038&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析 六、核心代码6.1 查…

AI DeepSeek

DeepSeek 文字解析 上传图片解析 视乎结果出入很大啊&#xff0c;或许我们应该描述更加清楚自己的需求。

QT使用eigen

QT使用eigen 1. 下载eigen https://eigen.tuxfamily.org/index.php?titleMain_Page#Download 下载后解压 2. QT引入eigen eigen源码好像只有头文件&#xff0c;因此只需要引入头文件就好了 qt新建项目后。修改pro文件. INCLUDEPATH E:\222078\qt\eigen-3.4.0\eigen-3.…

mysql学习笔记-数据库其他调优策略

1、如何定位调优问题 用户的反馈&#xff08;主要&#xff09; 日志分析&#xff08;主要&#xff09; 服务器资源使用监控 数据库内部状况监控 2、调优的维度和步骤 第1步&#xff1a;选择适合的 DBMS 第2步&#xff1a;优化表设计 第3步&#xff1a;优化逻辑查询 第4步&am…

HTB:Forest[WriteUP]

连接至HTB服务器并启动靶机 分配IP&#xff1a;10.10.16.21 靶机IP&#xff1a;10.10.10.161 靶机Domain&#xff1a;forest.htb 目录 连接至HTB服务器并启动靶机 信息收集 使用rustscan对靶机TCP端口进行开放扫描 将靶机TCP开放端口号提取并保存 使用nmap对靶机TCP开放端…

物业软件推动物业行业数字化转型 实现高效管理和优质客户体验

内容概要 在当今高速发展的数字化时代&#xff0c;物业软件的出现不仅使物业管理变得更加高效&#xff0c;也为行业转型提供了强大的支持。通过整合多种功能&#xff0c;物业软件显著提升了管理效率和客户体验。例如&#xff0c;在线收费和停车管理功能&#xff0c;让业主享受…

GO 库与框架篇

1. 需要重点掌握的库和框架? 输入输出: io,ioutil,fmt,bufio 字符处理: strings,bytes,strconv,regex,unicode,json 日期: 定时器-time.Tick,延时器-time.After/time.AfterFunc 数据库: database/sql 单元测试: testing 非类型安全操作: unsafe 同步:sync-同步操作,atomic-原子…

24-25出差交流体会-25-01-28

简洁版 如果发现自己走下坡路&#xff0c;工资下降等&#xff0c;如何办&#xff1f; &#xff08;环境因素等不在此文讨论范围&#xff0c;个人无法改变大环境。&#xff09; 多思考&#xff0c;是否是自身已经具备的能力在新模式下大幅贬值。 出路只有一条&#xff0c;提升自…

Linux 学习笔记__Day3

十八、设置虚拟机的静态IP 1、VMware的三种网络模式 安装VMware Workstation Pro之后&#xff0c;会在Windows系统中虚拟出两个虚拟网卡&#xff0c;如下&#xff1a; VMware提供了三种网络模式&#xff0c;分别是&#xff1a;桥接模式&#xff08;Bridged&#xff09;、NAT…

SOME/IP--协议英文原文讲解2

前言 SOME/IP协议越来越多的用于汽车电子行业中&#xff0c;关于协议详细完全的中文资料却没有&#xff0c;所以我将结合工作经验并对照英文原版协议做一系列的文章。基本分三大块&#xff1a; 1. SOME/IP协议讲解 2. SOME/IP-SD协议讲解 3. python/C举例调试讲解 4.1 Speci…

JWT实现单点登录

文章目录 JWT实现单点登录JWT 简介存在问题及解决方案登录流程后端程序实现前端保存Tokenstore存放信息的缺点及解决 校验流程&#xff1a;为gateway增加登录校验拦截器 另一种单点登录方法&#xff1a;Token&#xff0b;Redis实现单点登录 JWT实现单点登录 登录流程&#xff…

使用Avalonia UI实现DataGrid

1.Avalonia中的DataGrid的使用 DataGrid 是客户端 UI 中一个非常重要的控件。在 Avalonia 中&#xff0c;DataGrid 是一个独立的包 Avalonia.Controls.DataGrid&#xff0c;因此需要单独通过 NuGet 安装。接下来&#xff0c;将介绍如何安装和使用 DataGrid 控件。 2.安装 Dat…

特权模式docker逃逸

目录 1.环境 2.上线哥斯拉 3.特权模式逃逸 1.判断是否为docker环境 2.判断是否为特权模式 3.挂载宿主机磁盘到docker 4.计划任务反弹shell 1.环境 ubuntu部署一个存在CVE-2017-12615的docker: (ip:192.168.117.147) kali(ip:192.168.117.128) 哥斯拉 2.上线哥斯拉…