Example #1
0
 /// <summary>
 /// Clone constructor
 /// </summary>
 /// <param name="lbMesh"></param>
 public LBMesh(LBMesh lbMesh)
 {
     // A Mesh cannot be created outside the main Unity thread and must be called
     // from that is typically inherited from MonoBehaviour
     this.mesh      = null;
     this.title     = lbMesh.title;
     this.verts     = new List <Vector3>(lbMesh.verts);
     this.normals   = new List <Vector3>(lbMesh.normals);
     this.triangles = new List <int>(lbMesh.triangles);
     if (lbMesh.uvs != null)
     {
         this.uvs = new List <Vector2>(lbMesh.uvs);
     }
     else
     {
         uvs = new List <Vector2>();
     }
     if (lbMesh.uv2s != null)
     {
         this.uv2s = new List <Vector2>(lbMesh.uv2s);
     }
     else
     {
         uv2s = new List <Vector2>();
     }
     if (lbMesh.uv3s != null)
     {
         this.uv3s = new List <Vector2>(lbMesh.uv3s);
     }
     else
     {
         uv3s = new List <Vector2>();
     }
     if (lbMesh.uv4s != null)
     {
         this.uv4s = new List <Vector2>(lbMesh.uv4s);
     }
     else
     {
         uv4s = new List <Vector2>();
     }
     if (lbMesh.tangents != null)
     {
         this.tangents = new List <Vector4>(lbMesh.tangents);
     }
     else
     {
         tangents = new List <Vector4>();
     }
     minExtent = lbMesh.minExtent;
     maxExtent = lbMesh.maxExtent;
 }
