コード例 #1
0
ファイル: Scatter.cs プロジェクト: winterdl/ScamScatter
        private static void extractTrianglesAndVerticies(
            List <vertex> verticies,
            List <triangle> triangles,
            int quota,
            meshData meshData,
            float maxArea)
        {
            quota = Mathf.Min(quota, meshData.Triangles.Count);
            var usedPositions = new HashSet <Vector3>();
            var totalArea     = 0f;
            var retries       = quota / 2;
            var vd            = new Dictionary <int, int>();

            while (triangles.Count < quota && retries >= 0)
            {
                triangle t;
                if (!meshData.DequeueAdjacentTriangle(usedPositions, out t))
                {
                    retries--;
                    continue;
                }

                var p0 = meshData.GetPosition(t.I0);
                var p1 = meshData.GetPosition(t.I1);
                var p2 = meshData.GetPosition(t.I2);

                var area = Vector3.Cross(p1 - p0, p2 - p0).magnitude / 2;
                if (area > maxArea)
                {
                    meshData.Subdivide(t);
                    return;
                }

                var i0 = meshData.NewVertex(verticies, vd, t.I0);
                var i1 = meshData.NewVertex(verticies, vd, t.I1);
                var i2 = meshData.NewVertex(verticies, vd, t.I2);
                verticies[i0].TriangleIndexes.Add(triangles.Count);
                verticies[i1].TriangleIndexes.Add(triangles.Count);
                verticies[i2].TriangleIndexes.Add(triangles.Count);
                triangles.Add(new triangle(i0, i1, i2));

                if ((totalArea += area) > maxArea)
                {
                    return;
                }
            }
        }
コード例 #2
0
    private void InitTerrain() {
        int meshGridSize = 16;
        int numTerrainMeshVertices = meshGridSize * meshGridSize;
        terrainMeshBuffer = new ComputeBuffer(numTerrainMeshVertices, sizeof(float) * (3 + 3 + 2 + 4));
        int numStrokesPerVertX = 16;
        int numStrokesPerVertZ = 16;
        int numTerrainStrokes = meshGridSize * meshGridSize * numStrokesPerVertX * numStrokesPerVertZ;
        terrainStrokesBuffer = new ComputeBuffer(numTerrainStrokes, sizeof(float) * (3 + 3 + 3 + 3 + 3 + 2) + sizeof(int) * 1);

        //terrainGeneratorCompute = new ComputeShader();
        int kernel_id = terrainGeneratorCompute.FindKernel("CSMain");
        terrainGeneratorCompute.SetFloat("_GridSideLength", terrainSize);
        terrainGeneratorCompute.SetFloat("_NoiseFrequency", terrainNoiseFrequency);
        terrainGeneratorCompute.SetFloat("_NoiseAmplitude", terrainNoiseAmplitude);
        terrainGeneratorCompute.SetFloat("_GroundHeight", terrainAltitude);
        terrainGeneratorCompute.SetInt("_NumGroupsX", numStrokesPerVertX);
        terrainGeneratorCompute.SetInt("_NumGroupsZ", numStrokesPerVertZ);
        terrainGeneratorCompute.SetBuffer(kernel_id, "buf_StrokeData", terrainStrokesBuffer);
        terrainGeneratorCompute.SetBuffer(kernel_id, "buf_MeshData", terrainMeshBuffer);

        meshData[] meshDataArray = new meshData[numTerrainMeshVertices];  // memory to receive data from computeshader
        terrainGeneratorCompute.Dispatch(kernel_id, numStrokesPerVertX, 1, numStrokesPerVertZ);  // fill buffers

        terrainMeshBuffer.GetData(meshDataArray);  // download mesh Data

        // generate Mesh from data:
        //Construct mesh using received data         
        // Why same number of tris as vertices?  == // because all triangles have duplicate verts - no shared vertices?
        Vector3[] vertices = new Vector3[numTerrainMeshVertices];
        Color[] colors = new Color[numTerrainMeshVertices];
        int[] tris = new int[2 * (meshGridSize - 1) * (meshGridSize - 1) * 3];
        Vector2[] uvs = new Vector2[numTerrainMeshVertices];
        Vector3[] normals = new Vector3[numTerrainMeshVertices];

        for(int i = 0; i < numTerrainMeshVertices; i++) {
            vertices[i] = meshDataArray[i].pos;
            normals[i] = meshDataArray[i].normal;
            uvs[i] = meshDataArray[i].uv;
            colors[i] = meshDataArray[i].color;            
        }
        // Figure out triangles:
        int index = 0;
        int numSquares = meshGridSize - 1;
        for (int y = 0; y < numSquares; y++) {
            for(int x = 0; x < numSquares; x++) {
                // counterclockwise winding order:
                tris[index] = ((y + 1) * meshGridSize) + x;
                tris[index + 1] = (y * meshGridSize) + x + 1;
                tris[index + 2] = (y * meshGridSize) + x;

                tris[index + 3] = ((y + 1) * meshGridSize) + x;
                tris[index + 4] = ((y + 1) * meshGridSize) + x + 1;
                tris[index + 5] = (y * meshGridSize) + x + 1;

                index = index + 6;
            }
        }

        Mesh terrainMesh = new Mesh();
        terrainMesh.vertices = vertices;
        terrainMesh.uv = uvs; //Unwrapping.GeneratePerTriangleUV(NewMesh);
        terrainMesh.triangles = tris;
        terrainMesh.normals = normals; //NewMesh.RecalculateNormals();        
        terrainMesh.colors = colors;
        terrainMesh.RecalculateNormals();
        terrainMesh.RecalculateBounds();

        trainerTerrainManager.GetComponent<MeshFilter>().sharedMesh = terrainMesh;
        trainerTerrainManager.GetComponent<MeshCollider>().sharedMesh = terrainMesh;

        terrainMeshBuffer.Release();
        terrainMeshBuffer.Dispose();
    }
