Mesh collider only working on part of procedurally generated mesh
Hi, I currently have a problem with my mesh collider only appearing to work on part of my mesh however, in the video below I can see that my mesh collider covers the entire terrain mesh so I'm not quite sure what I've done wrong.
The mesh I'm generating is using Perlin noise to get random heights. I have also changed the mesh vert limit to use UnityEngine.Rendering.IndexFormat.UInt32 rather than the default 16 bits so that I can create a larger mesh with more vertices and I'm not sure if that would have any implications on the MeshCollider.
Also the reason I believe this is the collider at fault is because: 1. The player falls through the terrain but only at certain points. 2. I am using raycasts to place the trees and rocks and they only place if the raycast hits a collider but the trees and rocks are not spawning over the entire mesh.
Here is my code and the video I mentioned:
Code for my mesh generation:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(MeshFilter))]
public class MeshGenerator : MonoBehaviour
{
public Vector3[] Verticies;
int[] Triangles;
public int xSize = 125;
public int zSize = 125 + 0;
public ForestGenerator forestGenerator;
public Vector3 StartPosition;
public MapGenerator mapGenerator;
// Values for comnrolling attributes of the noise that gets the height of the terrain.
public float TerrainScale = 1000f;
public float HeightMultiplier = 700f;
public float terrainBumpiness;
public float bumpFrequency;
//Variables for noise
public float[,] heightMap;
MeshFilter meshFilter;
MeshRenderer meshRenderer;
public Material material;
Mesh mesh;
//MeshCollider meshCollider;
//GameObject[] mapSegments;
public GameObject Generate() // Generate should be called from other scripts to creeate the mesh
{
mesh = new Mesh();
mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32; // Set the index format which means we can have 4bn verts in our mesh
mesh.Clear();
GetComponent<MeshFilter>().mesh = mesh;
//heightMap = new float[xSize + 1, zSize + 1];
GameObject map = new GameObject() // Create new game object to attach the mesh to.
{
name = "Map segment",
tag = "Plane"
};
CreateShape();
UpdateMesh();
// Set up the new game object so that it has the correct components.
MeshRenderer meshRenderer = map.AddComponent<MeshRenderer>();
meshRenderer.material = material;
MeshCollider meshCollider = map.AddComponent<MeshCollider>();
mesh.RecalculateBounds();
meshCollider.sharedMesh = mesh;
meshCollider.transform.SetParent(gameObject.transform);
map.AddComponent<MeshFilter>().mesh = mesh;
return map;
}
public GameObject GenerateV2()
{
mesh = new Mesh();
mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32; // Set the index format which means we can have 4bn verts in our mesh
mesh.Clear();
GetComponent<MeshFilter>().mesh = mesh;
CreateShape();
UpdateMesh();
// Set up the new game object so that it has the correct components.
MeshRenderer meshRenderer = gameObject.AddComponent<MeshRenderer>();
meshRenderer.material = material;
MeshCollider meshCollider = GetComponent<MeshCollider>();
meshCollider.sharedMesh = mesh;
meshCollider.transform.SetParent(gameObject.transform);
gameObject.AddComponent<MeshFilter>().mesh = mesh;
return gameObject;
}
public void CreateShape()
{
Verticies = new Vector3[(xSize + 1) * (zSize + 1)];
float xPos;
float zPos;
for (int i = 0, z = 0; z <= zSize; z++) // loop through and generate the position and height of each verticy that makes up the ground mesh.
{
for (int x = 0; x <= xSize; x++)
{
zPos = StartPosition.z + z;
xPos = StartPosition.x + x;
Vector3 mapValue = new Vector3(xPos, 0f, zPos);
mapValue.y = heightMap[x, z] * HeightMultiplier;
Verticies[i] = mapValue;
i++;
}
}
int vert = 0;
int tris = 0;
Triangles = new int[xSize * zSize * 6];
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++;
}
}
void UpdateMesh()
{
mesh.Clear();
mesh.vertices = Verticies;
mesh.triangles = Triangles;
mesh.RecalculateBounds();
mesh.RecalculateNormals();
}
void OnDrawGizmosSelected()
{
if (Verticies == null)
return;
for (int i = 0; i < Verticies.Length; i+=1000)
{
Gizmos.DrawSphere(Verticies[i], 1f);
}
}
}
Code for the noise generation:
using UnityEngine;
using System.Collections;
public static class Noise {
public static float[,] GenerateNoiseMap(int mapWidth, int mapHeight, int seed, float scale, int octaves, float persistance, float lacunarity, Vector2 offset) {
float[,] noiseMap = new float[mapWidth, mapHeight];
Debug.Log("noiseMap length = " + noiseMap.Length + ", mapWidth = " + mapWidth + ", mapHeight = " + mapHeight);
System.Random prng = new System.Random (seed);
Vector2[] octaveOffsets = new Vector2[octaves];
for (int i = 0; i < octaves; i++) {
float offsetX = prng.Next (-100000, 100000) + offset.x;
float offsetY = prng.Next (-100000, 100000) + offset.y;
octaveOffsets [i] = new Vector2 (offsetX, offsetY);
}
if (scale <= 0) {
scale = 0.0001f;
}
float maxNoiseHeight = float.MinValue;
float minNoiseHeight = float.MaxValue;
float halfWidth = mapWidth / 2f;
float halfHeight = mapHeight / 2f;
for (int y = 0; y < mapHeight; y++) {
for (int x = 0; x < mapWidth; x++) {
float amplitude = 1;
float frequency = 1;
float noiseHeight = 0;
for (int i = 0; i < octaves; i++)
{
// float sampleX = (x - halfWidth) / scale * frequency + octaveOffsets[i].x + .1f;
// float sampleY = (y - halfHeight) / scale * frequency + octaveOffsets[i].y + .1f;
float sampleY = y / scale * frequency;
float sampleX = x / scale * frequency;
float perlinValue = Mathf.PerlinNoise (sampleX, sampleY) * 2 - 1;
noiseHeight += perlinValue * amplitude;
amplitude *= persistance;
frequency *= lacunarity;
}
if (noiseHeight > maxNoiseHeight) {
maxNoiseHeight = noiseHeight;
} else if (noiseHeight < minNoiseHeight) {
minNoiseHeight = noiseHeight;
}
noiseMap [x, y] = noiseHeight;
}
}
for (int y = 0; y < mapHeight; y++) {
for (int x = 0; x < mapWidth; x++) {
noiseMap [x, y] = Mathf.InverseLerp (minNoiseHeight, maxNoiseHeight, noiseMap [x, y]);
}
}
return noiseMap;
}
}
Would appreciate any help at all!
Many thanks, Brad.
Answer by anonyme0273 · Apr 08 at 10:20 AM
I've had the same issue, somehow, removing the line
meshCollider.sharedMesh = mesh;
worked for me, though my code was more barebones. ,I've had the same issue with similar code, somehow, removing the
meshCollider.sharedMesh = mesh;
line worked, though I only had barebones generation, not as indepth as yours.