贴花包裹网

时间:2019-03-04 15:39:50

标签: unity3d decal

我正在研究纹身模拟器程序,我需要知道是否有一种方法可以将贴花(纹身)包裹在目标网格周围,就像让一条纹身从一侧到另一侧穿刺一样,或背后的事件。

enter image description here

3 个答案:

答案 0 :(得分:3)

不是在运行时使用投影贴花,不是。

您这里需要的是程序纹身图。可以将其视为另一个纹理,例如光照贴图。您可能需要一个自定义着色器,但可以使用标准着色器的辅助反照率通道来完成。

棘手的部分是写入该纹理。我将概述基本算法,但要由您自行实现:

您需要做的第一件事是在代码中展开网格的三角形。您需要确定UV贴图上哪些边是连续的,哪些是分开的。接下来,您需要一种方法来识别纹身和初始变形。首先,您将需要在纹身源贴图上定义一个旋转的原点。然后,您将需要定义一个引用源纹理的结构,以及将其应用于目标纹理的UV位置(Vector2)/旋转(浮动)/缩放(浮动)。

一旦您以该格式存储了纹身,则可以开始为皮肤构建纹身蒙版纹理。如果您的皮肤uv具有一致的像素密度,则这会容易得多,因为您可以主要在uv空间中工作,但是如果没有,则需要重新投影以获取每个三倍体的比例。但是,基本上,您从包含原点的身体三角形开始,然后正常绘制到该三角形上。从那里,您知道该三角形的每个顶点和边缘在纹身源纹理上的位置。因此,遍历每个相邻的三角形(我建议使用广度优先的递归方法),然后从您已经知道的边缘继续进行。如果所有三个顶点不在源纹理的矩形范围内,则可以在此处停止。否则,继续下一个三角形的邻居。计算邻居时,请确保使用3D网格,以免卡住接缝。

当纹身完全缠绕并自身重叠时,该算法将需要处理一些边缘情况,但是有几种不同的处理方法。

将所有纹身都写成纹身纹理后,只需将其应用到皮肤材料上,瞧!这样不仅可以将所有计算移出实时渲染,而且还可以让您完全控制纹身的应用方式。

答案 1 :(得分:1)

您可以使用Unity的官方预览工具Render Pipelines - High Definition.

使用贴花投影仪

这是我用来将“ tatoo”投射到存储桶上的方式。您当然可以将其应用于您的模型。 (将贴图投影仪放在孩子身上,以便纹身可以跟随模型)

enter image description here

导入“渲染管线-高清晰度”包的最佳方法是将use Unity Hub to create a new project选为模板。如果它是现有项目,那么此official blog可能会为您提供帮助。

成功设置好程序包后,请按照this tutorial进行操作,即可将纹身图样投射到您想要的任何位置的模型上。

答案 2 :(得分:1)

我使用自定义着色器做了类似的事情。我认为它将满足您的要求。我的游戏会根据iPad游戏原型的单位等级和类型动态渲染标志。确切的操作方式取决于您在项目中的设置方式,但这就是我的样子-第一个图像是显示网格的线框,第二个是打开了着色器并显示它们添加颜色和标志基于等级和单位。我刚刚为顶部标记添加了着色器,因为它添加了单位标志,类似于您希望纹身的样式:

enter image description here enter image description here

请注意,您可以将多个着色器附加到特定的网格。

标志是具有透明度的图像,它被添加到着色器中并在着色器中被称为纹理:

shader parameter setup - emblem

您可以看到我们还有一张带有某些阴影纹理的图片,用作横幅的背景。

这是我的第一个着色器,它是在前一段时间写的,因此我确定它在所有方面都不是最理想的,但是希望它足以使您入门(它仍然适用于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
}}
}

着色器有点疯狂地学习如何做,但是一旦您使它们工作,就会很有趣-像大多数编程一样:)

在我的情况下,覆盖纹理的大小/形状与标志相同,这使其更容易使用。我在想,您需要向着色器添加一些参数,这些参数指示您希望相对于网格绘制覆盖层的位置,并且对纹身边界之外的顶点/片段什么都不做,就像第一个想法一样。