예제 #1
0
        public static string _MoldToMeshByTerrainPolygon(Terrain terrain, MeshCollider collider, bool MoldAdditive, float saftyMargin, float offset, bool doNotAddHeight = false)
        {
            if (collider == null)
            {
                return("error no collider");
            }

            Transform parent = collider.transform.parent;

            if (parent != null)
            {
                collider.transform.parent = null;
            }

            if (!terrain.GetComponent <Collider>().bounds.Intersects(collider.bounds))
            {
                return(".");
            }


            Vector3 terrainPos  = terrain.transform.position;
            Vector3 terrainSize = terrain.terrainData.size;
            Vector2 tmin        = Vector2.zero;
            Vector2 tmax        = Vector2.zero;

            tmin.x = (collider.bounds.min.x - terrainPos.x) / terrainSize.x;
            tmin.y = (collider.bounds.min.z - terrainPos.z) / terrainSize.z;
            tmax.x = (collider.bounds.max.x - terrainPos.x) / terrainSize.x;
            tmax.y = (collider.bounds.max.z - terrainPos.z) / terrainSize.z;

            int minIndexX = Mathf.FloorToInt(tmin.x * terrain.terrainData.heightmapWidth - saftyMargin);
            int minIndexY = Mathf.FloorToInt(tmin.y * terrain.terrainData.heightmapHeight - saftyMargin);
            int maxIndexX = Mathf.CeilToInt(tmax.x * terrain.terrainData.heightmapWidth + saftyMargin);
            int maxIndexY = Mathf.CeilToInt(tmax.y * terrain.terrainData.heightmapHeight + saftyMargin);

            //Make sure rectangle is inside terrain
            minIndexX = Mathf.Clamp(minIndexX, 0, terrain.terrainData.heightmapWidth - 1);
            minIndexY = Mathf.Clamp(minIndexY, 0, terrain.terrainData.heightmapHeight - 1);
            maxIndexX = Mathf.Clamp(maxIndexX, 0, terrain.terrainData.heightmapWidth - 1);
            maxIndexY = Mathf.Clamp(maxIndexY, 0, terrain.terrainData.heightmapHeight - 1);

            int mapWidth  = maxIndexX - minIndexX;
            int mapHeight = maxIndexY - minIndexY;

            float[,] heights = terrain.terrainData.GetHeights(minIndexX, minIndexY, mapWidth, mapHeight);

            for (int iz = 0; iz < mapHeight - 1; iz++)
            {
                for (int ix = 0; ix < mapWidth - 1; ix++)
                {
                    float[]   originalHeight   = new float[4];
                    float[]   targetHeight     = new float[4];
                    float     strength         = 1;
                    float[]   newHeight        = new float[4];
                    Vector3[] terrainPositions = new Vector3[4];

                    originalHeight[0] = heights[iz, ix];
                    originalHeight[1] = heights[iz, ix + 1];
                    originalHeight[2] = heights[iz + 1, ix + 1];
                    originalHeight[3] = heights[iz + 1, ix];

                    terrainPositions[0] = GetTerrainPos(terrain, minIndexX + ix, minIndexY + iz, originalHeight[0]);
                    terrainPositions[1] = GetTerrainPos(terrain, minIndexX + ix + 1, minIndexY + iz, originalHeight[1]);
                    terrainPositions[2] = GetTerrainPos(terrain, minIndexX + ix + 1, minIndexY + iz + 1, originalHeight[2]);
                    terrainPositions[3] = GetTerrainPos(terrain, minIndexX + ix, minIndexY + iz + 1, originalHeight[3]);

                    Vector3 rayOrigin = terrainPositions[0];
                    rayOrigin.y = terrain.transform.position.y + terrain.terrainData.size.y;
                    Ray        ray = new Ray(rayOrigin, Vector3.down);
                    RaycastHit hit;

                    for (int i = 0; i < 4; i++)
                    {
                        if (collider.Raycast(ray, out hit, terrain.terrainData.size.y * 10))
                        {
                            int[]   triangles = collider.sharedMesh.triangles;
                            float[] barys     = new float[3];
                            barys[0] = hit.barycentricCoordinate.x;
                            barys[1] = hit.barycentricCoordinate.y;
                            barys[2] = hit.barycentricCoordinate.z;

                            if (collider.sharedMesh.colors != null)
                            {
                                float tsmooth = 0;
                                for (int j = 0; j < 3; j++)
                                {
                                    tsmooth += collider.sharedMesh.colors[triangles[hit.triangleIndex * 3 + j]].a * barys[j];
                                }

                                strength = tsmooth;
                            }

                            newHeight[i] = hit.point.y - offset;
                        }
                        else
                        {
                            //newHeight = 1;
                        }
                    }

                    if (MoldAdditive)
                    {
                        for (int i = 0; i < 4; i++)
                        {
                            newHeight[i] = Mathf.Max(terrainPositions[i].y, newHeight[i]);
                        }
                    }

                    for (int i = 0; i < 4; i++)
                    {
                        targetHeight[i] = TerrainManager.GetHeightInTerrainSpace(newHeight[0], terrain);
                    }

                    if (doNotAddHeight)
                    {
                        for (int i = 0; i < 4; i++)
                        {
                            targetHeight[i] = Mathf.Min(originalHeight[i], targetHeight[i]);
                        }
                    }

                    heights[iz, ix]         = Mathf.Lerp(originalHeight[0], targetHeight[0], strength);
                    heights[iz, ix + 1]     = Mathf.Lerp(originalHeight[1], targetHeight[1], strength);
                    heights[iz + 1, ix + 1] = Mathf.Lerp(originalHeight[2], targetHeight[2], strength);
                    heights[iz + 1, ix]     = Mathf.Lerp(originalHeight[3], targetHeight[3], strength);
                }
            }

            terrain.terrainData.SetHeights(minIndexX, minIndexY, heights);
            collider.transform.parent = parent;
            return("ok");
        }
