UnityDecal——贴花方法总结

article/2025/8/28 23:22:09


这里写图片描述

Unity里贴花的实现方法比较多,商店里的插件也是各种各样,最近正好又在弄这个,趁机会给自己总结下:

1、构造贴片网格
思想很简单,就是在当前表面构建一个与表面完全贴合的新Mesh,并重新计算纹理贴图,从而实现贴片效果。
假设 P 为当前表面上的一点, 当前表面在该点的法线为 N, 点 P 为贴片的中心, 贴片的单位切向量为 T

根据给定的点 P , N , T,T 与 N 叉乘可得出的副法线 B, 可以定义表面在点 P 的切平面, 从切平面内可以裁剪出一个矩形, 再加上与法向量 N 平行的4个边平面, 可以构造贴片所在区域。 令 w 和 h 为贴片的宽和高, 则4个边平面的可表示为:


同时,也要进行前后平面的裁剪, 避免那些位于点 P 前后很远但位于边平面内的面被裁剪, 前后平面表示为


这里写图片描述

最后可构建出一个裁剪立方体


这里写图片描述

网格构造的执行过程为: 先确定贴片会影响到世界空间中的哪些表面, 可在计算出裁剪立方体后通过 Unity 中Bounds 类自带的 Intersects 函数得到, 对于得到的平面, 逐个遍历其中的三角形。 遍历时, 通过三个点得出三角形的两条边的对应向量, 再通过叉乘得出其法线 M, 转换到同一坐标系后可通过 Vector3.Angle 计算 N 与 M 的夹角, 若夹角大于 90 度, 则表明该三角形为背向贴片, 将其舍弃。 若夹角小于 90 度, 则依次与裁剪立方体的六个面进行比较判断 , 通过 Plane.GetSide 三角形的三角点是在立方体内。 若整个 Mesh 的顶点都在裁剪立方体内, 则将其保存为贴片的 Mesh 顶点, 若没有任何一点在裁剪立方体内, 则将其舍弃, 主要处理的是既有在立方体内的点,又有不在立方体内部的点的情况。

对于贴片可能影响的物体表面, 其中的三角形被当作凸多边形处理, 依次用6个边界平面中的一个屏幕去裁剪。用屏幕裁剪一个有N个顶点的多边形,最多产生一个有 n + 1 个定点的凸多边形, 这样一个三角形被6个平面裁剪, 最多产生有9个顶点的多边形:


这里写图片描述

如图所示, 截4次,得到7个顶点, 因为 Mesh 中的三角形大部分都会共边,因此每个三角形只裁剪一次。

6个平面裁剪完成后, 最终的凸多边形被当作三角形扇形 (Triangle_fans) 添加到贴片的三角网格。

可通过射线等方式按照其顶点顺序计算出其与立方体表面的一个交点, 并舍弃立方体外的点, 用交点与内部的点重新构建 Mesh, 最后根据新顶点的位置计算其投影后的 UV 坐标即可。

2、G-buffer投影
最早接触到的是 Unity 官方 commandbuffer 例子里的,C#脚本这边很简略,只是在 LightingPass 前 new 了一个commandbuffer, 核心实现则在 Shader 中,vertex 和 fragment shader 代码如下:

struct v2f{float4 pos : SV_POSITION;half2 uv : TEXCOORD0;float4 screenUV : TEXCOORD1;float3 ray : TEXCOORD2;half3 orientation : TEXCOORD3;};v2f vert (float3 v : POSITION){v2f o;o.pos = mul (UNITY_MATRIX_MVP, float4(v,1));o.uv = v.xz+0.5;o.screenUV = ComputeScreenPos (o.pos);o.ray = mul (UNITY_MATRIX_MV, float4(v,1)).xyz * float3(-1,-1,1);o.orientation = mul ((float3x3)unity_ObjectToWorld, float3(0,1,0));return o;}CBUFFER_START(UnityPerCamera2)// float4x4 _CameraToWorld;CBUFFER_ENDsampler2D _MainTex;sampler2D_float _CameraDepthTexture;sampler2D _NormalsCopy;fixed4 frag(v2f i) : SV_Target{i.ray = i.ray * (_ProjectionParams.z / i.ray.z);float2 uv = i.screenUV.xy / i.screenUV.w;// read depth and reconstruct world positionfloat depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, uv);depth = Linear01Depth (depth);float4 vpos = float4(i.ray * depth,1);float3 wpos = mul (unity_CameraToWorld, vpos).xyz;float3 opos = mul (unity_WorldToObject, float4(wpos,1)).xyz;clip (float3(0.5,0.5,0.5) - abs(opos.xyz));i.uv = opos.xz+0.5;half3 normal = tex2D(_NormalsCopy, uv).rgb;fixed3 wnormal = normal.rgb * 2.0 - 1.0;clip (dot(wnormal, i.orientation) - 0.3);fixed4 col = tex2D (_MainTex, i.uv);if (col.a < 0.8)col.a = 0;return col;}

其中 ray 是相机相机指向每个顶点的向量 (乘以 float3(-1,-1,1) 是因为经过MV变换后 z 通常是负数)

