- Home /
The question is answered, right answer was accepted
Creating cube in script/ texture stretches on all sides but top and bottom?
I'm trying to create a cube from scratch and everything is going well except when I add a material or texture to it. The texture is correct on the top and bottom faces, but stretches on all other sides. The texture appears correctly on Unity's default cube, but I create the cubes in a way that not all faces are drawn.
I believe the problem may be incorrect UV mapping but I'm finding it quite difficult to understand how that works. The script is included below, and I appreciate any and all help!
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class BlockScript : MonoBehaviour {
//Code for rendering mesh
Vector3[] vertices = new Vector3[8];
List<int> trianglesOne = new List<int>();
Vector2[] uvs = new Vector2[8];
Mesh mesh;
public Material wood;
//Vector3 pos;
//End of code for rendering mesh
ChunkScript chunkScript;
public GameObject CoordChecker;
int xPos;
int yPos;
int zPos;
void AddComponents() {
gameObject.AddComponent<MeshFilter>();
gameObject.AddComponent<MeshRenderer>();
gameObject.AddComponent<BoxCollider>();
BoxCollider box = gameObject.GetComponent<BoxCollider>();
box.size = new Vector3(.99f, .99f, .99f);
mesh = GetComponent<MeshFilter>().mesh;
if (GlobalVariableHolder.wood) gameObject.GetComponent<MeshRenderer>().material = wood;
gameObject.tag = "Block";
}
void Start() {
AddComponents();
}
public void printName() {
print(name);
}
void OnTriggerEnter(Collider other) {
if (other.tag == "Chunk") {
transform.parent = other.transform;
xPos = (int)transform.localPosition.x;
yPos = (int)transform.localPosition.y;
zPos = (int)transform.localPosition.z;
transform.name = (xPos + " " + yPos + " " + zPos);
chunkScript = transform.parent.GetComponent<ChunkScript>();
chunkScript.blockPos[xPos, yPos, zPos] = true;
CreateFaces();
chunkScript.ChunkUpdate();
}
}
void OnDestroy() {
chunkScript.blockPos[xPos, yPos, zPos] = false;
}
//Checks if each direction has a block and calls the respective function to draw the face
public void CreateFaces() {
mesh.Clear();
Vertices();
if (zPos < 9) {
if (chunkScript.blockPos[xPos, yPos, zPos + 1] == false) FaceNorth();
} else if(zPos == 9) {
GameObject checker = Instantiate(CoordChecker, new Vector3(xPos, yPos, zPos + 1), Quaternion.identity) as GameObject;
CoordCheckerScript checkerScript = checker.GetComponent<CoordCheckerScript>();
if (checkerScript.containsBlock == false) { FaceNorth(); }
Destroy(checker.gameObject);
}
if (xPos < 9) {
if (!chunkScript.blockPos[xPos + 1, yPos, zPos]) FaceEast();
} else if(xPos == 9) {
GameObject checker = Instantiate(CoordChecker, new Vector3(xPos + 1, yPos, zPos), Quaternion.identity) as GameObject;
CoordCheckerScript checkerScript = checker.GetComponent<CoordCheckerScript>();
if (checkerScript.containsBlock == false) { FaceWest(); }
Destroy(checker.gameObject);
}
if (zPos > 0) {
if (!chunkScript.blockPos[xPos, yPos, zPos - 1]) FaceSouth();
} else if(zPos == 0) {
GameObject checker = Instantiate(CoordChecker, new Vector3(xPos, yPos, zPos - 1), Quaternion.identity) as GameObject;
CoordCheckerScript checkerScript = checker.GetComponent<CoordCheckerScript>();
if (checkerScript.containsBlock == false) { FaceSouth(); }
Destroy(checker.gameObject);
}
if (xPos > 0) {
if (!chunkScript.blockPos[xPos - 1, yPos, zPos]) FaceWest();
} else if (xPos == 0) {
GameObject checker = Instantiate(CoordChecker, new Vector3(xPos - 1, yPos, zPos), Quaternion.identity) as GameObject;
CoordCheckerScript checkerScript = checker.GetComponent<CoordCheckerScript>();
if (checkerScript.containsBlock == false) { FaceWest(); }
Destroy(checker.gameObject);
}
if (yPos < 299) {
if (!chunkScript.blockPos[xPos, yPos + 1, zPos]) FaceTop();
}
if (yPos > 0) {
if (!chunkScript.blockPos[xPos, yPos - 1, zPos]) FaceBottom();
}
int[] triangles = trianglesOne.ToArray();
mesh.triangles = triangles;
}
//Code to set mesh triangles
void Vertices() {
vertices[0] = new Vector3(-0.5f, -0.5f, -0.5f);
vertices[1] = new Vector3(-0.5f, 0.5f, -0.5f);
vertices[2] = new Vector3(0.5f, 0.5f, -0.5f);
vertices[3] = new Vector3(0.5f, -0.5f, -0.5f);
vertices[4] = new Vector3(-0.5f, -0.5f, 0.5f);
vertices[5] = new Vector3(-0.5f, 0.5f, 0.5f);
vertices[6] = new Vector3(0.5f, 0.5f, 0.5f);
vertices[7] = new Vector3(0.5f, -0.5f, 0.5f);
mesh.vertices = vertices;
for(int i = 0; i < vertices.Length; i++) {
uvs[i] = new Vector2(vertices[i].x, vertices[i].z);
}
mesh.uv = uvs;
}
void FaceNorth() {
trianglesOne.Add(7);
trianglesOne.Add(6);
trianglesOne.Add(5);
trianglesOne.Add(7);
trianglesOne.Add(5);
trianglesOne.Add(4);
}
void FaceEast() {
trianglesOne.Add(3);
trianglesOne.Add(2);
trianglesOne.Add(6);
trianglesOne.Add(3);
trianglesOne.Add(6);
trianglesOne.Add(7);
}
void FaceSouth() {
trianglesOne.Add(0);
trianglesOne.Add(1);
trianglesOne.Add(2);
trianglesOne.Add(0);
trianglesOne.Add(2);
trianglesOne.Add(3);
}
void FaceWest() {
trianglesOne.Add(4);
trianglesOne.Add(5);
trianglesOne.Add(1);
trianglesOne.Add(4);
trianglesOne.Add(1);
trianglesOne.Add(0);
}
void FaceTop() {
trianglesOne.Add(1);
trianglesOne.Add(5);
trianglesOne.Add(6);
trianglesOne.Add(1);
trianglesOne.Add(6);
trianglesOne.Add(2);
}
void FaceBottom() {
trianglesOne.Add(4);
trianglesOne.Add(0);
trianglesOne.Add(3);
trianglesOne.Add(4);
trianglesOne.Add(3);
trianglesOne.Add(7);
}
Hmm, this code looks familiar, lol. $$anonymous$$ay I suggest you post an image of the texture you are mapping onto the cube? Here is how I would figure out the UV mapping: looking at the texture image, I would draw six squares on it. Preferably, each edge would be flush with another square's edge ( or flush when possible, given the 2d limitations), and all edges be equal in length. Once the squares are laid out, note the position of each corner as a fraction of total height and width (between 0 and 1). These will be the UV points you want to use for each face.
This method will not distort the UV texture, but it WILL need to leave OUT some of the image (unless you choose to allow those squares to overlap). Also, with this method the square edges that don't touch in the UV texture, will not have perfectly matching edges on the 3d model.
If you DO want all edges to be flush, you will need to select different UV coordinates such that the edges are indeed flush. Drawing six "squares" on the uv image obviously will NOT work for all but one face in this situation (because you simply cannot make all their edges touch; trapazoids might fit better that squares, for some faces, for example). This will probably necessitate that you distort the UV texture you are using.
EDIT: I would suggest you make some "test" texture, that makes clear EXACTLY how the image is getting distorted. I usually whip up some kind of graph-paper (or maybe a big X) with circles- looking thing. You can even draw lines of a particular color, right on your expected UV edges, to confirm that match up.
Sorry for my late response (work). Are you saying that I need to declare the UV points in each of the functions that declare the triangles?
I wrote an answer 22h ago but it has yet not been published... So I post it now as comment.
The texture stretches on all sides but top and bottom because of the following code:
for(int i = 0; i < vertices.Length; i++) {
uvs[i] = new Vector2(vertices[i].x, vertices[i].z);
}
The UVs are good on the top and bottom faces because the X and Z values are different for each corner. However, for the other faces, it makes the selected zone of the texture be a line and not a surface. This is why you get stretched faces...
Thanks for taking the time to answer. I believe I understand what you're saying but I'm not sure how to go about doing that. I'm gonna keep reading up on how to properly assign uv coordinates and whatnot. From reading the responses you guys have kindly taken the time to write, I know the problem is definitely the UV mapping, but I'm not entirely sure how to go about doing it.
Answer by cjdev · May 28, 2016 at 04:00 PM
Unfortunately, as far as I know, the only way to procedurally UV a complex mesh is to split it apart into smaller meshes so that they are connected on the UV plane. If you aren't aware, the UV coordinate system is like the XY system except that it goes from 0-1 for a typical texture (beyond 1 it tiles every whole number). To map a cube you can do it a couple ways, depending on what you need: map each face onto the entire 0-1 square, taking up the whole texture and repeating it on each face, or unfolding the cube into a "T" shape within the UV grid.
Either way you'll likely need to split it up as I said because when you add UVs to a procedural mesh you do it one for each vertex. However, when unfolding a mesh there will be points that are shared, the same vertex represented by two points in UV space. For the case of the cube you could solve it by creating 6 squares, a total of 24 verts, and create the UVs for each based on your texture. A more efficient method would be to only double up on the vertices that have more than one UV point. And finally, you could always use a custom shader and save on the vertex count.
Sorry for the late response (work).
I know how to map what part of the texture image to use, so that's not a problem. I just can't wrap my head around mapping the object I'm trying to texture. I basically want to create an object just like the primitive cube that Unity let's you create with the "Create Game Object" button, but only drawing the faces that are visible.
I believe I want to "map each face onto the entire 0-1 square, taking up the whole texture and repeating it on each face" as you put it, I just don't know how to do that.
In that case for each square you'll want to place each vertex at a corner of a 0-1 square. So there's a vertex with a UV point at 0,0 and one at 0,1 and 1,0 and 1,1. Putting them in the right order is a matter of keeping track of the vertex order and where you want them on your texture.
I think I have an idea on what to do, but I'll have to play around with it tomorrow and get back to you. Although, if you could provide a small chunk of code I might be able to better understand how to do it properly. That would take a bit of the fun out of it though.
Follow this Question
Related Questions
UV Tiling/repeat 1 Answer
Texture on custom mesh splits at edge. 1 Answer
need guide in uv texture 0 Answers
Why zero height mesh gets black independent of shader 1 Answer
How to set UV (Map) for Mesh made by script without duplicating vertices? 2 Answers