コード例 #3
0
ファイル: Scatter.cs プロジェクト: winterdl/ScamScatter
        private IEnumerator run(
            ScatterCommands commands,
            Action <Stats> whenDone)
        {
            var sw          = Stopwatch.StartNew();
            var stats       = new Stats();
            var objectCount = 0;

            foreach (var cmd in commands)
            {
                var gameObject = cmd.GameObject;
                // already scattered?
                if (gameObject == null ||
                    gameObject.name.StartsWith(FragmentNamePrefix) ||
                    gameObject.name.StartsWith(DebrisNamePrefix))
                {
                    continue;
                }

                var targetPartCount = cmd.TargetPartCount.GetValueOrDefault(TargetPartCount);
                var targetArea      = cmd.TargetArea.GetValueOrDefault(TargetArea);
                var newThicknessMin = cmd.NewThicknessMin.GetValueOrDefault(NewThicknessMin);
                var newThicknessMax = cmd.NewThicknessMax.GetValueOrDefault(NewThicknessMax);
                Debug.Log(targetArea);

                var meshData = new meshData(cmd.Mesh, cmd.MeshScale);
                stats.SourceTriangles += meshData.TotalTriangleCount;
                for (var submeshIndex = 0; submeshIndex < cmd.Mesh.subMeshCount; submeshIndex++)
                {
                    meshData.SelectSubmesh(submeshIndex);
                    var maxTris = Mathf.Max(2, meshData.TotalTriangleCount / targetPartCount);
                    while (meshData.Triangles.Any())
                    {
                        var newTriangles = new List <triangle>();
                        var newVerticies = new List <vertex>();

                        var quota = Mathf.Min(meshData.Triangles.Count, Random.Range(maxTris - 1, maxTris + 2));
                        extractTrianglesAndVerticies(newVerticies, newTriangles, quota, meshData, targetArea);

                        // at this point, we have a continous surface in newTriangles+newVerticies which
                        // are a subset of the whole mesh
                        // now let's create some SCAM!

                        // first, calculate the average normal of the surface and the midpoint
                        var frontNormal   = Vector3.zero;
                        var frontMidpoint = Vector3.zero;
                        foreach (var t in newTriangles)
                        {
                            var p1 = newVerticies[t.I0].Pos;
                            var p2 = newVerticies[t.I1].Pos;
                            var p3 = newVerticies[t.I2].Pos;

                            frontMidpoint += p1 + p2 + p3;
                            frontNormal   += Vector3.Cross(p2 - p1, p3 - p1);
                        }
                        var backVector   = -frontNormal.normalized * Random.Range(newThicknessMin, newThicknessMax);
                        var backMidpoint = frontMidpoint / (newTriangles.Count * 3) + backVector;

                        // now we create a backside by creating a flipped backside, pushed backward by
                        // the user's specified thickness. we also contract it somewhat, to avoid z-fighting
                        // with orthogonal surfaces
                        var vertLength = newVerticies.Count;
                        for (var k = 0; k < vertLength; k++)
                        {
                            newVerticies.Add(new vertex
                            {
                                Pos     = Vector3.Lerp(newVerticies[k].Pos + backVector, backMidpoint, 0.2f),
                                Uv      = Vector2.one - newVerticies[k].Uv,
                                Normal  = -newVerticies[k].Normal,
                                Tangent = newVerticies[k].Tangent
                            });
                        }

                        // create all the new scam triangles
                        var tlen = newTriangles.Count;
                        for (var ti = 0; ti < tlen; ti++)
                        {
                            var t = newTriangles[ti];
                            // this is triangle for the backside (only verticies has been created this far)
                            newTriangles.Add(new triangle(t.I0 + vertLength, t.I2 + vertLength, t.I1 + vertLength));

                            // for each side of the front triangle, investigate if it is an outer
                            // side, and if so, create two triangles connecting the front with the back
                            buildSideRect(newVerticies, vertLength, newTriangles, ti, t.I0, t.I1);
                            buildSideRect(newVerticies, vertLength, newTriangles, ti, t.I1, t.I2);
                            buildSideRect(newVerticies, vertLength, newTriangles, ti, t.I2, t.I0);
                            // the new triangles created have completely wrong normals. fixing that would
                            // slow things down. just sayin'
                        }

                        // a micro optimizition here would be to stop using LINQ
                        var theNewMesh = new Mesh
                        {
                            vertices  = newVerticies.Select(_ => _.Pos).ToArray(),
                            normals   = newVerticies.Select(_ => _.Normal).ToArray(),
                            uv        = newVerticies.Select(_ => _.Uv).ToArray(),
                            tangents  = newVerticies.Select(_ => _.Tangent).ToArray(),
                            triangles = newTriangles.SelectMany(_ => new[] { _.I0, _.I1, _.I2 }).ToArray()
                        };

                        var newFragment = new GameObject($"{FragmentNamePrefix}{++objectCount}");
                        newFragment.transform.parent   = cmd.NewTransformParent;
                        newFragment.transform.position = cmd.Renderer.transform.position;
                        newFragment.transform.rotation = cmd.Renderer.transform.rotation;
#if UNITY_EDITOR
                        newFragment.AddComponent <MeshRenderer>().sharedMaterial = cmd.Renderer.sharedMaterials[submeshIndex % cmd.Renderer.sharedMaterials.Length];
#else
                        newFragment.AddComponent <MeshRenderer>().material = cmd.Renderer.materials[submeshIndex % cmd.Renderer.materials.Length];
#endif
                        newFragment.AddComponent <MeshFilter>().mesh = theNewMesh;
                        newFragment.AddComponent <BoxCollider>();

                        stats.NewGameObjects++;
                        stats.NewTriangles += newTriangles.Count;

                        if (MaxTimeMs > 0 && sw.ElapsedMilliseconds > MaxTimeMs)
                        {
                            Debug.Log("Yield");
                            yield return(null);

                            sw.Restart();
                        }
                    }
                }

                if (cmd.DestroyMesh)
                {
                    Object.Destroy(cmd.Mesh);
                }
                if (cmd.Destroy)
                {
                    Object.Destroy(gameObject);
                }
            }
            whenDone?.Invoke(stats);
        }