i.ray = i.ray * (_ProjectionParams.z / i.ray.z);

则是将向量的终点由顶点(光栅化后应该是像素,但放这里好像又不太好表达)位置投影到了相机远截面,如图所示:


这里写图片描述

然后通过深度图得到像素投影在其他物体上的坐标,并重新转换至模型坐标

clip (float3(0.5,0.5,0.5) - abs(opos.xyz));

因为 Demo 中使用的是单位大小的 Cube, 因此投影后在 Cube 外的像素直接 clip 掉

clip (dot(wnormal, i.orientation) - 0.3);

则是将投影点的法线与设施好的 Decal 朝向做比较,裁剪掉角度太大的避免贴图拉伸造成的Artificial, 如图所示:


这里写图片描述 这里写图片描述

也不能说好还是不好23333

3、Forward Render 投影
思路基本上跟G-BUFFER的一样,既然延迟渲染可以这样做,Forward为什么不行,同样有 NormalDepthTexture,如法炮制,我们得到这样的结果:


这里写图片描述

很明显,深度图精度不够,导致渲染结果惨不忍睹,其原因是在 forward path 下相机渲染 DepthNormals texture 时, depth 和 normal 各分配了两个 8 bits 的通道, 而单独只渲染 depth 的时候会根据配置给 16 或者 32 bits。因此,我们可以通过 replacement shader 和 command buffer 自己提前渲染好高精度的深度图,结果就好很多了:


这里写图片描述

4、others
projector就不说啦,适合用于数量多的血迹或者弹孔,之前看到寒霜引擎有篇演讲是用 geometry shader 去做弹痕的 decal,但一时半会儿找不到链接了,之后再补吧


http://chatgpt.dhexx.cn/article/tceYGCFq.shtml

相关文章

Blender学习笔记-印花(decal)贴图

最近学习blender制作模型&#xff0c;特将学习心得记录下来&#xff0c;供参考。 今天的心得是如何将贴图(英文名为decal)贴在另一张贴图的表面上&#xff0c;常用于文字、logo的图案制作。 视频教程&#xff08;可在最后的链接下载&#xff09;最后的结果如下图所示&#xf…

Decal的另类用法

Decal在没有办法得到深度之前都是根据地形的高度自己生成三角形来生成的&#xff0c;有了深度之后一切变的很简单&#xff0c;只需要画一个box就可以解决&#xff0c;类似于点光源。 以前做过的一个项目最后就是把地形的一个sector分成几个decal来画&#xff0c;虽然DP增加了&a…

Oracle中declare如何使用

Oracle中declare如何使用 首先我们需要了解declare遵循下面的实现结构 declare --声明 begin --开始 end; --结束 了解之后&#xff0c;我们就可以在这个结构中添加语句实现小功能 例如&#xff1a;输出今天的日期 declare --声明 datevalue varchar2(20);--定义变量 begin --…

DCC - Photoshop - Nvidia NormalMapFilter - 法线生成工具 - 顺便测试 Unity URP 12.1 中的 Decal System

文章目录 NVIDIA Texture Tools Exporter 下载、安装法线生成素材图扣干净无用像素使用 NVIDIA Normal Map Filter 生成贴图配置好 URP Renderer添加好 Decal Render Feature设置好 Decal Render Feature Techniqu: DBuffer配置好 unity shader graph添加 URP Decal Projector …

图形杂记-Decal贴花

ThreeJS WEBGL Decal 贴花 在图形学里主要指将特定图案&#xff0c;以类似粘贴或印刷的方式附着于其他物体上&#xff0c;能创造一种新颖的体验或逼真的效果&#xff0c;比较有趣&#xff0c;游戏中比较出名的有喷射战士splatoon123等。 unity HDRP中默认支持decal&#xff0c…

SQL中的declare用法

&#xfeff;&#xfeff; 平时写SQL查询、存储过程都是凭着感觉来&#xff0c;没有探究过SQL的具体语法&#xff0c;一直都是按c#那一套往SQL上模仿&#xff0c;前几天项目中碰到一个问题引起了我对declare定义变量的作用域的兴趣。 大家都知道c#中的局部变量&#xff0c;在i…

UE4使用贴花(Decal)

一、创建贴花材质 1:新建一个Material材质&#xff0c;修改Material Domain 为Deferred Decal (延迟贴花)&#xff0c;设置Blend Mode 为Translucent(半透明) 2&#xff1a;新建节点 3&#xff1a;给节点赋予材质&#xff0c;根据要求链接透明度和粗糙度 二、使用使用贴花 …

Deferred Decal(延迟贴花)

Decal渲染是一个引擎中重要的一部分&#xff0c;记忆中印象最深刻的就是以前CS中的弹痕与爆炸痕迹了。目前来说&#xff0c;Decal的实现方法也比较多&#xff0c;而且感觉还跟游戏类型有关&#xff0c;比如子弹乱飞的射击类FPS游戏中对贴花系统的要求就比较高&#xff0c;因为本…

