Beispiel #1
0
 public static void flatShade(this MeshObjectData mesh)
 {
     Vector3[] oldVerts  = mesh.vertices;
     int[]     triangles = mesh.triangles;
     Vector3[] vertices  = new Vector3[triangles.Length];
     for (int i = 0; i < triangles.Length; i++)
     {
         vertices[i]  = oldVerts[triangles[i]];
         triangles[i] = i;
     }
     mesh.vertices  = vertices;
     mesh.triangles = triangles;
 }
        private void BuildTree(TreeThreadReturnData ReturnData)
        {
            MeshObjectData TreeBuildData = ReturnData.TreeBuildData;
            Mesh           TreeMesh      = TreeBuildData.ToMesh();

            TreeMesh.RecalculateBounds();
            TreeMesh.RecalculateNormals();

            string     ObjectName = ReturnData.TreeData.TreeName != null && ReturnData.TreeData.TreeName != "" ? ReturnData.TreeData.TreeName : "Woah!, Some kind of random Tree";
            GameObject treeObject = new GameObject(ObjectName);

            treeObject.AddComponent <MeshFilter>().mesh = TreeMesh;
            treeObject.AddComponent <MeshRenderer>();
            Material mat = new Material(vertexShader);

            mat.SetFloat("_Smoothness", 0f);
            treeObject.GetComponent <Renderer>().material = mat;
            MeshObjectData[] PlantBuildData = ReturnData.FoliagesBuildData;

            for (int i = 0; i < PlantBuildData.Length; i++)
            {
                Mesh plantMesh = PlantBuildData[i].ToMesh();
                plantMesh.RecalculateBounds();
                plantMesh.RecalculateNormals();

                GameObject Foliage = new GameObject("Foliage");
                Foliage.AddComponent <MeshFilter>().mesh = plantMesh;
                Foliage.AddComponent <MeshRenderer>();
                Foliage.GetComponent <Renderer>().material = new Material(mat);
                UnityEngine.Random.InitState(ReturnData.TreeData.TreeSeed + i);
                Foliage.transform.localScale *= UnityEngine.Random.Range(ReturnData.TreeData.foliageScaleMin, ReturnData.TreeData.foliageScaleMax);
                Foliage.transform.position    = PlantBuildData[i].position;
                Foliage.transform.SetParent(treeObject.transform);
            }

            treeObject.transform.position = TreeBuildData.position;

            ReturnData.OriginalCallBack(treeObject);
        }
        static MeshObjectData CreateFoliage(TreeData data, TreeBranch Branch, int index)
        {
            MeshDraft m;

            switch (data.FoliageBasePrimitiveShape)
            {
            case TreeData.BasePrimitiveShapes.Dodecahedron:
                m = MeshDraft.Dodecahedron(0.5f);
                break;

            case TreeData.BasePrimitiveShapes.Icosahedron:
                m = MeshDraft.Icosahedron(0.5f, false);
                break;

            case TreeData.BasePrimitiveShapes.Prism:
                m = MeshDraft.Prism(0.5f, data.foliageSegments, 0.1f, false);
                break;

            case TreeData.BasePrimitiveShapes.Pyramid:
                m = MeshDraft.Pyramid(0.5f, data.foliageSegments, 0.5f, false);
                break;

            default:
                m = MeshDraft.Sphere(0.5f, data.foliageSegments, data.foliageSegments, false);
                break;
            }

            MeshObjectData plant = new MeshObjectData();

            plant.vertices  = m.vertices.ToArray();
            plant.triangles = m.triangles.ToArray();
            plant.tangents  = m.tangents.ToArray();
            plant.AutoWeldMesh(0.0001f, 0.4f);

            Vector3[] verts        = plant.vertices;
            float     currentNoise = data.noise;

            currentNoise *= 0.4f;
            Vector3 Pos = Branch.To;

            plant.position = Pos;

            int  s = data.TreeSeed + index + Mathf.RoundToInt(Pos.x) + Mathf.RoundToInt(Pos.y) + Mathf.RoundToInt(Pos.z) + Mathf.RoundToInt(Branch.Length);
            Rand r = new Rand(s);

            for (int i = 0; i < verts.Length; i++)
            {
                verts[i].x += r.Range(-currentNoise, currentNoise);
                verts[i].y += r.Range(-currentNoise, currentNoise);
                verts[i].z += r.Range(-currentNoise, currentNoise);
            }

            plant.vertices = verts;

            plant.flatShade();

            Color[] vertexColor = new Color[plant.vertices.Length];
            Color   CC          = data.foliageColors[r.Range(0, data.foliageColors.Length)];

            for (int c = 0; c < plant.vertices.Length; c++)
            {
                vertexColor[c] = CC;
            }
            plant.colors = vertexColor;
            return(plant);
        }
        public static void Build(TreeThreadReturnData ReturnData)
        {
            TreeData data = ReturnData.TreeData;

            var root = new TreeBranch(
                data.generations,
                data.length,
                data.radius,
                data
                );

            var vertices  = new List <Vector3>();
            var normals   = new List <Vector3>();
            var tangents  = new List <Vector4>();
            var uvs       = new List <Vector2>();
            var triangles = new List <int>();

            List <MeshObjectData> Foliages = new List <MeshObjectData>();

            Rand rand;
            int  FolCheckCount = 0;

            float maxLength = TraverseMaxLength(root);

            Traverse(root, (branch) =>
            {
                var offset = vertices.Count;

                var vOffset = branch.Offset / maxLength;
                var vLength = branch.Length / maxLength;

                for (int i = 0, n = branch.Segments.Count; i < n; i++)
                {
                    var t = 1f * i / (n - 1);
                    var v = vOffset + vLength * t;

                    var segment = branch.Segments[i];
                    var N       = segment.Frame.Normal;
                    var B       = segment.Frame.Binormal;
                    for (int j = 0; j <= data.radialSegments; j++)
                    {
                        // 0.0 ~ 2π
                        var u     = 1f * j / data.radialSegments;
                        float rad = u * PI2;

                        float cos  = Mathf.Cos(rad), sin = Mathf.Sin(rad);
                        var normal = (cos * N + sin * B).normalized;
                        vertices.Add(segment.Position + segment.Radius * normal);
                        normals.Add(normal);

                        var tangent = segment.Frame.Tangent;
                        tangents.Add(new Vector4(tangent.x, tangent.y, tangent.z, 0f));

                        uvs.Add(new Vector2(u, v));
                    }
                }

                for (int j = 1; j <= data.heightSegments; j++)
                {
                    for (int i = 1; i <= data.radialSegments; i++)
                    {
                        int a = (data.radialSegments + 1) * (j - 1) + (i - 1);
                        int b = (data.radialSegments + 1) * j + (i - 1);
                        int c = (data.radialSegments + 1) * j + i;
                        int d = (data.radialSegments + 1) * (j - 1) + i;

                        a += offset;
                        b += offset;
                        c += offset;
                        d += offset;

                        triangles.Add(a); triangles.Add(d); triangles.Add(b);
                        triangles.Add(b); triangles.Add(d); triangles.Add(c);
                    }
                }

                //plants
                if (branch.Children == null || branch.Children.Count == 0)
                {
                    rand         = new Rand(FolCheckCount + data.TreeSeed);
                    float chance = rand.Range(0f, 100f);
                    Debug.Log(chance);
                    if (chance <= data.foliageChance)
                    {
                        Foliages.Add(CreateFoliage(data, branch, Foliages.Count + FolCheckCount));
                    }
                    FolCheckCount++;
                }
            });

            MeshObjectData TreeMeshData = new MeshObjectData();

            TreeMeshData.vertices  = vertices.ToArray();
            TreeMeshData.triangles = triangles.ToArray();
            TreeMeshData.position  = ReturnData.TreePos;

            TreeMeshData.flatShade();

            Color[] treecolor = new Color[TreeMeshData.vertices.Length];

            for (int i = 0; i < TreeMeshData.vertices.Length; i++)
            {
                treecolor[i] = data.branchColor;
            }

            TreeMeshData.colors = treecolor;

            ReturnData.TreeBuildData = TreeMeshData;

            ReturnData.FoliagesBuildData = Foliages.ToArray();
            ReturnData.ManagerCallBack(ReturnData);
        }
