Я пытаюсь создать игру, подобную кубовому миру, в которой я постепенно создаю атлас текстур, чтобы объединить все мои текстуры в одну. Затем я создаю кубы (сделанные из квадратов), к которым я хочу применить атлас текстуры (с указанием, конечно же, uvs). Проблема, с которой я столкнулся, состоит в том, что для визуализированных кубов (или кусков) применяется серебряный материал по умолчанию, который не применяется ни к одной из моих текстур. Может кто-то увидеть, где я иду не так.
Вот репо для всего кода: https://github.com/JoshPJackson/BlockGame
Общий поток логи c:
- Создание текстурного атласа (и сохранение тектов)
- Создание 6 четырехугольников для создания куба
- Добавить me sh рендеринг в квадроциклы
- Укажите uvs
- Примените текстуру атласа текстуры для quad me sh рендерер
В нескольких нижних строках блока. В файле cs я применяю атлас текстуры к материалу рендеринга me sh
Создатель моего атласа текстуры:
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using System;
namespace Game.Textures
{
public class TextureAtlasMapper
{
public Texture2D atlas;
public Texture2D[] textures;
public Rect[] rects;
public Dictionary<string, Rect> mappedTextures;
protected float individualHeight = 32.0f;
protected float individualWidth = 32.0f;
public TextureAtlasMapper()
{
UnityEngine.Object[] objects = Resources.LoadAll("textures") as UnityEngine.Object[];
textures = new Texture2D[objects.Length];
for (int i = 0; i < objects.Length; i++)
{
textures[i] = (Texture2D) objects[i];
}
atlas = new Texture2D(2048, 2048);
atlas.name = "myatlas";
rects = atlas.PackTextures(textures, 2);
mappedTextures = new Dictionary<string, Rect>();
for (int i = 0; i < rects.Length; i++)
{
mappedTextures[textures[i].name] = rects[i];
}
}
public float GetImageHeight()
{
return atlas.height;
}
public float GetImageWidth()
{
return atlas.width;
}
public Vector2[] GetMappedUVs(string textureName)
{
if (!mappedTextures.ContainsKey(textureName))
{
Debug.Log("missing entry: " + textureName);
}
Rect rect = mappedTextures[textureName];
Vector2[] list = new Vector2[4];
float u1 = rect.x + rect.width;
float u2 = rect.x;
float u3 = u2;
float u4 = u1;
float v1 = rect.y + rect.height;
float v2 = v1;
float v3 = rect.y;
float v4 = v3;
list.SetValue(new Vector2(u1, v1), 0);
list.SetValue(new Vector2(u2, v2), 1);
list.SetValue(new Vector2(u3, v3), 2);
list.SetValue(new Vector2(u4, v4), 3);
return list;
}
}
}
Моя четверка * sh класс:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Game.Textures;
using Game.Blocks;
namespace Game.Meshes
{
public class QuadMesh
{
Vector3[] allVertices = new Vector3[8];
Vector3[] vertices = new Vector3[4];
Vector3[] normals = new Vector3[4];
Vector2[] uvs = new Vector2[4];
public Mesh mesh;
int[] triangles = new int[6] { 3, 1, 0, 3, 2, 1 };
public QuadMesh(Block.Cubeside side)
{
SetAllVertices();
mesh = new Mesh();
normals = GetNormalCollection(Vector3.up);
switch (side)
{
case Block.Cubeside.BOTTOM:
vertices = GetVertexCollection(new int[] { 0, 1, 2, 3});
normals = GetNormalCollection(Vector3.down);
break;
case Block.Cubeside.TOP:
vertices = GetVertexCollection(new int[] { 7, 6, 5, 4 });
break;
case Block.Cubeside.LEFT:
vertices = GetVertexCollection(new int[] { 7, 4, 0, 3 });
normals = GetNormalCollection(Vector3.left);
break;
case Block.Cubeside.RIGHT:
vertices = GetVertexCollection(new int[] { 5, 6, 2, 1 });
normals = GetNormalCollection(Vector3.right);
break;
case Block.Cubeside.FRONT:
vertices = GetVertexCollection(new int[] { 4, 5, 1, 0 });
break;
case Block.Cubeside.BACK:
vertices = GetVertexCollection(new int[] { 6, 7, 3, 2 });
break;
}
mesh.vertices = vertices;
mesh.normals = normals;
// mesh.uv = uvs;
Vector2 uv00 = new Vector2(0f, 0f);
Vector2 uv10 = new Vector2(1f, 0f);
Vector2 uv01 = new Vector2(0f, 1f);
Vector2 uv11 = new Vector2(1f, 1f);
mesh.uv = new Vector2[] { uv11, uv01, uv00, uv10 };
mesh.triangles = triangles;
mesh.RecalculateBounds();
}
private void SetAllVertices()
{
allVertices.SetValue(new Vector3(-0.5f, -0.5f, 0.5f), 0);
allVertices.SetValue(new Vector3(0.5f, -0.5f, 0.5f), 1);
allVertices.SetValue(new Vector3(0.5f, -0.5f, -0.5f), 2);
allVertices.SetValue(new Vector3(-0.5f, -0.5f, -0.5f), 3);
allVertices.SetValue(new Vector3(-0.5f, 0.5f, 0.5f), 4);
allVertices.SetValue(new Vector3(0.5f, 0.5f, 0.5f), 5);
allVertices.SetValue(new Vector3(0.5f, 0.5f, -0.5f), 6);
allVertices.SetValue(new Vector3(-0.5f, 0.5f, -0.5f), 7);
}
private Vector3[] GetVertexCollection(int[] indices)
{
Vector3[] toReturn = new Vector3[4];
for (int i = 0; i < indices.Length; i++)
{
toReturn.SetValue(allVertices[indices[i]], i);
}
return toReturn;
}
private Vector3[] GetNormalCollection(Vector3 normal)
{
return new Vector3[4]
{
normal,
normal,
normal,
normal
};
}
}
}
И мой базовый блок класса:
using System.Collections;
using System.Collections.Generic;
using System;
using UnityEngine;
using UnityEngine.U2D;
using Game.Meshes;
using Game.Textures;
using Game.Chunks;
namespace Game.Blocks
{
abstract public class Block
{
// cube sides
public enum Cubeside { BOTTOM, TOP, LEFT, RIGHT, FRONT, BACK };
// block types
public enum BlockType { AIR, DIRT, GRASS }
// uvs
public virtual string[] textureNames { get; }
public bool isSolid = true;
// global position
public Vector3 globalPosition;
public Vector3 localPosition;
// parent chunk
public Chunk chunk;
// position inside chunk
public Vector3 positionInChunk;
public Cubeside[] renderedSides;
public Mesh mesh;
public GameObject parent;
public WorldBuilder worldBuilder()
{
return chunk.parent.parent;
}
public void Render()
{
if (this.GetType() != typeof(Air)) {
if (HasAirBack())
{
CreateQuad(Cubeside.BACK);
}
if (HasAirBelow())
{
CreateQuad(Cubeside.BOTTOM);
}
if (HasAirFront())
{
CreateQuad(Cubeside.FRONT);
}
if (HasAirAbove())
{
CreateQuad(Cubeside.TOP);
}
if (HasAirLeft())
{
CreateQuad(Cubeside.LEFT);
}
if (HasAirRight())
{
CreateQuad(Cubeside.RIGHT);
}
}
}
public bool HasAirAbove()
{
int maxHeight = ChunkColumn.chunksPerColumn * Chunk.size;
if (globalPosition.y + 1 > maxHeight - 1)
{
return true;
}
Block blockAbove = worldBuilder().GetBlockAtGlobalPosition(new Vector3(
globalPosition.x,
globalPosition.y + 1,
globalPosition.z
));
return blockAbove.GetType() == typeof(Air);
}
public bool HasAirBelow()
{
if (globalPosition.y - 1 >= 0)
{
Block blockAbove = worldBuilder().GetBlockAtGlobalPosition(new Vector3(
globalPosition.x,
globalPosition.y - 1,
globalPosition.z
));
return blockAbove.GetType() == typeof(Air);
}
return true;
}
public bool HasAirLeft()
{
if (globalPosition.x - 1 >= 0)
{
Block blockAbove = worldBuilder().GetBlockAtGlobalPosition(new Vector3(
globalPosition.x - 1,
globalPosition.y,
globalPosition.z
));
return blockAbove.GetType() == typeof(Air);
}
return true;
}
public bool HasAirRight()
{
if (globalPosition.x + 1 < worldBuilder().Size.x * Chunk.size)
{
Block blockAbove = worldBuilder().GetBlockAtGlobalPosition(new Vector3(
globalPosition.x + 1,
globalPosition.y,
globalPosition.z
));
return blockAbove.GetType() == typeof(Air);
}
return true;
}
public bool HasAirBack()
{
if (globalPosition.z - 1 >= 0)
{
Block blockAbove = worldBuilder().GetBlockAtGlobalPosition(new Vector3(
globalPosition.x,
globalPosition.y,
globalPosition.z - 1
));
return blockAbove.GetType() == typeof(Air);
}
return true;
}
public bool HasAirFront()
{
if (globalPosition.z + 1 < worldBuilder().Size.x * Chunk.size - 1)
{
Block blockAbove = worldBuilder().GetBlockAtGlobalPosition(new Vector3(
globalPosition.x,
globalPosition.y,
globalPosition.z + 1
));
return blockAbove.GetType() == typeof(Air);
}
return true;
}
public virtual void CreateQuad(Cubeside side)
{
string[] textures = new String[6];
if (textureNames.Length == 1)
{
for (int j = 0; j < 6; j++)
{
textures[j] = textureNames[0];
}
} else
{
textures = textureNames;
}
for (int i = 0; i < textures.Length; i++)
{
QuadMesh quadMesh = new QuadMesh(side);
TextureAtlasMapper mapper = Game.currentGame.mapper;
Vector2[] uvs = mapper.GetMappedUVs(textures[i]);
GameObject quad = new GameObject("Quad");
quad.transform.position = globalPosition;
quad.transform.parent = chunk.GameObject.transform;
MeshFilter meshFilter = (MeshFilter)quad.AddComponent(typeof(MeshFilter));
Mesh myMesh = quadMesh.mesh;
myMesh.uv = uvs;
myMesh.RecalculateBounds();
myMesh.name = "my mesh";
meshFilter.mesh = myMesh;
MeshRenderer renderer = quad.AddComponent(typeof(MeshRenderer)) as MeshRenderer;
renderer.material = new Material(Shader.Find("Standard"));
renderer.material.mainTexture = mapper.atlas;
}
}
}
}