- Home /
Animated procedural mesh stops animating when I use it's vertices to place objects on it's surface.
Hi, I have two scripts that don't seem to work together.
The first script creates a plane and animates it using sine waves. (based off Catlike Coding) The second script takes the vertices positions and randomly places prefabs on them. Independently they work as intended, but when applied on the same game object, the mesh stops moving. However the gizmos attached to the vertices still do.
This is the first script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(MeshRenderer), typeof(MeshFilter))]
public class VertexGraph : Graph {
private Vector3[] vertices;
private Mesh mesh;
int xSize, zSize;
protected override void OnValidate(){
Generate();
base.OnValidate();
}
void Awake () {
// Generate();
Displace();
}
void Update () {
if (animate){
Displace();
}
}
private void Generate(){
GetComponent<MeshFilter>().mesh = mesh = new Mesh();
mesh.name = "Vertex Graph";
vertices = new Vector3[(resolution + 1) * (resolution + 1)];
Vector2[] uv = new Vector2[vertices.Length];
Vector4[] tangents = new Vector4[vertices.Length];
Vector4 tangent = new Vector4 (1f, 0f, 0f, -1f);
xSize = resolution / 2;
zSize = resolution / 2;
for (int i = 0, z = -zSize; z <= zSize; z++){
for (int x = -xSize; x <= xSize; x++, i++){
vertices[i] = new Vector3 (x, 0, z);
uv[i] = new Vector2((float) x / xSize, (float) z / zSize);
tangents[i] = tangent;
}
}
mesh.vertices = vertices;
mesh.uv = uv;
mesh.tangents = tangents;
int[] triangles = new int[resolution * resolution * 6];
for (int ti = 0, vi = 0, y = 0; y < resolution; y++, vi++){
for (int x = 0; x < resolution; x++, ti +=6, vi++){
triangles[ti] = vi;
triangles[ti + 3] = triangles[ti + 2] = vi + 1;
triangles[ti + 4] = triangles[ti + 1] = vi + resolution + 1;
triangles[ti + 5] = vi + resolution + 2;
}
}
mesh.triangles = triangles;
mesh.RecalculateNormals();
}
protected override void Displace(){
float t = Time.time * speed;
GraphFunction f = Graph.functions[(int)function];
float stepU = step / resolution;
for (int i = 0, z = 0; z <= resolution; z++) {
float v = (z + 0.5f) * stepU - 1;
for (int x = 0; x <= resolution; x++, i++) {
float u = (x + 0.5f) * stepU - 1;
vertices[i] = Vector3.Scale(f(u, v, t), amplitude);
}
}
mesh.vertices = vertices;
mesh.RecalculateNormals();
MeshCollider meshCollider;
if (GetComponent<MeshCollider>()) { meshCollider = GetComponent<MeshCollider>(); }
else { meshCollider = gameObject.AddComponent<MeshCollider>(); }
meshCollider.sharedMesh = null;
meshCollider.sharedMesh = GetComponent<MeshFilter>().sharedMesh;
}
private void OnDrawGizmosSelected()
{
if (vertices == null)
{
return;
}
Gizmos.color = Color.black;
for (int i = 0; i < vertices.Length; i++)
{
Vector3 worldPt = transform.TransformPoint(vertices[i]);
Gizmos.DrawSphere(worldPt, 0.01f);
}
}
}
And the second script: / Created with help from http://catlikecoding.com/unity/tutorials/swirly-pipe/ /
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
public class RiverObstacles : MonoBehaviour {
[Tooltip("Prefabs to use as obstacles in the river.")]
[SerializeField]private GameObject[] obstacles;
[Tooltip("Prefabs to use as overhead obstacles.")]
[SerializeField]private GameObject[] overheadObstacles;
[Tooltip("How many obstacles can appear on this river?")]
[SerializeField]private int obstacleLimit = 0;
[Tooltip("Does this river have overhanging obstacles?")]
[SerializeField]private bool overhead = false;
[Tooltip("How many overhead obstacles can appear on this river?")]
[SerializeField]private int overheadLimit = 0;
[Tooltip("The range of height for overhead obstacles to spawn at.")]
[MinMaxSlider(1f, 3f)] [SerializeField]private Vector2 overheadHeight = new Vector2 (1.5f, 2.0f);
[Tooltip("Global scale of obstacles.")]
[SerializeField]private Vector3 obstacleScale = Vector3.one;
[SerializeField]private Mesh riverMesh;
private int obstaclesCount = 0;
private int overheadCount = 0;
private GameObject[] activeObstacles;
private GameObject[] activeOverhead;
private Vector3[] riverVertices;
// Use this for initialization
void Start () {
if (!riverMesh) { riverMesh = GetComponent<MeshFilter>().mesh; }
activeObstacles = new GameObject[obstacleLimit];
activeOverhead = new GameObject[overheadLimit];
riverVertices = riverMesh.vertices;
for (int i = 0; i < riverVertices.Length; i++)
{
riverVertices[i] = transform.TransformPoint(riverVertices[i]);
}
SetObstacleLocations();
if (overhead)
{
SetOverheadObstacles();
}
}
// Update is called once per frame
void Update () {
if (Input.GetKeyDown(KeyCode.Space))
{
SetObstacleLocations();
if (overhead)
{
SetOverheadObstacles();
}
}
}
private void SetObstacleLocations()
{
bool[] filledLocations = new bool[riverVertices.Length];
if (obstaclesCount >= obstacleLimit)
{
int obstaclesDestroyed = 0;
foreach (GameObject o in activeObstacles)
{
Destroy(o);
obstaclesDestroyed++;
}
obstaclesCount = 0;
Debug.Log ("Cleaned up " + obstaclesDestroyed + " obstacles.");
}
for (int i = 0; i < obstacleLimit; i++)
{
//obstacle location randomly chosen from vertices
int loc = Random.Range(0, riverVertices.Length);
//obstacle object randomly chosen from obstacle array
int obj = Random.Range(0, obstacles.Length);
while (filledLocations[loc])
{
loc = Random.Range(0, riverVertices.Length);
}
filledLocations[loc] = true;
Vector3 pos = riverVertices[loc];
Quaternion rot = Quaternion.Euler(Random.Range(0, 360), Random.Range(0, 360), Random.Range(0, 360));
GameObject newObstacle = Instantiate<GameObject> (obstacles[obj]);
Vector3 sca = divideVector3(newObstacle.transform.localScale, transform.localScale);
newObstacle.transform.SetParent(transform, false);
newObstacle.transform.localScale = sca;
newObstacle.transform.position = pos;
// newObstacle.transform.localRotation = rot;
//changing rotation messes with scaling. :(
activeObstacles[i] = newObstacle;
obstaclesCount++;
}
//Debug.Log (obstaclesCount + " obstacles created.");
}
private void SetOverheadObstacles()
{
bool[] filledLocations = new bool[riverVertices.Length-1];
if (overheadCount >= overheadLimit)
{
int overheadDestroyed = 0;
foreach (GameObject o in activeOverhead)
{
Destroy(o);
overheadDestroyed++;
}
overheadCount = 0;
Debug.Log ("Cleaned up " + overheadDestroyed + " overhead obstacles.");
}
for (int i = 0; i < overheadLimit; i++)
{
//obstacle location randomly chosen from vertices
int loc = Random.Range(0, riverVertices.Length);
//obstacle object randomly chosen from obstacle array
int obj = Random.Range(0, overheadObstacles.Length);
while (filledLocations[loc])
{
loc = Random.Range(0, riverVertices.Length);
}
float obsOverheadHeight = Random.Range(overheadHeight.x, overheadHeight.y);
filledLocations[loc] = true;
Vector3 pos = new Vector3 (0f, riverVertices[loc].y + obsOverheadHeight, riverVertices[loc].z);
Quaternion rot = Quaternion.Euler(Random.Range(0, 360), Random.Range(-20, 20), 0f);
GameObject newOverhead = Instantiate<GameObject> (overheadObstacles[obj], transform);
Vector3 sca = divideVector3(newOverhead.transform.localScale, transform.localScale);
newOverhead.transform.localScale = sca;
newOverhead.transform.position = pos;
// newOverhead.transform.rotation = rot;
//changing rotation messes with scaling. :(
activeOverhead[i] = newOverhead;
overheadCount++;
}
//Debug.Log (overheadCount + " overhead obstacles created.");
}
private Vector3 divideVector3(Vector3 a, Vector3 b)
{
Vector3 result;
result = new Vector3(
a.x / b.x,
a.y / b.y,
a.z / b.z
);
return result;
}
}
Does anyone have any ideas why the mesh would stop updating? It seems to work fine if I generate a mesh without animating it and then enable animation, but only through the inspector. Getting a script to do it will have the same result as having it enabled in the beginning.