答案 0 :(得分:3)
不是在运行时使用投影贴花,不是。
您这里需要的是程序纹身图。可以将其视为另一个纹理,例如光照贴图。您可能需要一个自定义着色器,但可以使用标准着色器的辅助反照率通道来完成。
棘手的部分是写入该纹理。我将概述基本算法,但要由您自行实现:
您需要做的第一件事是在代码中展开网格的三角形。您需要确定UV贴图上哪些边是连续的,哪些是分开的。接下来,您需要一种方法来识别纹身和初始变形。首先,您将需要在纹身源贴图上定义一个旋转的原点。然后,您将需要定义一个引用源纹理的结构,以及将其应用于目标纹理的UV位置(Vector2)/旋转(浮动)/缩放(浮动)。
一旦您以该格式存储了纹身,则可以开始为皮肤构建纹身蒙版纹理。如果您的皮肤uv具有一致的像素密度,则这会容易得多,因为您可以主要在uv空间中工作,但是如果没有,则需要重新投影以获取每个三倍体的比例。但是,基本上,您从包含原点的身体三角形开始,然后正常绘制到该三角形上。从那里,您知道该三角形的每个顶点和边缘在纹身源纹理上的位置。因此,遍历每个相邻的三角形(我建议使用广度优先的递归方法),然后从您已经知道的边缘继续进行。如果所有三个顶点不在源纹理的矩形范围内,则可以在此处停止。否则,继续下一个三角形的邻居。计算邻居时,请确保使用3D网格,以免卡住接缝。
当纹身完全缠绕并自身重叠时,该算法将需要处理一些边缘情况,但是有几种不同的处理方法。
将所有纹身都写成纹身纹理后,只需将其应用到皮肤材料上,瞧!这样不仅可以将所有计算移出实时渲染,而且还可以让您完全控制纹身的应用方式。
答案 1 :(得分:1)
您可以使用Unity的官方预览工具Render Pipelines - High Definition.
使用贴花投影仪这是我用来将“ tatoo”投射到存储桶上的方式。您当然可以将其应用于您的模型。 (将贴图投影仪放在孩子身上,以便纹身可以跟随模型)
导入“渲染管线-高清晰度”包的最佳方法是将use Unity Hub to create a new project选为模板。如果它是现有项目,那么此official blog可能会为您提供帮助。
成功设置好程序包后,请按照this tutorial进行操作,即可将纹身图样投射到您想要的任何位置的模型上。
答案 2 :(得分:1)
我使用自定义着色器做了类似的事情。我认为它将满足您的要求。我的游戏会根据iPad游戏原型的单位等级和类型动态渲染标志。确切的操作方式取决于您在项目中的设置方式,但这就是我的样子-第一个图像是显示网格的线框,第二个是打开了着色器并显示它们添加颜色和标志基于等级和单位。我刚刚为顶部标记添加了着色器,因为它添加了单位标志,类似于您希望纹身的样式:
请注意,您可以将多个着色器附加到特定的网格。
标志是具有透明度的图像,它被添加到着色器中并在着色器中被称为纹理:
您可以看到我们还有一张带有某些阴影纹理的图片,用作横幅的背景。
这是我的第一个着色器,它是在前一段时间写的,因此我确定它在所有方面都不是最理想的,但是希望它足以使您入门(它仍然适用于Unity 2018.3.x)。 ,尽管我必须修改一些内容才能进行编译):
Shader "Custom/TroopFlagEmblemShader" {
Properties {
_BackColor ("Background Color", Color) = (0.78, 0.2, 0.2) // scarlet
_MainTex ("Background (RGBA)", 2D) = "" {}
_EmblemTex("Emblem (RGBA)", 2D) = "" {}
_Rank ( "Rank (1-9)", Float ) = 3.0
}
SubShader {
Pass {
CGPROGRAM
#pragma exclude_renderers xbox360 ps3 flash
#pragma target 3.0
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata {
float4 vertex: POSITION;
float4 texcoord: TEXCOORD0;
};
struct v2f {
float4 pos: SV_POSITION;
float2 uv: TEXCOORD0;
};
uniform sampler2D _MainTex;
uniform sampler2D _EmblemTex;
uniform float3 _BackColor;
uniform float _Rank;
v2f vert( appdata v )
{
v2f o;
o.pos = UnityObjectToClipPos( v.vertex );
o.uv = v.texcoord.xy;
return o;
}
float4 frag( v2f IN ) : COLOR
{
float4 outColor;
float4 backTextureColor = tex2D( _MainTex, IN.uv.xy );
float4 emblemTextureColor = tex2D( _EmblemTex, IN.uv.xy );
// not drawing the square at all above rank 5
if ( _Rank >= 6.0 )
discard;
if ( _Rank < 5 ) // 4 and below
{
outColor = float4( (emblemTextureColor.rgb * emblemTextureColor.a) +
(((1.0 - emblemTextureColor.a) * backTextureColor.rgb) * _BackColor.rgb) , 1 );
// float4(_BackColor.rgb, 1 ));
}
else if ( _Rank >= 5.0 ) // but excluded from 6 above
{
// 5 is just solid backcolor combined with background texture
outColor = float4( backTextureColor.rgb * _BackColor.rgb, 1 );
}
return outColor;
}
ENDCG
}}
}
着色器有点疯狂地学习如何做,但是一旦您使它们工作,就会很有趣-像大多数编程一样:)
在我的情况下,覆盖纹理的大小/形状与标志相同,这使其更容易使用。我在想,您需要向着色器添加一些参数,这些参数指示您希望相对于网格绘制覆盖层的位置,并且对纹身边界之外的顶点/片段什么都不做,就像第一个想法一样。