コード例 #4
0
    private void InitTerrain()
    {
        int meshGridSize           = 16;
        int numTerrainMeshVertices = meshGridSize * meshGridSize;

        terrainMeshBuffer = new ComputeBuffer(numTerrainMeshVertices, sizeof(float) * (3 + 3 + 2 + 4));
        int numStrokesPerVertX = 16;
        int numStrokesPerVertZ = 16;
        int numTerrainStrokes  = meshGridSize * meshGridSize * numStrokesPerVertX * numStrokesPerVertZ;

        terrainStrokesBuffer = new ComputeBuffer(numTerrainStrokes, sizeof(float) * (3 + 3 + 3 + 3 + 3 + 2) + sizeof(int) * 1);

        //terrainGeneratorCompute = new ComputeShader();
        int kernel_id = terrainGeneratorCompute.FindKernel("CSMain");

        terrainGeneratorCompute.SetFloat("_GridSideLength", terrainSize);
        terrainGeneratorCompute.SetFloat("_NoiseFrequency", terrainNoiseFrequency);
        terrainGeneratorCompute.SetFloat("_NoiseAmplitude", terrainNoiseAmplitude);
        terrainGeneratorCompute.SetFloat("_GroundHeight", terrainAltitude);
        terrainGeneratorCompute.SetInt("_NumGroupsX", numStrokesPerVertX);
        terrainGeneratorCompute.SetInt("_NumGroupsZ", numStrokesPerVertZ);
        terrainGeneratorCompute.SetBuffer(kernel_id, "buf_StrokeData", terrainStrokesBuffer);
        terrainGeneratorCompute.SetBuffer(kernel_id, "buf_MeshData", terrainMeshBuffer);

        meshData[] meshDataArray = new meshData[numTerrainMeshVertices];                        // memory to receive data from computeshader
        terrainGeneratorCompute.Dispatch(kernel_id, numStrokesPerVertX, 1, numStrokesPerVertZ); // fill buffers

        terrainMeshBuffer.GetData(meshDataArray);                                               // download mesh Data

        // generate Mesh from data:
        //Construct mesh using received data
        // Why same number of tris as vertices?  == // because all triangles have duplicate verts - no shared vertices?
        Vector3[] vertices = new Vector3[numTerrainMeshVertices];
        Color[]   colors   = new Color[numTerrainMeshVertices];
        int[]     tris     = new int[2 * (meshGridSize - 1) * (meshGridSize - 1) * 3];
        Vector2[] uvs      = new Vector2[numTerrainMeshVertices];
        Vector3[] normals  = new Vector3[numTerrainMeshVertices];

        for (int i = 0; i < numTerrainMeshVertices; i++)
        {
            vertices[i] = meshDataArray[i].pos;
            normals[i]  = meshDataArray[i].normal;
            uvs[i]      = meshDataArray[i].uv;
            colors[i]   = meshDataArray[i].color;
        }
        // Figure out triangles:
        int index      = 0;
        int numSquares = meshGridSize - 1;

        for (int y = 0; y < numSquares; y++)
        {
            for (int x = 0; x < numSquares; x++)
            {
                // counterclockwise winding order:
                tris[index]     = ((y + 1) * meshGridSize) + x;
                tris[index + 1] = (y * meshGridSize) + x + 1;
                tris[index + 2] = (y * meshGridSize) + x;

                tris[index + 3] = ((y + 1) * meshGridSize) + x;
                tris[index + 4] = ((y + 1) * meshGridSize) + x + 1;
                tris[index + 5] = (y * meshGridSize) + x + 1;

                index = index + 6;
            }
        }

        Mesh terrainMesh = new Mesh();

        terrainMesh.vertices  = vertices;
        terrainMesh.uv        = uvs;     //Unwrapping.GeneratePerTriangleUV(NewMesh);
        terrainMesh.triangles = tris;
        terrainMesh.normals   = normals; //NewMesh.RecalculateNormals();
        terrainMesh.colors    = colors;
        terrainMesh.RecalculateNormals();
        terrainMesh.RecalculateBounds();

        trainerTerrainManager.GetComponent <MeshFilter>().sharedMesh   = terrainMesh;
        trainerTerrainManager.GetComponent <MeshCollider>().sharedMesh = terrainMesh;

        terrainMeshBuffer.Release();
        terrainMeshBuffer.Dispose();
    }