gpt4 book ai didi

unity-game-engine - 使用 Unity 中的自定义着色器正确平铺图集纹理

转载 作者:行者123 更新时间:2023-12-02 21:11:48 25 4
gpt4 key购买 nike

这有点复杂,但我希望它归结为一个非常简单的问题。事情是这样的:我使用 Unity 在运行时从 bsp 文件生成 map 游戏对象,该文件包含一大堆顶点、面、uv、纹理引用等。创建的网格完全按照应有的样子显示,并且所有纹理都显示得很好。但有一个问题,使用如此多的 Material 创建如此多的网格,导致大量的绘制调用,从而使程序变慢。所以我寻找一种减少绘制调用的方法,并找到了解决方案。将所有网格合并为一个大网格,并通过组合所有使用的纹理来创建纹理图集。组合网格效果很好,组合纹理效果也很好。然后我遇到了uv贴图的问题。因此,我从 NVidia 白皮书中找到了一个解决方案来制作自定义着色器,该着色器使用 tex2d 函数使用 uv 位置及其导数从纹理中插入纹理元素。我认为这会起作用,但我的网格有非常奇怪的三角形,我认为它们正在破坏这个解决方案。在下图中,您可以看到网格组合时与单独时的差异:

Combined Meshes with Changed UVs and Custom Shader

Separate Meshes with original UVs

这是我在着色器中用于设置模型颜色的代码:

o.Albedo = tex2D (_MainTex, IN.uv2_BlendTex, ddx(IN.uv_MainTex), ddy(IN.uv_MainTex)).rgb;

如您所见,我添加了第二个 UV,它是原始 UV 的非平铺版本。我通过使用 frac() 函数来实现这一点,但是是在 C# 代码中而不是在着色器中。由于纹理可以具有不同的大小,因此我必须在进入着色器之前计算 UV,因为当时我可以访问纹理大小。

这是我用来计算 2 个 UV 的代码:

                Rect surfaceTextureRect = uvReMappers[textureIndex];
Mesh surfaceMesh = allFaces[i].mesh;
Vector2[] atlasTiledUVs = new Vector2[surfaceMesh.uv.Length];
Vector2[] atlasClampedUVs = new Vector2[surfaceMesh.uv.Length];
for (int j = 0; j < atlasClampedUVs.Length; j++)
{
Vector2 clampedUV = new Vector2((surfaceMesh.uv[j].x - Mathf.Floor(surfaceMesh.uv[j].x)), (surfaceMesh.uv[j].y - Mathf.Floor(surfaceMesh.uv[j].y)));
float atlasClampedX = (clampedUV.x * surfaceTextureRect.width) + surfaceTextureRect.x;
float atlasClampedY = (clampedUV.y * surfaceTextureRect.height) + surfaceTextureRect.y;
atlasTiledUVs[j] = new Vector2((surfaceMesh.uv[j].x * surfaceTextureRect.width) + surfaceTextureRect.x, (surfaceMesh.uv[j].y * surfaceTextureRect.height) + surfaceTextureRect.y);
atlasClampedUVs[j] = new Vector2(atlasClampedX, atlasClampedY);
if (i < 10) { Debug.Log(i + " Original: " + surfaceMesh.uv[j] + " ClampedUV: " + clampedUV); }
}
surfaceMesh.uv = atlasTiledUVs;
surfaceMesh.uv2 = atlasClampedUVs;

数组uvReMappers是使用Texture2D函数PackTextures()时创建的一个矩形数组。

抱歉花了这么长时间,但这是我的问题:为什么纹理会扭曲。是因为网格的三角测量方式还是因为我编写自定义着色器的方式。最后我该如何解决它。

感谢您的宝贵时间。抱歉写了这么多,但我以前从来没有发过问题。我总是在网上找到几乎所有问题的答案,但我已经搜索了好几天如何解决这个问题。我觉得它可能太具体而无法找到答案。我希望我已经提供了足够的信息。

最佳答案

我终于解决了这个问题!所以事实证明我不应该在着色器之前计算 UV。相反,我通过 UV 传递着色器所需的信息,以便它可以直接计算新的纹理元素位置。

这是着色器之前的代码:

Rect surfaceTextureRect = uvReMappers[textureIndex];
Mesh surfaceMesh = allFaces[i].mesh;
Vector2[] atlasTexturePosition = new Vector2[surfaceMesh.uv.Length];
Vector2[] atlasTextureSize = new Vector2[surfaceMesh.uv.Length];
for (int j = 0; j < atlasTexturePosition.Length; j++)
{
atlasTexturePosition[j] = new Vector2(surfaceTextureRect.x, surfaceTextureRect.y);
atlasTextureSize[j] = new Vector2(surfaceTextureRect.width, surfaceTextureRect.height);
}
surfaceMesh.uv2 = atlasTexturePosition;
surfaceMesh.uv3 = atlasTextureSize;

这是着色器代码:

tex2D(_MainTex, float2((frac(IN.uv.x) * IN.uv3.x) + IN.uv2.x, (frac(IN.uv.y) * IN.uv3.y) + IN.uv2.y));

关于unity-game-engine - 使用 Unity 中的自定义着色器正确平铺图集纹理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33055568/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com