Beispiel #5
0
        private IEnumerator CookieBaking()
        {
            yield return(null);

            var resolution = s_resolutionOptions[s_selectedCookieResolution];


            // We only want to use GameObjects that are within the outer radius that we have set. So, a quick test
            // to see if something is within the ball park would be to check if their bounding box insersects with
            // a bounding box that contains the outer radius. Once that has been done, we can take a closer look at
            // what's left.
            var meshRenders        = FindObjectsOfType <MeshRenderer>();
            var lightCenter        = s_currentLightComponent.transform.position;
            var lightBoundingBox   = new UnityEngine.Bounds(lightCenter, 2.0f * s_outerRadius * Vector3.one);
            var intersectingBounds = new List <MeshRenderer>();

            foreach (var meshRenderer in meshRenders)
            {
                var otherBounds = meshRenderer.bounds;
                if (otherBounds.Intersects(lightBoundingBox))
                {
                    intersectingBounds.Add(meshRenderer);
                }
            }

            yield return(null);

            // Now, we can limit things a bit more by finding the point within our mesh bounds that is nearset to
            // the light's center. We then check this point to see if it's within the distance of our outer radius.
            var intersectingOuterRadius = new List <MeshRenderer>();

            foreach (var meshRenderer in intersectingBounds)
            {
                var otherBounds         = meshRenderer.bounds;
                var nearsetPointToLight = otherBounds.ClosestPoint(lightCenter);
                if ((nearsetPointToLight - lightCenter).sqrMagnitude <= (s_outerRadius * s_outerRadius))
                {
                    intersectingOuterRadius.Add(meshRenderer);
                }
            }

            yield return(null);

            var processMeshRenderer = intersectingBounds;
            var processMeshFilter   = new List <MeshFilter>();

            // We're reusing the List from intersectingBounds and placing it under a more appropriate name.
            // Basically, we're reusing a piece of memory that's no longer needed instead of allocating a new List
            // with a new array. Also, this array shouldn't need to be resized to something larger because it
            // already a capacity that is greater than or equal to the number of items we will be processing.
            processMeshRenderer.Clear();
            intersectingBounds = null;


            // Also, while we're at it, lets make sure that we are only baking items that are static. After all,
            // what's the point of baking the shadow casting item that might not be there?
            foreach (var meshRender in intersectingOuterRadius)
            {
                var gameObject = meshRender.gameObject;

                // If the gameObject isn't static, than it can be moved. Since we are not updating the cookie at
                // runtime, having a moving object would be bad.
                if (!gameObject.isStatic)
                {
                    continue;
                }

                // The mesh for our object is inside the MeshFilter, so we need that to get the mesh. Also, since we're
                // dealing with static meshes, then we really shouldn't be dealing with any Skinned Mesh Renderers.
                var meshFilter = gameObject.GetComponent <MeshFilter>();
                if (meshFilter == null)
                {
                    continue;
                }

                // If there's no mesh, then what are we even bothering with this?
                if (meshFilter.sharedMesh == null)
                {
                    continue;
                }

                processMeshRenderer.Add(meshRender);
                processMeshFilter.Add(meshFilter);
            }

            yield return(null);


            // Todo: With this design, items that use the same mesh will replicate the mesh verts and triangle index
            //		 arrays. I need to add a way to check if we have already added a mesh and if so, pull up the triangle
            //		 index array information to pass along to the meshRefDatum.
            var meshObjecRefData = new List <MeshObjectData>(processMeshRenderer.Count);
            var indexList        = new List <int>();
            var vertexList       = new List <Vector3>(processMeshRenderer.Count * 50);

            for (int i = 0; i < processMeshRenderer.Count; i++)
            {
                var mesh                = processMeshFilter[i].sharedMesh;
                var meshVerts           = mesh.vertices;
                var meshTriangleIndices = mesh.triangles;

                var meshRefDatum = new MeshObjectData()
                {
                    LocalToWorldMatrix = processMeshRenderer[i].localToWorldMatrix,
                    IndicesOffset      = indexList.Count,                                       // The starting index of the vert-index for this object's mesh.
                    IndicesCount       = meshTriangleIndices.Length,                            // The number of indices used to form all of the mesh triangles.
                    VerticesOffset     = vertexList.Count,
                    Bounds             = new Bounds()
                    {
                        Center = processMeshRenderer[i].bounds.center,
                        Extent = processMeshRenderer[i].bounds.extents
                    }
                };

                meshObjecRefData.Add(meshRefDatum);
                vertexList.AddRange(meshVerts);
                indexList.AddRange(meshTriangleIndices);
            }

            yield return(null);

            ///
            /// Try adding tracing code here.
            ///
            var backgroundWorkerArgs = new BackgroundWorkerArgs()
            {
                Indices    = indexList,
                ObjectData = meshObjecRefData,
                Vertices   = vertexList,

                LightPosition = lightCenter,
                LightForward  = s_currentLightComponent.transform.forward,
                LightUpward   = s_currentLightComponent.transform.up
            };

            yield return(null);

            using (var backgroundWorker = new BackgroundWorker())
            {
                backgroundWorker.DoWork += BackgroundWorker_DoWork;
                backgroundWorker.RunWorkerAsync(backgroundWorkerArgs);

                while (!backgroundWorkerArgs.Complete)
                {
                    yield return(new EditorWaitForSeconds(0.15f));
                }
            }

            s_currentBakeState = BakeState.Finalize;

            yield return(null);


            ///
            /// Code for saving our results into the project and applying them to the light component.
            ///

            // Create a Texture2D to place our results into. This Texture2D will be added to the project's assets
            // and it will be applied to the light source we were raytracing.
            Texture2D finalResults = new Texture2D(resolution, resolution, TextureFormat.RGBAFloat, false, true)
            {
                alphaIsTransparency = true,
                filterMode          = FilterMode.Point,
                wrapMode            = TextureWrapMode.Clamp,
                name = s_currentLightComponent.name + "_ShadowCookie_" + resolution.ToString()
            };

            yield return(null);

            //finalResults.SetPixels(threadArgs.Result);
            yield return(null);


            // Check for the location where we will be saving the Texture2D. If that location doesn't exist, then
            // create it.
            var assetFolderPath = "Assets/Light_Cookies/" + s_currentLightComponent.gameObject.scene.name;

            if (!Directory.Exists(assetFolderPath))
            {
                if (!Directory.Exists("Assets/Light_Cookies"))
                {
                    AssetDatabase.CreateFolder("Assets", "Light_Cookies");
                    yield return(null);
                }
                AssetDatabase.CreateFolder("Assets/Light_Cookies", s_currentLightComponent.gameObject.scene.name);
            }
            yield return(null);


            // Save the Texture2D as a project asset.
            var assetPath = assetFolderPath + "/" + finalResults.name + ".asset";

            AssetDatabase.CreateAsset(finalResults, assetPath);

            yield return(null);

            // Apply the Texture2D to the light as a cooke, then finish cleaning up.
            s_currentLightComponent.cookie = finalResults;
            EditorUtility.SetDirty(s_currentLightComponent.gameObject);
            s_bakingCoroutine = null;                           // The coroutines for MonoBehaviors have the option to manipulate them from the outside, which I have
            // made use of. With a bit of luck, those functions will be added to the EditorCoroutines at some point
            // in time.
            // -FCT
            yield return(null);

            s_currentBakeState = BakeState.SettingSelection;
        }
    public static void AutoWeldMesh(this MeshObjectData mesh, float threshold, float bucketStep)
    {
        Vector3[] oldVertices = mesh.vertices;
        Vector3[] newVertices = new Vector3[oldVertices.Length];
        int[]     old2new     = new int[oldVertices.Length];
        int       newSize     = 0;

        // Find AABB
        Vector3 min = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
        Vector3 max = new Vector3(float.MinValue, float.MinValue, float.MinValue);

        for (int i = 0; i < oldVertices.Length; i++)
        {
            if (oldVertices[i].x < min.x)
            {
                min.x = oldVertices[i].x;
            }
            if (oldVertices[i].y < min.y)
            {
                min.y = oldVertices[i].y;
            }
            if (oldVertices[i].z < min.z)
            {
                min.z = oldVertices[i].z;
            }
            if (oldVertices[i].x > max.x)
            {
                max.x = oldVertices[i].x;
            }
            if (oldVertices[i].y > max.y)
            {
                max.y = oldVertices[i].y;
            }
            if (oldVertices[i].z > max.z)
            {
                max.z = oldVertices[i].z;
            }
        }

        // Make cubic buckets, each with dimensions "bucketStep"
        int bucketSizeX = Mathf.FloorToInt((max.x - min.x) / bucketStep) + 1;
        int bucketSizeY = Mathf.FloorToInt((max.y - min.y) / bucketStep) + 1;
        int bucketSizeZ = Mathf.FloorToInt((max.z - min.z) / bucketStep) + 1;

        List <int>[,,] buckets = new List <int> [bucketSizeX, bucketSizeY, bucketSizeZ];

        // Make new vertices
        for (int i = 0; i < oldVertices.Length; i++)
        {
            // Determine which bucket it belongs to
            int x = Mathf.FloorToInt((oldVertices[i].x - min.x) / bucketStep);
            int y = Mathf.FloorToInt((oldVertices[i].y - min.y) / bucketStep);
            int z = Mathf.FloorToInt((oldVertices[i].z - min.z) / bucketStep);

            // Check to see if it's already been added
            if (buckets[x, y, z] == null)
            {
                buckets[x, y, z] = new List <int>(); // Make buckets lazily
            }
            for (int j = 0; j < buckets[x, y, z].Count; j++)
            {
                Vector3 to = newVertices[buckets[x, y, z][j]] - oldVertices[i];
                if (Vector3.SqrMagnitude(to) < threshold)
                {
                    old2new[i] = buckets[x, y, z][j];
                    goto skip; // Skip to next old vertex if this one is already there
                }
            }

            // Add new vertex
            newVertices[newSize] = oldVertices[i];
            buckets[x, y, z].Add(newSize);
            old2new[i] = newSize;
            newSize++;

            skip :;
        }

        // Make new triangles
        int[] oldTris = mesh.triangles;
        int[] newTris = new int[oldTris.Length];
        for (int i = 0; i < oldTris.Length; i++)
        {
            newTris[i] = old2new[oldTris[i]];
        }

        Vector3[] finalVertices = new Vector3[newSize];
        for (int i = 0; i < newSize; i++)
        {
            finalVertices[i] = newVertices[i];
        }

        //mesh.Clear();
        mesh.vertices  = finalVertices;
        mesh.triangles = newTris;
        //mesh.RecalculateNormals();
    }