예제 #2
0
        public static string MoldToMesh(Terrain terrain, MeshCollider collider, bool MoldAdditive, float saftyMargin, float offset, bool strengthFromColor, bool doNotAddHeight = false, bool invertStrength = false)
        {
            if (collider == null)
            {
                return("error no collider");
            }

            Transform parent = collider.transform.parent;

            if (parent != null)
            {
                collider.transform.parent = null;
            }

            if (!terrain.GetComponent <Collider>().bounds.Intersects(collider.bounds))
            {
                return(".");
            }


            Vector3 terrainPos  = terrain.transform.position;
            Vector3 terrainSize = terrain.terrainData.size;
            Vector2 tmin        = Vector2.zero;
            Vector2 tmax        = Vector2.zero;

            tmin.x = (collider.bounds.min.x - terrainPos.x) / terrainSize.x;
            tmin.y = (collider.bounds.min.z - terrainPos.z) / terrainSize.z;
            tmax.x = (collider.bounds.max.x - terrainPos.x) / terrainSize.x;
            tmax.y = (collider.bounds.max.z - terrainPos.z) / terrainSize.z;

            int minIndexX = Mathf.FloorToInt(tmin.x * terrain.terrainData.heightmapWidth - saftyMargin);
            int minIndexY = Mathf.FloorToInt(tmin.y * terrain.terrainData.heightmapHeight - saftyMargin);
            int maxIndexX = Mathf.CeilToInt(tmax.x * terrain.terrainData.heightmapWidth + saftyMargin);
            int maxIndexY = Mathf.CeilToInt(tmax.y * terrain.terrainData.heightmapHeight + saftyMargin);

            //Make sure rectangle is inside terrain
            minIndexX = Mathf.Clamp(minIndexX, 0, terrain.terrainData.heightmapWidth - 1);
            minIndexY = Mathf.Clamp(minIndexY, 0, terrain.terrainData.heightmapHeight - 1);
            maxIndexX = Mathf.Clamp(maxIndexX, 0, terrain.terrainData.heightmapWidth - 1);
            maxIndexY = Mathf.Clamp(maxIndexY, 0, terrain.terrainData.heightmapHeight - 1);

            int mapWidth  = maxIndexX - minIndexX;
            int mapHeight = maxIndexY - minIndexY;

            float[,] heights = terrain.terrainData.GetHeights(minIndexX, minIndexY, mapWidth, mapHeight);
            Vector3 worldPos;

            for (int iz = 0; iz < mapHeight; iz++)
            {
                for (int ix = 0; ix < mapWidth; ix++)
                {
                    float originalHeight = heights[iz, ix];
                    float height         = terrainPos.y + originalHeight * terrain.terrainData.size.y;
                    worldPos = terrainPos;

                    worldPos.x += terrain.terrainData.size.x * ((float)(minIndexX + ix)) / ((float)(terrain.terrainData.heightmapWidth - 1));
                    worldPos.y += height;
                    worldPos.z += terrain.terrainData.size.z * ((float)(minIndexY + iz)) / ((float)(terrain.terrainData.heightmapHeight - 1));


                    float strength  = 1;
                    float newHeight = height;

                    Vector3 rayOrigin = worldPos;
                    rayOrigin.y = terrain.transform.position.y + terrain.terrainData.size.y;
                    Ray        ray = new Ray(rayOrigin, Vector3.down);
                    RaycastHit hit;

                    if (collider.Raycast(ray, out hit, terrain.terrainData.size.y * 10))
                    {
                        bool hasError = false;
                        try
                        {
                            if (strengthFromColor && collider.sharedMesh.colors != null && collider.sharedMesh.triangles.Length > hit.triangleIndex * 3 + 3)
                            {
                                int[]   triangles = collider.sharedMesh.triangles;
                                float[] barys     = new float[3];
                                barys[0] = hit.barycentricCoordinate.x;
                                barys[1] = hit.barycentricCoordinate.y;
                                barys[2] = hit.barycentricCoordinate.z;

                                float tsmooth = 0;
                                for (int i = 0; i < 3; i++)
                                {
                                    tsmooth += collider.sharedMesh.colors[triangles[hit.triangleIndex * 3 + i]].a * barys[i];
                                }

                                strength = tsmooth;
                            }
                            else
                            {
                                strength = 1;
                            }
                        }
                        catch
                        {
                            hasError = true;
                        }

                        if (hasError)
                        {
                            strength = 1;
                        }

                        if (invertStrength)
                        {
                            strength = 1 - strength;
                        }
                        newHeight = hit.point.y - offset * strength;
                    }
                    else
                    {
                        //newHeight = 1;
                    }

                    if (MoldAdditive)
                    {
                        newHeight = Mathf.Max(height, newHeight);
                    }
                    float targetHeight = TerrainManager.GetHeightInTerrainSpace(newHeight, terrain);

                    if (doNotAddHeight)
                    {
                        targetHeight = Mathf.Min(originalHeight, targetHeight);
                    }
                    heights[iz, ix] = Mathf.Lerp(originalHeight, targetHeight, strength);
                }
            }

            terrain.terrainData.SetHeights(minIndexX, minIndexY, heights);
            collider.transform.parent = parent;
            return("ok");
        }