Hi all. I’m trying to create a cubeworld-like game in which I’m programatically creating a texture atlas to combine all of my textures into one. I’m then creating cubes (made of quads) that I want to apply the texture atlas to (specifying uvs too of course). The problem I’m having is that the rendered cubes (or chunks) have the default silver material applied with none of my textures. Can someone see where I am going wrong.
Here is a repo for all the code: https://github.com/JoshPJackson/BlockGame
[157632-untitled.png*_|157632]
The general flow of logic:
- Create texture atlas (and store rects)
- Create 6 quads to make a cube
- Add mesh renderer to quads
- Specify uvs
- Apply texture atlas texture to quad mesh renderer
At the bottom few lines of the Block.cs file is where I’m applying the texture atlas to the mesh renderer material
My texture atlas creator:
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 _= (Texture2D) objects*;*_
}
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_.name] = rects*;
}
}*_
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;
}
}
}
My quad mesh class:
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);*
}
return toReturn;
}
private Vector3[] GetNormalCollection(Vector3 normal)
{
return new Vector3[4]
{
normal,
normal,
normal,
normal
};
}
}
}
And my base block class:
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*);*
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;
}
}
}
}
_*