问题描述
我正在制作立方体素游戏。我已经完成了块、世界、块和网格的生成,但有一个问题 - 我无法制作纹理。
我需要的只是在 3D 网格的一侧添加纹理(每个纹理都不同!)。我见过一些实现,但很难阅读其他人的代码(我尝试使用它们,但没有奏效)。我尝试过自己做这件事,但没有结果。
谁能解释一下如何做到这一点??
这是我当前的代码:
[ExecuteInEditMode]
[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshRenderer))]
public class Chunk : MonoBehavIoUr
{
private ushort[] _voxels = new ushort[16 * 16 * 16];
private MeshFilter meshFilter;
private Vector3[] cubeVertices = new[] {
new Vector3 (0,0),new Vector3 (1,1,new Vector3 (0,1),};
private int[] cubeTriangles = new[] {
// Front
0,2,3,// Top
2,4,5,// Right
1,6,// Left
0,7,// Back
5,// Bottom
0,6
};
public ushort this[int x,int y,int z]
{
get { return _voxels[x * 16 * 16 + y * 16 + z]; }
set { _voxels[x * 16 * 16 + y * 16 + z] = value; }
}
void Start()
{
meshFilter = GetComponent<MeshFilter>();
}
private void Update()
{
GenerateMesh();
}
public void GenerateMesh()
{
Mesh mesh = new Mesh();
List<Vector3> vertices = new List<Vector3>();
List<int> triangles = new List<int>();
for (var x = 0; x < 16; x++)
{
for (var y = 0; y < 16; y++)
{
for (var z = 0; z < 16; z++)
{
var voxelType = this[x,y,z];
if (voxelType == 0)
continue;
var pos = new Vector3(x,z);
var verticesPos = vertices.Count;
foreach (var vert in cubeVertices)
vertices.Add(pos + vert);
foreach (var tri in cubeTriangles)
triangles.Add(verticesPos + tri);
}
}
}
mesh.SetVertices(vertices);
mesh.SetTriangles(triangles.ToArray(),0);
meshFilter.mesh = mesh;
}
}
注意:这是一篇经过多次编辑的转帖,因此它专注于一个问题,并且有更好的解释。对不起。
解决方法
与您的 SetVertices()
和 SetTriangles()
一样,您可以使用纹理上每个顶点的 UV 坐标列表调用 SetUVs()
。
UV 列表大小必须与顶点列表大小匹配!
UV 坐标表示为 Vector2,其值介于 0 和 1 之间。 例如,要将整个纹理应用到立方体的正面,前 4 个 uv 如下所示:
private Vector2[] cubeUVs = new[] {
new Vector2 (0,0),new Vector2 (1,1),new Vector2 (0,...
}
...
mesh.SetUVs(0,cubeUVs);
如果您的纹理不是正方形,那么它将被拉伸。
您还应该在 RecalculateBounds()
方法的末尾调用 RecalculateNormals()
和 GenerateMesh()
以避免以后出现一些问题。
编辑
如果您真的想要为立方体的每一面使用不同的纹理文件,那么对我来说最干净、最高效的解决方案是为立方体的每一面设置不同的 VertexColor,例如。 (1,(0,1,(1,1) 和 (0,1).
但是,您必须将所有顶点复制 3 次。 (因为顶点颜色绑定到一个顶点,立方体的每个顶点属于3条边)
(你仍然需要像我之前说的那样设置 UV,但每一面都有整个纹理而不是纹理的一部分)
然后,您必须在输入中创建一个具有 6 个纹理的自定义着色器(每侧一个)。
而在fragment函数中,你根据顶点颜色选择合适的纹理颜色。
你可以为此,做一些 if 来选择纹理,但它的性能不会很好:
float3 finalColor;
if(vertexColor.r > 0.5f && vertexColor.g < 0.5f && vertexColor.b < 0.5f)
{
finalColor = text2D(_TopTexture,in.uv);
}
else if(...)
{
...
}
...
或者如果你想要更多的性能(有很多立方体),你可以做一些乘法来选择正确的纹理:
float3 topTexColor = text2D(_TopTexture,in.uv) * vertexColor.r * (1.0f - vertexColor.g) * (1.0f - vertexColor.b);
float3 frontTexColor = ...;
...
float3 finalColor = topTexColor + frontTexColor + ...;