Beispiel #7
0
        public static void Build(RockThreadReturnData returnData)
        {
            RockData  data = returnData.RockData;
            MeshDraft MD;

            switch (data.RockBasePrimitiveShape)
            {
            case RockData.BasePrimitiveShapes.Dodecahedron:
                MD = MeshDraft.Dodecahedron(0.5f);
                break;

            case RockData.BasePrimitiveShapes.Icosahedron:
                MD = MeshDraft.Icosahedron(0.5f, false);
                break;

            case RockData.BasePrimitiveShapes.Prism:
                MD = MeshDraft.Prism(0.5f, data.Segments, 1f, false);
                break;

            case RockData.BasePrimitiveShapes.Pyramid:
                MD = MeshDraft.Pyramid(0.5f, data.Segments, 1f, false);
                break;

            default:
                MD = MeshDraft.Sphere(0.5f, data.Segments, data.Segments, false);
                break;
            }
            ;
            MeshObjectData rock = new MeshObjectData();

            rock.vertices  = MD.vertices.ToArray();
            rock.triangles = MD.triangles.ToArray();
            rock.tangents  = MD.tangents.ToArray();
            rock.AutoWeldMesh(0.0001f, 0.4f);
            Vector3[] verts = rock.vertices;
            INoise    noise = new SimplexNoise(data.RockSeed, 0.3f, 0.2f);
            Rand      r     = new Rand(data.RockSeed);

            for (int i = 0; i < verts.Length; i++)
            {
                float currentNoise = NoiseGen(noise, 3, verts[i].x / 0.5f, verts[i].y / 0.5f, verts[i].z / 0.5f);
                //currentNoise*=2;
                Vector3 norm = verts[i].normalized;
                verts[i].x += currentNoise * norm.x;
                verts[i].y += currentNoise * norm.y;
                verts[i].z += currentNoise * norm.z;

                verts[i].x *= 3;
                verts[i].y *= 1.2f;
                verts[i].z *= 1.5f;
            }
            rock.vertices = verts;
            rock.flatShade();

            Color[] vertexColor = new Color[rock.vertices.Length];

            for (int i = 0; i < rock.vertices.Length; i++)
            {
                vertexColor[i] = data.RockGradientColor.Color.Evaluate(1 - rock.vertices[i].y);
            }

            rock.colors = vertexColor;
            returnData.RockBuildData = rock;
            returnData.ManagerCallBack(returnData);
        }