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,但一时半会儿找不到链接了,之后再补吧

UnityDecal——贴花方法总结相关推荐

  1. unity的贴花方案

    前言 最近通关了<What Remains of Edith Finch>(艾迪芬奇的记忆),总体来说应该算是一个剧情+解密向的游戏,故事+表现手法十分出色. 游戏主要是叙述一个神秘的家族 ...

  2. 在 Oracle Enterprise Linux 和 iSCSI 上构建您自己的 Oracle RAC 11g 集群

    作者:Jeffrey Hunter 了解如何以低于 2,700 美元的费用在 Oracle Enterprise Linux 上安装并配置 Oracle RAC 11g 第 2 版开发集群. 本指南中 ...

  3. Java面试题大全2021版

    一.Java 基础 JDK 和 JRE 有什么区别? JDK:Java Development Kit 的简称,java 开发工具包,提供了 java 的开发环境和运行环境. JRE:Java Run ...

  4. Blender图解教程:用Krita为模型贴花

    本文基于Blender 2.81Alpha 和 Krita 4.2.5 效果图 概述 这是一种基础色 + 贴花图案的风格,相对纯色有更强的表现力而相对手绘效率要更高一些,这个例子主要是用于创建基础色贴 ...

  5. 游戏中的Decal(贴花)

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

  6. (41)Decal [ 贴花] Actor

    添加decal到关卡中 向场景中添加decal的最简单的方法是:在内容浏览器中选中适当的decal材质,然后右击并从关联菜单中选择 Add Actor(添加 Actor) > Add Defer ...

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

    本文最终效果 文章目录 一.前言 二.环境准备 1.URP环境准备 2.技能范围图案 二.方案一:写Shader实现 1.Shader脚本:UrpDecal.shader 2.材质球 3.创建Cube ...

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

    本文最终效果 文章目录 一.前言 二.环境准备 1.URP环境准备 2.技能范围图案 二.方案一:写Shader实现 1.Shader脚本:UrpDecal.shader 2.材质球 3.创建Cube ...

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

    Decal顶点没有烘焙的光照数据,因此无法在含前向管线的阴影下绘制.特效贴花为unlit自发光材质,阴影下表现影响不大.而场景Decal需要计算光照. 1. Decal实现原理 MobileDecal ...

  10. Deferred Decal(延迟贴花)

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

最新文章

  1. MATLAB从入门到精通-Matlab R2020b新功能 | 子标题和标题/标签对齐功能!
  2. 写聊天室之前 了解聊天室拓展出来的各种知识点
  3. linux开机自动启动数据库,mysql随linux开机自动启动
  4. Android 4.0 SDK下载安装
  5. 【C语言简单说】八:分支结构之if...else...(2)
  6. linux的nohup命令的用法。
  7. 使用Node 操作MySQL数据库
  8. “模块计算机类型“x64”与目标计算机类型“X86”冲突解决方案
  9. 监督学习 | SVM 之线性支持向量机原理
  10. 缺货警告!小米这款手机已被骂惨...
  11. Problem B: 编写函数:求最大公约数gcd()和最小公倍数lcm() (Append Code) 山东科技大学 oj
  12. java 判断两个时间相差的天数
  13. Android 串口蓝牙通信开发Java版本
  14. php 微信开发 网页授权登录,微信开发网页授权登录——2018年6月2日
  15. 字节跳动bytedance西瓜视频播放器研究
  16. 【技术干货】聊聊在大厂推荐场景中embedding都是怎么做的
  17. Netty源码解析-Netty内存泄露检测
  18. 股票打板 知识 收集
  19. Chrome主页被劫持怎么破
  20. 写作分享|向SCI期刊投稿时使用什么邮箱比较好?

热门文章

  1. 文章:Integration of omic networks in a developmental atlas of maize
  2. 『网络迷踪』ctfshow-这里有轨
  3. 爬虫基本原理与实战---12、选择器的用法
  4. 央视2套 CCTV2006年度经济人物 南方之夜
  5. 「Java学习打卡」30、3.25面向对象程序练习
  6. [Servlet3.0新功能]注释替代配置文件
  7. 最近找的一些物联网的资料,稍微整理了下
  8. 启动spring出错 org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catal
  9. 制造行业的 缺料分析、欠料分析、齐套分析
  10. 02-过拟合和欠拟合的表现与解决方法