this is the part of the code that generate a mesh, if you want more information ask.
So in the scene I cannot see it, I tried to enter play mode but nothing, if I go in the inspector I can see: 4 verts, 2 tris, the right amount of tris and verts.
public void ConstructMesh()
{
Vector3[] vertices = new Vector3[(resolution + 2) * (resolution + 2)];
int[] triangles = new int[(resolution + 1) * (resolution + 1) * 6];
int triIndex = 0;
for (int y = 0; y < resolution; y++)
{
for (int x = 0; x < resolution; x++)
{
int i = x + y * resolution;
Vector2 percent = new Vector2(x, y) / (resolution - 1);
Vector3 pointOnUnitCode = localUp + (percent.x - .5f) * 2 * axisA + (percent.y - .5f) * 2 * axisB;
vertices[i] = pointOnUnitCode;
triangles[triIndex] = i;
triangles[triIndex + 1] = i + resolution + 1;
triangles[triIndex + 2] = i + resolution;
triangles[triIndex + 3] = i;
triangles[triIndex + 4] = i + 1;
triangles[triIndex + 5] = i + resolution + 1;
triIndex += 6;
}
}
planet.Clear();
planet.vertices = vertices;
planet.triangles = triangles;
planet.RecalculateNormals();
}
You need a MeshRenderer and MeshFilter in the GameObject to be able to render your mesh.
Supposing your method ConstructMesh is a MonoBehaviour and it's attached to the same object you want to display the mesh, you can do the following:
GetComponent<MeshFilter>().mesh = planet;
Related
I`m helping my friend to make his study project, and for it we need a 3d frustum, with and ability to set the diameter of the upper round surface and the bottom one in runtime, could you please advice how can it be done? I am thinking of getting the array of edgex/vertices, that are connected with the center one on the top and on the bottom, and change their coords, maybe there is an easier way to do so?
For creating a cone frustum with dynamic sizes you can use the script from http://wiki.unity3d.com/index.php/ProceduralPrimitives#C.23_-_Cone
Since you create the mesh once at beginning later you know exactly which vertices are the ones for the top and bottom plane so you can easily change them dynamically afterwards.
Somewhat like e.g.
public class DynamicConicalFrustum : MonoBehaviour
{
[SerializeField] private MeshFilter meshFilter;
[SerializeField] private MeshCollider meshCollider;
[Header("Settings")]
[SerializeField] private float _height = 1f;
[SerializeField] private float _bottomRadius = .25f;
[SerializeField] private float _topRadius = .05f;
[SerializeField] private int nbSides = 18;
private Mesh mesh;
const float _2pi = Mathf.PI * 2f;
private Vector3[] vertices;
private void Awake()
{
if (!meshFilter && !TryGetComponent<MeshFilter>(out meshFilter))
{
meshFilter = gameObject.AddComponent<MeshFilter>();
}
if(!GetComponent<MeshRenderer>())
{
var mr = gameObject.AddComponent<MeshRenderer>();
mr.material = new Material(Shader.Find("Standard"));
}
if (!meshCollider)
meshCollider = GetComponent<MeshCollider>();
mesh = meshFilter.mesh;
if (!mesh)
{
mesh = new Mesh();
}
meshFilter.mesh = mesh;
if (meshCollider)
meshCollider.sharedMesh = mesh;
RecreateFrustum(_height,_bottomRadius,_topRadius);
}
#if UNITY_EDITOR
private void OnValidate()
{
if (Application.isPlaying)
{
Awake();
}
}
#endif
public void RecreateFrustum(float height, float bottomRadius, float topRadius)
{
mesh.Clear();
int nbVerticesCap = nbSides + 1;
#region Vertices
// bottom + top + sides
vertices = new Vector3[nbVerticesCap + nbVerticesCap + nbSides * 2 + 2];
// Bottom cap
vertices[0] = new Vector3(0f, 0f, 0f);
for(var idx = 1; idx <= nbSides; idx++)
{
float rad = (float)(idx ) / nbSides * _2pi;
vertices[idx ] = new Vector3(Mathf.Cos(rad) * bottomRadius, 0f, Mathf.Sin(rad) * bottomRadius);
}
// Top cap
vertices[nbSides + 1] = new Vector3(0f, height, 0f);
for(var idx = nbSides + 2; idx <= nbSides * 2 + 1; idx++)
{
float rad = (float)(idx - nbSides - 1) / nbSides * _2pi;
vertices[idx] = new Vector3(Mathf.Cos(rad) * topRadius, height, Mathf.Sin(rad) * topRadius);
}
// Sides
int v = 0;
for(var idx = nbSides * 2 + 2; idx <= vertices.Length - 4; idx+=2)
{
float rad = (float)v / nbSides * _2pi;
vertices[idx] = new Vector3(Mathf.Cos(rad) * topRadius, height, Mathf.Sin(rad) * topRadius);
vertices[idx + 1] = new Vector3(Mathf.Cos(rad) * bottomRadius, 0, Mathf.Sin(rad) * bottomRadius);
v++;
}
vertices[vertices.Length - 2] = vertices[nbSides * 2 + 2];
vertices[vertices.Length - 1] = vertices[nbSides * 2 + 3];
#endregion
#region Triangles
int nbTriangles = nbSides + nbSides + nbSides * 2;
int[] triangles = new int[nbTriangles * 3 + 3];
// Bottom cap
int tri = 0;
int i = 0;
while (tri < nbSides - 1)
{
triangles[i] = 0;
triangles[i + 1] = tri + 1;
triangles[i + 2] = tri + 2;
tri++;
i += 3;
}
triangles[i] = 0;
triangles[i + 1] = tri + 1;
triangles[i + 2] = 1;
tri++;
i += 3;
// Top cap
//tri++;
while (tri < nbSides * 2)
{
triangles[i] = tri + 2;
triangles[i + 1] = tri + 1;
triangles[i + 2] = nbVerticesCap;
tri++;
i += 3;
}
triangles[i] = nbVerticesCap + 1;
triangles[i + 1] = tri + 1;
triangles[i + 2] = nbVerticesCap;
tri++;
i += 3;
tri++;
// Sides
while (tri <= nbTriangles)
{
triangles[i] = tri + 2;
triangles[i + 1] = tri + 1;
triangles[i + 2] = tri + 0;
tri++;
i += 3;
triangles[i] = tri + 1;
triangles[i + 1] = tri + 2;
triangles[i + 2] = tri + 0;
tri++;
i += 3;
}
#endregion
mesh.vertices = vertices;
mesh.triangles = triangles;
mesh.RecalculateBounds();
mesh.RecalculateNormals();
mesh.RecalculateTangents();
mesh.Optimize();
}
}
It's of course not really optimized currently but I hope you can keep going from there ;)
E.g. that method creates extra vertices for the sides .. one could re-use the ones from the top and bottom cap since they match positions anyway.
Further you could of course also just update the according vertices when the height and radius change, you wouldn't need to recreate the entire mesh every time since the triangles stay the same, only the vertices change positions.
This question already has an answer here:
How to use meshes with more than 64k vertices in Unity 2018.1
(1 answer)
Closed 2 years ago.
I'm trying to upload point cloud in unity C#.
Because there is no element that draws point directly, I create a cube for each point of point cloud.
So, For n points in point cloud, 8n vertices (because it is cube), 12 meshes exist for my code.
A mesh = 3 index --> a cube : 12 meshes --> 3*12 index (var name : triangles)
point XYZ are saved in PointList : List < Vector3 >
each points has color in ColorList : List< Vector3 >
I checked all vertices and meshes have correct values, and drawing points (cubes) works well.
However there is a problem. The original point cloud has 1412765 points(image1). And the number of vertices is same to it. But! If I try to draw all of them, maybe some of them are not drawn. (image2. I guess around 10000 cubes is the maximum.)
What's the problem?
float resolution = 2.5f;
int pointSize = PointList.Count;
MeshFilter mf = GetComponent<MeshFilter>();
Mesh mesh = new Mesh();
mf.mesh = mesh;
Vector3[] vertices;
vertices = new Vector3[pointSize * 8];
for (int i = 0; i < pointSize; i++)
{
float x = PointList[i].x;
float y = PointList[i].y;
float z = PointList[i].z;
vertices[i * 8 + 0] = new Vector3(x - resolution, y - resolution, z - resolution);
vertices[i * 8 + 1] = new Vector3(x + resolution, y - resolution, z - resolution);
vertices[i * 8 + 2] = new Vector3(x + resolution, y + resolution, z - resolution);
vertices[i * 8 + 3] = new Vector3(x - resolution, y + resolution, z - resolution);
vertices[i * 8 + 4] = new Vector3(x - resolution, y + resolution, z + resolution);
vertices[i * 8 + 5] = new Vector3(x + resolution, y + resolution, z + resolution);
vertices[i * 8 + 6] = new Vector3(x + resolution, y - resolution, z + resolution);
vertices[i * 8 + 7] = new Vector3(x - resolution, y - resolution, z + resolution);
}
mesh.vertices = vertices;
int[] triangles;
triangles = new int[pointSize * 12 * 3];
triangles[0] = 0;
triangles[1] = 2;
triangles[2] = 1;
triangles[3] = 0;
triangles[4] = 3;
triangles[5] = 2;
triangles[6] = 2;
triangles[7] = 3;
triangles[8] = 4;
triangles[9] = 2;
triangles[10] = 4;
triangles[11] = 5;
triangles[12] = 1;
triangles[13] = 2;
triangles[14] = 5;
triangles[15] = 1;
triangles[16] = 5;
triangles[17] = 6;
triangles[18] = 0;
triangles[19] = 7;
triangles[20] = 4;
triangles[21] = 0;
triangles[22] = 4;
triangles[23] = 3;
triangles[24] = 5;
triangles[25] = 4;
triangles[26] = 7;
triangles[27] = 5;
triangles[28] = 7;
triangles[29] = 6;
triangles[30] = 0;
triangles[31] = 6;
triangles[32] = 7;
triangles[33] = 0;
triangles[34] = 1;
triangles[35] = 6;
for (int i = 1; i < pointSize; i++)
{
for (int j = 0; j < 36; j++)
{
int val = triangles[j] + 8 * i;
triangles[i * 36 + j] = triangles[j] + 8 * i;
}
}
mesh.triangles = triangles;
Color32[] colors = new Color32[mesh.vertices.Length];
for (int i = 0; i < pointSize; i++)
{
for (int j = 0; j < 8; j++)
{
Color32 newColor = new Color32(
(byte)ColorList[i].x,
(byte)ColorList[i].y,
(byte)ColorList[i].z,
255);
colors[i * 8 + j] = newColor;
}
}
mesh.colors32 = colors;
Debug.Log("points : " + PointList.Count);
Debug.Log("vertices (point*8): " + mesh.vertices.Length);
Debug.Log("triangles (point*36): " + mesh.triangles.Length);
Debug.Log("colors (points*8): " + mesh.colors32.Length);
}
I found an anser!!!!
the maximum number of vertices is 65535 when using mesh!!!
Adding just one line can solve this problem
mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
How to use meshes with more than 64k vertices in Unity 2018.1
So for some reason, this map generation works for up to xSize=100 and zSize=100.
As soon as I go further it does weird things like this (at xSize=300 and zSize=300):
Going even more up to 1000x1000 it generates something like this:
I have no idea why it works just up to 100x100.
Is there some mesh limitation I'm not aware of?
I first thought just the vertices weren't connecting properly but then after doing the 1000x1000 example and looking the 300x300 example from top it definitely doesn't even make the vertices in right place...
I can't see an error in my code for some reason. I'm stuck here looking the code blindly all day.
Any help?
Code [Just the CreateMapXZ() function]:
vertices = new Vector3[(xSize + 1) * (zSize + 1)];
uvs = new Vector2[(xSize + 1) * (zSize + 1)];
float uvFactorX = 1.0f / xSize;
float uvFactorZ = 1.0f / zSize;
for (int i = 0, z = 0; z <= zSize; z++)
{
for (int x = 0; x <= xSize; x++)
{
vertices[i] = new Vector3(x, 0, z);
uvs[i++] = new Vector2(x * uvFactorX, z * uvFactorZ);
//i++;
}
}
triangles = new int[xSize * zSize * 6];
int vert = 0;
int tris = 0;
for (int z = 0; z < zSize; z++)
{
for (int x = 0; x < xSize; x++)
{
triangles[tris + 0] = vert + 0;
triangles[tris + 1] = vert + xSize + 1;
triangles[tris + 2] = vert + 1;
triangles[tris + 3] = vert + 1;
triangles[tris + 4] = vert + xSize + 1;
triangles[tris + 5] = vert + xSize + 2;
vert++;
tris += 6;
}
vert++;
}
applyNoise();
UpdateMesh();
I am trying to start work on learning strategy/base building games in unity. I started out by copying code from this video but my version only does a single line of squares.
It is the z dimension that does not continue and it does seem like it is a problem with the triangles/normals as the vertices seem to be in the right place via making the vertices a public variable and seeing them in unity's inspector. I think I'd have to write a widget to show the vertices to be sure as I'm no mathematician. I removed the actual creation of the object in unity for the sake of brevity as there is no math involved. Also the procedural object does seem to crumble to nothing at larger sizes, although that's not really an issue until the first one is fixed.
void BuildMesh()
{
int numTiles = size_x * size_z;
int numTris = numTiles * 2;
int vsize_x = size_x + 1;
int vsize_z = size_z + 1;
int numVerts = vsize_x * vsize_z;
//Generate Mesh Data
vertices = new Vector3[ numVerts ];
Vector3[] normals = new Vector3[ numVerts ];
Vector2[] uv = new Vector2[ numVerts ];
int[] triangles = new int[ numTris * 3];
int x, z;
for (z = 0; z < vsize_z; z++)
{
for (x = 0; x < vsize_x; x++)
{
vertices[z * vsize_x + x] = new Vector3(x * tileSize, 0, z * tileSize);
normals[ z * vsize_x + x] = Vector3.up;
uv[z * vsize_x + x] = new Vector2((float)x / vsize_x, (float)z / vsize_z);
}
}
for (z = 0; z < size_z; z++)
{
for (x = 0; x < size_x; x++)
{
int squareIndex = x * size_x + x;
int triOffset = squareIndex * 6;
triangles[triOffset + 0] = z * vsize_x + x + 0;
triangles[triOffset + 1] = z * vsize_x + x + vsize_x + 0;
triangles[triOffset + 2] = z * vsize_x + x + vsize_x + 1;
triangles[triOffset + 3] = z * vsize_x + x + 0;
triangles[triOffset + 4] = z * vsize_x + x + vsize_x + 1;
triangles[triOffset + 5] = z * vsize_x + x + 1;
}
}
The code from the video:
derHugo answered the question in the comments. Just posting this to mark it as answered. Thanks.
I'm following this tutorial set: https://www.youtube.com/watch?v=owBt9SNKXCI&index=6&list=PLbghT7MmckI4qGA0Wm_TZS8LVrqS47I9R to dynamically build a tile map layout. It works to a point, but it generates a very strange layout with 128 x 128 sized tiles.
Clearly that strange partitioning shouldn't be happening, but I cannot seem to track down what's going on to cause it. Here is my version of the code, which is mostly identical to quill18creates's version sans a few small differences:
using UnityEngine;
using System.Collections;
[ExecuteInEditMode]
public class TileMap : MonoBehaviour {
public int size_x = 100;
public int size_z = 50;
public float tileSize = 1.0f;
public Texture2D terrainTiles;
int tileResolution = 128;
// Use this for initialization
void Start () {
BuildMesh();
}
Color[][] ChopUpTiles() {
int numTilesPerRow = terrainTiles.width / tileResolution;
int numRows = terrainTiles.height / tileResolution;
Color[][] tiles = new Color[numTilesPerRow*numRows][];
for(int y=0; y < numRows; y++) {
for(int x=0; x < numTilesPerRow; x++) {
tiles[y * numTilesPerRow + x] = terrainTiles.GetPixels( x*tileResolution , y*tileResolution, tileResolution, tileResolution );
}
}
return tiles;
}
void BuildTexture() {
//DTileMap map = new DTileMap(size_x, size_z);
int texWidth = size_x * tileResolution;
int texHeight = size_z * tileResolution;
Texture2D texture = new Texture2D(texWidth, texHeight);
Color[][] tiles = ChopUpTiles();
for(int y=0; y < size_z; y++) {
for(int x=0; x < size_x; x++) {
Color[] p = tiles[Mathf.RoundToInt(Random.Range(0, 5))];
texture.SetPixels(x * tileResolution, y * tileResolution, tileResolution, tileResolution, p);
}
}
//texture.filterMode = FilterMode.Bilinear;
texture.wrapMode = TextureWrapMode.Clamp;
texture.Apply();
MeshRenderer mesh_renderer = GetComponent<MeshRenderer>();
mesh_renderer.sharedMaterials[0].mainTexture = texture;
}
public void BuildMesh() {
int numTiles = size_x * size_z;
int numTris = numTiles * 2;
int vsize_x = size_x + 1;
int vsize_z = size_z + 1;
int numVerts = vsize_x * vsize_z;
// Generate the mesh data
Vector3[] vertices = new Vector3[ numVerts ];
Vector3[] normals = new Vector3[numVerts];
Vector2[] uv = new Vector2[numVerts];
int[] triangles = new int[ numTris * 3 ];
int x, z;
for(z=0; z < vsize_z; z++) {
for(x=0; x < vsize_x; x++) {
vertices[ z * vsize_x + x ] = new Vector3( x*tileSize, 0, -z*tileSize );
normals[ z * vsize_x + x ] = Vector3.up;
uv[ (z * vsize_x) + x ] = new Vector2( (float)x / size_x, (float)z / size_z );
}
}
Debug.Log ("Done Verts!");
for(z=0; z < size_z; z++) {
for(x=0; x < size_x; x++) {
int squareIndex = z * size_x + x;
int triOffset = squareIndex * 6;
triangles[triOffset + 0] = z * vsize_x + x + 0;
triangles[triOffset + 2] = z * vsize_x + x + vsize_x + 0;
triangles[triOffset + 1] = z * vsize_x + x + vsize_x + 1;
triangles[triOffset + 3] = z * vsize_x + x + 0;
triangles[triOffset + 5] = z * vsize_x + x + vsize_x + 1;
triangles[triOffset + 4] = z * vsize_x + x + 1;
}
}
// Create a new Mesh and populate with the data
Mesh mesh = new Mesh();
mesh.vertices = vertices;
mesh.triangles = triangles;
mesh.normals = normals;
mesh.uv = uv;
// Assign our mesh to our filter/renderer/collider
MeshFilter mesh_filter = GetComponent<MeshFilter>();
MeshCollider mesh_collider = GetComponent<MeshCollider>();
mesh_filter.mesh = mesh;
mesh_collider.sharedMesh = mesh;
BuildTexture();
}
}
I don't get exactly what part is wrong in the image but I think it is that the same tiles are lumping together.
I tried your code and it works well for me. But I guess the following part could be causing the lumping together problem for you:
Color[] p = tiles[Mathf.RoundToInt(Random.Range(0, 5))];
Instead you should do:
Color[] p = tiles[Random.Range(0, 5)];
Because, the other way, Random is generating float numbers and maybe they are near the each other that rounding them to the integer gives same tile. Give it a try.
Also just reminding, make sure the width and the height of your texture is divisible by 128.
Well, it was definitely a size issue, but there was also an issue with positioning. Tiles have to start at the bottom-left corner for the coordinate system to find them.