Example #2
0
 /// <summary>
 /// Delete the Unity Mesh class instance and release memory. Clears all LBMesh data but doesn't delete the class instance.
 /// NOTE: Memory will be released by LB back to the available heap within Unity. However, whether or not Unity
 /// releases that memory back to the OS or not is beyond the control of LB.
 /// </summary>
 /// <param name="lbMesh"></param>
 public static void DeleteMesh(LBMesh lbMesh)
 {
     if (lbMesh != null)
     {
         if (lbMesh.mesh != null)
         {
             lbMesh.mesh.Clear(false); lbMesh.mesh = null;
         }
         if (lbMesh.normals != null)
         {
             lbMesh.normals.Clear(); lbMesh.normals.TrimExcess(); lbMesh.normals = null;
         }
         if (lbMesh.tangents != null)
         {
             lbMesh.tangents.Clear(); lbMesh.tangents.TrimExcess(); lbMesh.tangents = null;
         }
         if (lbMesh.uvs != null)
         {
             lbMesh.uvs.Clear(); lbMesh.uvs.TrimExcess(); lbMesh.uvs = null;
         }
         if (lbMesh.uv2s != null)
         {
             lbMesh.uv2s.Clear(); lbMesh.uv2s.TrimExcess(); lbMesh.uv2s = null;
         }
         if (lbMesh.uv3s != null)
         {
             lbMesh.uv3s.Clear(); lbMesh.uv3s.TrimExcess(); lbMesh.uv3s = null;
         }
         if (lbMesh.uv4s != null)
         {
             lbMesh.uv4s.Clear(); lbMesh.uv4s.TrimExcess(); lbMesh.uv4s = null;
         }
         if (lbMesh.triangles != null)
         {
             lbMesh.triangles.Clear(); lbMesh.triangles.TrimExcess(); lbMesh.triangles = null;
         }
         if (lbMesh.verts != null)
         {
             lbMesh.verts.Clear(); lbMesh.verts.TrimExcess(); lbMesh.verts = null;
         }
         System.GC.Collect();
     }
 }
        /// <summary>
        /// Create an LBMesh object to hold the water mesh for a Topography Image Modifier Layer.
        /// </summary>
        /// <param name="landscape"></param>
        /// <param name="lbLayer"></param>
        /// <param name="layerIdx"></param>
        /// <param name="meshTitle"></param>
        /// <param name="showErrors"></param>
        /// <returns></returns>
        public static bool CreateMeshForWaterFromLayer(LBLandscape landscape, LBLayer lbLayer, int layerIdx, string meshTitle, bool showErrors)
        {
            bool isSuccessful = false;

            string methodName = "LBMeshOperations.CreateMeshForWaterFromLayer";

            if (landscape == null)
            {
                if (showErrors)
                {
                    Debug.LogWarning("ERROR: " + methodName + " landscape is null. Please Report");
                }
            }
            else if (lbLayer == null)
            {
                if (showErrors)
                {
                    Debug.LogWarning("ERROR: " + methodName + " lbLayer is null. Please Report");
                }
            }
            else if (lbLayer.type != LBLayer.LayerType.ImageModifier)
            {
                if (showErrors)
                {
                    Debug.LogWarning("ERROR: " + methodName + " LayerType must be ImageModifier. Please Report");
                }
            }
            {
                // TODO get the minium area below zero for the RAW modifier file to use for meshWidth/Length

                // Get the absolute width and length
                Vector2 meshSize = Vector2.zero;
                meshSize.x = lbLayer.areaRect.width < 0 ? -lbLayer.areaRect.width : lbLayer.areaRect.width;
                meshSize.y = lbLayer.areaRect.height < 0 ? -lbLayer.areaRect.height : lbLayer.areaRect.height;

                // Get the bottom-left point of mesh with landscape (it might be outside the landscape)
                Vector2 meshBottomLeft = Vector2.zero;
                meshBottomLeft.x = lbLayer.areaRect.x - (meshSize.x / 2f);
                meshBottomLeft.y = lbLayer.areaRect.y - (meshSize.y / 2f);
                if (meshBottomLeft.x < 0)
                {
                    meshBottomLeft.x += meshSize.x;
                }
                else if (meshBottomLeft.x == meshSize.x)
                {
                    meshBottomLeft.x = 0f;
                }
                if (meshBottomLeft.y < 0)
                {
                    meshBottomLeft.y += meshSize.y;
                }
                else if (meshBottomLeft.y == meshSize.y)
                {
                    meshBottomLeft.y = 0f;
                }

                //Debug.Log("INFO: " + methodName + " areaRect xy: " + lbLayer.areaRect.x + "," + lbLayer.areaRect.y + " b-l:" + meshBottomLeft);

                // If there is an existing LBMesh instance, remove all the mesh data
                if (lbLayer.modifierWaterLBMesh != null)
                {
                    LBMesh.DeleteMesh(lbLayer.modifierWaterLBMesh);
                }
                else
                {
                    lbLayer.modifierWaterLBMesh = new LBMesh();
                }

                if (lbLayer.modifierWaterLBMesh == null)
                {
                    if (showErrors)
                    {
                        Debug.LogWarning("ERROR: " + methodName + " Could not create LBMesh for the water in Layer " + (layerIdx + 1) + ". Please Report");
                    }
                }
                else if (meshSize.x < 0.1f || meshSize.y < 0.1f)
                {
                    { if (showErrors)
                      {
                          Debug.LogWarning("ERROR: " + methodName + " LayerType " + (layerIdx + 1) + " has an invalid water mesh size " + meshSize.x + "," + meshSize.y);
                      }
                    }
                }
                {
                    lbLayer.modifierWaterLBMesh.title = meshTitle;

                    // Initialise mesh lists
                    List <Vector3> verts     = new List <Vector3>();
                    List <Vector2> uvs       = new List <Vector2>();
                    List <int>     triangles = new List <int>();
                    List <Vector3> normals   = new List <Vector3>();
                    List <Vector4> tangents  = new List <Vector4>();
                    List <Vector4> colours   = new List <Vector4>(); // Store as Vector4s rather than Color so they are serializable

                    // Declare outside loops for less garbage collection
                    // We are creating a flat plane, so can use Vector2.
                    Vector2 vertPositionN     = Vector2.zero; // Normalised position within mesh
                    Vector2 vertLandscapePosN = Vector2.zero; // Normalised postion within the landscape
                    int     vertCount         = 0;

                    // Default colour of each vert (stored in LB as a Vector4)
                    Vector4 defaultVertColour = new Vector4(1f, 1f, 1f, 1f);

                    // The number of cells wide and long in the mesh
                    int meshWidth  = 10;
                    int meshLength = 10;

                    for (int x = 0; x < meshWidth; x++)
                    {
                        for (int z = 0; z < meshLength; z++)
                        {
                            // Create the vert as a 0-1 position
                            // Normalise the RAW Pixel - converting it to a range of 0 to 1
                            vertPositionN.x = (float)x / (float)(meshWidth - 1);
                            vertPositionN.y = (float)z / (float)(meshLength - 1);
                            verts.Add(new Vector3(vertPositionN.x * meshSize.x, 0f, vertPositionN.y * meshSize.y));
                            normals.Add(Vector3.up);

                            if (lbLayer.modifierWaterIsMeshLandscapeUV)
                            {
                                // UVs normalised to the landscape
                                vertLandscapePosN.x = ((vertPositionN.x * meshSize.x) + meshBottomLeft.x) / landscape.size.x;
                                vertLandscapePosN.y = ((vertPositionN.y * meshSize.y) + meshBottomLeft.y) / landscape.size.y;

                                uvs.Add(new Vector2(vertLandscapePosN.x / lbLayer.modifierWaterMeshUVTileScale.x, vertLandscapePosN.y / lbLayer.modifierWaterMeshUVTileScale.y));
                            }
                            else
                            {
                                // Generic uvs (simply 0-1 coordinates of vert position)
                                uvs.Add(new Vector2(vertPositionN.x / lbLayer.modifierWaterMeshUVTileScale.x, vertPositionN.y / lbLayer.modifierWaterMeshUVTileScale.y));
                            }

                            // Create tangent
                            tangents.Add(new Vector4(1f, 0f, 0f, 1f));

                            // Add the two triangles for the quad
                            // Not required if on left or bottom edges of the mesh
                            if (x < meshWidth - 1 && z < meshLength - 1)
                            {
                                // Bottom (left) triangle
                                // Bottom left of quad
                                triangles.Add(vertCount);
                                // Bottom right of quad
                                triangles.Add(vertCount + 1);
                                // Top right of quad
                                triangles.Add(vertCount + meshWidth + 1);

                                // Top (right) triangle
                                // Top left of quad
                                triangles.Add(vertCount + meshWidth);
                                // Bottom left of quad
                                triangles.Add(vertCount);
                                // Top right of quad
                                triangles.Add(vertCount + meshWidth + 1);
                            }

                            // Set default vert colour
                            colours.Add(defaultVertColour);

                            // Increment the vert count
                            vertCount++;
                        }
                    }

                    lbLayer.modifierWaterLBMesh.verts     = verts;
                    lbLayer.modifierWaterLBMesh.triangles = triangles;
                    lbLayer.modifierWaterLBMesh.normals   = normals;
                    lbLayer.modifierWaterLBMesh.uvs       = uvs;
                    lbLayer.modifierWaterLBMesh.tangents  = tangents;

                    //Debug.Log("INFO " + methodName + " - created Mesh (verts " + verts.Count + " tris " + (triangles.Count / 3) + ")");

                    isSuccessful = true;
                }
            }

            return(isSuccessful);
        }
        /// <summary>
        /// Add a LBMesh mesh to a new gameobject in the scene as a child of the parentTransform
        /// </summary>
        /// <param name="lbMesh"></param>
        /// <param name="position"></param>
        /// <param name="gameobjectName"></param>
        /// <param name="parentTransform"></param>
        /// <param name="meshMaterial"></param>
        /// <param name="isStatic"></param>
        /// <param name="checkForExisting"></param>
        /// <returns></returns>
        public static Transform AddMeshToScene(LBMesh lbMesh, Vector3 position, string gameobjectName, Transform parentTransform, Material meshMaterial, bool isStatic, bool checkForExisting)
        {
            Transform meshTranform = null;
            string    methodName   = "LBMeshOperations.AddMeshToScene";

            // Basic validation
            if (lbMesh == null)
            {
                Debug.LogWarning("ERROR: " + methodName + " - LBMesh cannot be null");
            }
            else if (string.IsNullOrEmpty(gameobjectName))
            {
                Debug.LogWarning("ERROR: " + methodName + " - no name specified");
            }
            else if (parentTransform == null)
            {
                Debug.LogWarning("ERROR: " + methodName + " - no parent transform is specified");
            }
            else
            {
                GameObject meshGameObject;
                Transform  tfrm = null;

                // Check to see if the GameObject already exists
                if (checkForExisting)
                {
                    tfrm = parentTransform.Find(gameobjectName);
                }

                // If it doesn't exist or checkForExisting is false, create a new child object.
                if (tfrm == null)
                {
                    meshGameObject = new GameObject(gameobjectName);
                    if (meshGameObject == null)
                    {
                        Debug.LogWarning("ERROR: " + methodName + " - could not create GameObject " + gameobjectName);
                    }
                    else
                    {
                        meshGameObject.transform.SetParent(parentTransform);
                    }
                }
                else
                {
                    meshGameObject = tfrm.gameObject;
                }

                if (meshGameObject != null)
                {
                    meshGameObject.isStatic           = isStatic;
                    meshGameObject.transform.position = position;

                    // If the Mesh Filter doesn't exist, add it
                    MeshFilter meshFilter = meshGameObject.GetComponent <MeshFilter>();
                    if (meshFilter == null)
                    {
                        meshFilter = meshGameObject.AddComponent <MeshFilter>();
                    }

                    // If the Mesh Renderer doesn't exist, add it
                    MeshRenderer meshRenderer = meshGameObject.GetComponent <MeshRenderer>();
                    if (meshRenderer == null)
                    {
                        meshRenderer = meshGameObject.AddComponent <MeshRenderer>();
                    }

                    if (meshFilter == null)
                    {
                        Debug.LogWarning("ERROR: " + methodName + " - Could not add MeshFilter to " + gameobjectName);
                    }
                    else if (meshRenderer == null)
                    {
                        Debug.LogWarning("ERROR: " + methodName + " - Could not add MeshRenderer to " + gameobjectName);
                    }
                    else
                    {
                        meshFilter.sharedMesh       = lbMesh.mesh;
                        meshRenderer.sharedMaterial = meshMaterial;

                        //lbMesh.mesh.RecalculateBounds();

                        // We may already have the trfm (see above) but we want to only return if everything succeeds
                        meshTranform = meshGameObject.transform;
                    }
                }
            }

            return(meshTranform);
        }