【游戏开发小技】Unity中实现Dota里的角色技能地面贴花效果(URP | ShaderGraph | Decal)

本文最终效果 文章目录 一、前言二、环境准备1、URP环境准备2、技能范围图案 二、方案一&#xff1a;写Shader实现1、Shader脚本&#xff1a;UrpDecal.shader2、材质球3、创建Cube4、地面场景5、添加Renderer Feature: Decal6、移动DecalCube&#xff0c;与地面交叉7、运行效果…

UE5实现贴地面效果(RT+Decal)

文章目录 1.实现目标2.实现过程2.1 实现原理2.1.1 Render Target2.1.2 Polygon2.2 具体过程3.参考资料1.实现目标 在之前的文章中基于CesiumForUnreal实现了对地形3DTileset的贴地面绘制效果,在这里基于UE自带的RT和Decal实现更加通用的贴地面效果。依旧是加载在线的Cesium W…

Unity Shader-Decal贴花(SelfDecal,Alpha Blend,Mesh Decal,Projector,Deferred Decal)

前言 最近通关了《What Remains of Edith Finch》&#xff08;艾迪芬奇的记忆&#xff09;&#xff0c;总体来说应该算是一个剧情解密向的游戏&#xff0c;故事表现手法十分出色。 游戏主要是叙述一个神秘的家族遭遇了一系列类似《死神来了》的故事&#xff0c;家族的人离奇死…

Unity Decal 贴花效果测试

贴花效果&#xff0c;就和名字的直接意思类似&#xff0c;把一张图贴到另一个物体上显示&#xff0c;经常被用于表现一些重复出现的图案&#xff0c;比如弹孔&#xff0c;涂鸦&#xff0c;污渍等。效果图&#xff1a; 常规贴花实现 Unity官方提供了一个工程&#xff0c;这个…

UE4 Decal 贴花不在静态光照下绘制

Decal顶点没有烘焙的光照数据&#xff0c;因此无法在含前向管线的阴影下绘制。特效贴花为unlit自发光材质&#xff0c;阴影下表现影响不大。而场景Decal需要计算光照。 1. Decal实现原理 MobileDecalRendering.cpp 通过矩阵变换 得到FrustumComponentToClip&#xff0c;传入…

游戏中的Decal(贴花)

在游戏中&#xff0c;decal是一种非常常见的效果&#xff0c;常用来实现弹孔&#xff0c;血迹&#xff0c;涂鸦等效果。最近研究了下Decal在游戏引擎中的实现方式&#xff0c;大致总结了一下&#xff1a;1.基于面片实现&#xff1a;直接用一个Quat的mesh,加上一张贴图&#xff…

UE4 Decal实现简介

Decal 是游戏中常见的一个东西&#xff0c;经常被用在 显示弹痕&#xff0c;地面叠加花纹等。 Decal 绘制流程 Decal可以认为是&#xff0c;将一个面的画面沿Decal的Box的X轴方向投影到物体表面。 Decal的绘制实际只有一个Box绘制。 RHICmdList.DrawIndexedPrimitive(GetUn…

跳出for循环

跳出for循环有三种方式&#xff1a; 1&#xff1a;continue&#xff1b;跳出当次循环&#xff0c;可继续进行下一个循环&#xff1b; function ceshi(){for(var i 0 ; i < 6 ; i){if(i 3){continue;}console.log(,i);} }ceshi(); 效果图&#xff1a; 2&#xff1a;brea…

跳出forEach循环

我们平时用到的循环有很多种。for, map, while, forEach, for...of, for...in等等&#xff0c;每种循环都有在某一次循环语句中跳出本次循环的方法&#xff0c;但是除了forEach。 有小伙伴说不用不就好了。其实这些循环里边&#xff0c;当属for的效率最高&#xff0c;for...in最…

Java 8 跳出foreach循环,跳出本次循环,继续执行,之前的for each循环如何跳出本次循环,跳出循环,跳出多层for循环。

在Java8之前&#xff0c;最开始使用for i 循环&#xff0c;很老旧&#xff0c; 后来有了高级的for each 循环&#xff0c;然后这个跳出本次循环和跳出所有的for循环&#xff0c;都简单&#xff0c;稍微没见过的就是跳出多层for循环。 然后就是Java8出的foreach循环&#xff0…

js中的for循环如何跳出,js中for循环的两种语法

js几种for循环的几种用法 谷歌人工智能写作项目&#xff1a;小发猫 js&#xff0c;for循环是怎么运行的&#xff1f; typescript有哪些变化。 最普遍的介绍&#xff1a;for循环是JavaScript中最常用的循环&#xff0c;标准for循环代码格式为&#xff1a;for(定义变量初始值;…

if/while/do-while/for循环以及跳出循环break/return/continue

流程控制对任何一门编程语言都是至关重要的&#xff0c;它为我们提供了控制程序步骤的基本手段。常见对主要分为&#xff0c;条件语句、循环语句、跳转语句。 1、if语句 if 语句是一种判断语句。 语法&#xff1a; if(条件){条件成立时执行的代码 } if...else 语句当条件成…