Exemple #1
0
        public async Task <Mesh> Build(Terrain terrain, List <Texture2D> alphaMaps, MassiveGrassProfile profile, List <Element> elements)
        {
            var terrainData = terrain.terrainData;
            var w           = terrainData.alphamapWidth;
            var h           = terrainData.alphamapHeight;

            var meshData    = new MeshData(elements.Count, 2);
            var actualCount = 0;
            var alphas      = new float[elements.Count];

            for (var i = 0; i < elements.Count; i++)
            {
                var element = elements[i];
                var layers  = profile.PaintTextureIndex;
                var alpha   = 0f;

                foreach (var layer in layers)
                {
                    try
                    {
                        var v = alphaMaps[layer].GetPixel(
                            Mathf.RoundToInt((float)w * element.normalizedPosition.y),
                            Mathf.RoundToInt((float)h * element.normalizedPosition.x)).a;
                        alpha = Mathf.Max(alpha, v);
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e);
                        throw;
                    }
                }

                alphas[i] = alpha;
            }

            await Task.Run(() =>
            {
                for (var i = 0; i < elements.Count; i++)
                {
                    var element = elements[i];
                    if (alphas[i] >= profile.AlphaMapThreshold)
                    {
                        if (alphas[i] + profile.DensityFactor > ParkAndMiller.Get(i))
                        {
                            AddQuad(meshData, profile, element, alphas[i], actualCount++);
                        }
                    }
                }
            });

            var mesh = new Mesh();

            mesh.name      = "MassiveGrass Quad Mesh";
            mesh.vertices  = meshData.vertices.Take(4 * actualCount).ToArray();
            mesh.normals   = meshData.normals.Take(4 * actualCount).ToArray();
            mesh.triangles = meshData.triangles.Take(6 * actualCount).ToArray();
            mesh.colors    = meshData.colors.Take(4 * actualCount).ToArray();
            mesh.SetUVs(0, meshData.uvs.Take(4 * actualCount).ToList());
            return(mesh);
        }
Exemple #2
0
        public MassiveGrassRenderer(Camera camera, Terrain terrain, List <Texture2D> alphaMaps, MassiveGrassProfile profile)
        {
            this.camera    = camera;
            this.terrain   = terrain;
            this.profile   = profile;
            this.alphaMaps = alphaMaps;

            var terrainSize = terrain.terrainData.bounds.size.x;

            grid        = new MassiveGrassGrid(terrain, Mathf.CeilToInt(terrainSize / profile.GridSize));
            meshBuilder = new MeshBuilder();
        }
        public async Task <Mesh> Build(
            Terrain terrain,
            List <Texture2D> alphaMaps,
            MassiveGrassGrid.CellIndex index,
            Rect rect,
            MassiveGrassProfile profile)
        {
            var elements = await GenerateElements(terrain, rect, profile, index.hash % 50000);

            var builder = profile.CreateBuilder();

            return(await builder.Build(terrain, alphaMaps, profile, elements));
        }
            public void OnBeginRender(
                Camera camera,
                MassiveGrassProfile profile,
                Terrain terrain,
                List <Texture2D> alphaMaps,
                int maxParallelJobCount)
            {
                if (profile == null)
                {
                    return;
                }
                if (!renderers.ContainsKey(profile))
                {
                    renderers[profile] = new MassiveGrassRenderer(
                        camera,
                        terrain,
                        alphaMaps,
                        profile,
                        maxParallelJobCount);
                    Debug.Log($" renderer for {profile} created on {camera}");
                }

                renderers[profile].OnBeginRender();
            }
Exemple #5
0
        public async Task <MeshData> BuildMeshData(Terrain terrain, IReadOnlyCollection <Texture2D> alphaMaps, MassiveGrassProfile profile, Element[] elements)
        {
            var terrainData = terrain.terrainData;
            var w           = terrainData.alphamapWidth;
            var h           = terrainData.alphamapHeight;

            if (pool.Count <= 0)
            {
                pool.Push(new MeshData(elements.Length, 2));
            }
            var meshData    = pool.Pop();
            var actualCount = 0;
            var alphas      = new float[elements.Length];
            var layers      = new List <int>(profile.TerrainLayers.Length);

            foreach (var terrainLayer in profile.TerrainLayers)
            {
                for (var i = 0; i < terrainData.terrainLayers.Length; i++)
                {
                    if (terrainData.terrainLayers[i] == terrainLayer)
                    {
                        layers.Add(i);
                    }
                }
            }

            for (var i = 0; i < elements.Length; i++)
            {
                var element = elements[i];
                var alpha   = 0f;

                foreach (var layer in layers)
                {
                    var texIndex = layer / 4;
                    if (texIndex < alphaMaps.Count)
                    {
                        var pixel = alphaMaps.ElementAt(layer / 4).GetPixelBilinear(
                            element.normalizedPosition.x * (w - 1f) / w,
                            element.normalizedPosition.y * (h - 1f) / h);
                        switch (layer % 4)
                        {
                        case 0: alpha = Mathf.Max(alpha, pixel.r); break;

                        case 1: alpha = Mathf.Max(alpha, pixel.g); break;

                        case 2: alpha = Mathf.Max(alpha, pixel.b); break;

                        case 3: alpha = Mathf.Max(alpha, pixel.a); break;
                        }
                    }
                }

                alphas[i] = alpha;
            }

            await Task.Run(() =>
            {
                for (var i = 0; i < elements.Length; i++)
                {
                    var element = elements[i];
                    var alpha   = alphas[i];
                    if (alpha >= profile.AlphaMapThreshold)
                    {
                        AddQuad(meshData, profile, element, alpha, actualCount++);
                    }
                    else
                    {
                        var rand = 1 - Mathf.Repeat(1f, ParkAndMiller.Get(i));
                        if (alpha > profile.DensityFactor *rand *rand)
                        {
                            AddQuad(meshData, profile, element, alpha, actualCount++);
                        }
                    }
                }

                meshData.SetActualCount(
                    4 * actualCount,
                    6 * actualCount);
            });

            return(meshData);
        }
Exemple #6
0
        private void AddQuad(MeshData meshData, MassiveGrassProfile profile, Element element, float density, int index)
        {
            var vOrigin   = index * 4;
            var iOrigin   = index * 6;
            var rand      = ParkAndMiller.Get(element.index);
            var normalRot = Quaternion.LookRotation(element.normal);
            var slant     = Quaternion.AngleAxis(profile.Slant * 90f * (rand - 0.5f), Vector3.right);
            var slantWeak = Quaternion.AngleAxis(profile.Slant * 45f * (rand - 0.5f), Vector3.right);
            var upRot     = Quaternion.AngleAxis(360f * rand, Vector3.up);
            var rot       = normalRot *
                            Quaternion.AngleAxis(90f, Vector3.right) *
                            upRot *
                            slant;
            var scale        = profile.Scale * (1 + 0.4f * (rand - 0.5f));
            var rightVec     = rot * Vector3.right;
            var upVec        = rot * Vector3.up;
            var p1           = scale.x * -rightVec * 0.5f + scale.y * upVec + Vector3.up * profile.GroundOffset;
            var p2           = scale.x * rightVec * 0.5f + scale.y * upVec + Vector3.up * profile.GroundOffset;
            var p3           = scale.x * rightVec * 0.5f + Vector3.up * profile.GroundOffset;
            var p4           = scale.x * -rightVec * 0.5f + Vector3.up * profile.GroundOffset;
            var normal       = element.normal;
            var normalBottom = element.normal;

            switch (profile.NormalType)
            {
            case NormalType.KeepMesh:
                break;

            case NormalType.Up:
                normalBottom = normal = rot * Vector3.up;
                break;

            case NormalType.Shading:
                normal       = rot * Vector3.up;
                normalBottom = rot * Vector3.forward;
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }
            meshData.vertices[vOrigin + 0] = element.position + p1;
            meshData.vertices[vOrigin + 1] = element.position + p2;
            meshData.vertices[vOrigin + 2] = element.position + p3;
            meshData.vertices[vOrigin + 3] = element.position + p4;
            meshData.normals[vOrigin + 0]  = normal;
            meshData.normals[vOrigin + 1]  = normal;
            meshData.normals[vOrigin + 2]  = normalBottom;
            meshData.normals[vOrigin + 3]  = normalBottom;

            var attr1 = new MassiveGrassProfile.VertAttribute(density, rand, element.position, p1);
            var attr2 = new MassiveGrassProfile.VertAttribute(density, rand, element.position, p2);
            var attr3 = new MassiveGrassProfile.VertAttribute(density, rand, element.position, p3);
            var attr4 = new MassiveGrassProfile.VertAttribute(density, rand, element.position, p4);

            {
                var vColorR = profile.GetCustomVertexData(VertexDataType.VertexColorR, attr1);
                var vColorG = profile.GetCustomVertexData(VertexDataType.VertexColorG, attr1);
                var vColorB = profile.GetCustomVertexData(VertexDataType.VertexColorB, attr1);
                var vColorA = profile.GetCustomVertexData(VertexDataType.VertexColorA, attr1);
                meshData.colors[vOrigin + 0] = new Color(vColorR, vColorG, vColorB, vColorA);
            }
            {
                var vColorR = profile.GetCustomVertexData(VertexDataType.VertexColorR, attr2);
                var vColorG = profile.GetCustomVertexData(VertexDataType.VertexColorG, attr2);
                var vColorB = profile.GetCustomVertexData(VertexDataType.VertexColorB, attr2);
                var vColorA = profile.GetCustomVertexData(VertexDataType.VertexColorA, attr2);
                meshData.colors[vOrigin + 1] = new Color(vColorR, vColorG, vColorB, vColorA);
            }
            {
                var vColorR = profile.GetCustomVertexData(VertexDataType.VertexColorR, attr3);
                var vColorG = profile.GetCustomVertexData(VertexDataType.VertexColorG, attr3);
                var vColorB = profile.GetCustomVertexData(VertexDataType.VertexColorB, attr3);
                var vColorA = profile.GetCustomVertexData(VertexDataType.VertexColorA, attr3);
                meshData.colors[vOrigin + 2] = new Color(vColorR, vColorG, vColorB, vColorA);
            }
            {
                var vColorR = profile.GetCustomVertexData(VertexDataType.VertexColorR, attr4);
                var vColorG = profile.GetCustomVertexData(VertexDataType.VertexColorG, attr4);
                var vColorB = profile.GetCustomVertexData(VertexDataType.VertexColorB, attr4);
                var vColorA = profile.GetCustomVertexData(VertexDataType.VertexColorA, attr4);
                meshData.colors[vOrigin + 3] = new Color(vColorR, vColorG, vColorB, vColorA);
            }
            {
                var uv1Z = profile.GetCustomVertexData(VertexDataType.UV1Z, attr1);
                var uv1W = profile.GetCustomVertexData(VertexDataType.UV1W, attr1);
                meshData.uvs[vOrigin + 0] = new Vector4(0f, 1f, uv1Z, uv1W);
            }
            {
                var uv1Z = profile.GetCustomVertexData(VertexDataType.UV1Z, attr2);
                var uv1W = profile.GetCustomVertexData(VertexDataType.UV1W, attr2);
                meshData.uvs[vOrigin + 1] = new Vector4(1f, 1f, uv1Z, uv1W);
            }
            {
                var uv1Z = profile.GetCustomVertexData(VertexDataType.UV1Z, attr3);
                var uv1W = profile.GetCustomVertexData(VertexDataType.UV1W, attr3);
                meshData.uvs[vOrigin + 2] = new Vector4(1f, 0f, uv1Z, uv1W);
            }
            {
                var uv1Z = profile.GetCustomVertexData(VertexDataType.UV1Z, attr4);
                var uv1W = profile.GetCustomVertexData(VertexDataType.UV1W, attr4);
                meshData.uvs[vOrigin + 3] = new Vector4(0f, 0f, uv1Z, uv1W);
            }
            meshData.triangles[iOrigin + 0] = vOrigin + 0;
            meshData.triangles[iOrigin + 1] = vOrigin + 1;
            meshData.triangles[iOrigin + 2] = vOrigin + 2;
            meshData.triangles[iOrigin + 3] = vOrigin + 2;
            meshData.triangles[iOrigin + 4] = vOrigin + 3;
            meshData.triangles[iOrigin + 5] = vOrigin + 0;
        }
Exemple #7
0
        public async Task <Mesh> Build(Terrain terrain, List <Texture2D> alphaMaps, MassiveGrassProfile profile, List <Element> elements)
        {
            var terrainData = terrain.terrainData;
            var w           = terrainData.alphamapWidth;
            var h           = terrainData.alphamapHeight;
            var alphas      = new float[elements.Count];

            for (var i = 0; i < elements.Count; i++)
            {
                var element = elements[i];
                var layers  = profile.PaintTextureIndex;
                var alpha   = 0f;

                foreach (var layer in layers)
                {
                    var v = alphaMaps[layer].GetPixel(
                        Mathf.RoundToInt((float)w * element.normalizedPosition.x),
                        Mathf.RoundToInt((float)h * element.normalizedPosition.y)).a;
                    alpha = Mathf.Max(alpha, v);
                }

                alphas[i] = alpha;
            }

            var mesh    = new Mesh();
            var combine = new List <CombineInstance>();

            if (cache == null)
            {
                cache = Mesh.Instantiate(profile.Mesh);
                switch (profile.NormalType)
                {
                case NormalType.KeepMesh:
                    break;

                case NormalType.Up:
                    cache.normals = cache.normals.Select(_ => Vector3.up).ToArray();
                    break;

                case NormalType.Shading:
                    cache.normals = cache.normals.Select((_, i) =>
                                                         Vector3.Slerp(cache.normals[i], Vector3.up, cache.vertices[i].y)).ToArray();
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }
            }

            var scale = new Vector3(profile.Scale.x, profile.Scale.y, profile.Scale.x);

            for (var i = 0; i < elements.Count; i++)
            {
                var element = elements[i];
                if (alphas[i] >= profile.AlphaMapThreshold)
                {
                    var density = alphas[i];
                    var rand    = ParkAndMiller.Get(element.index);
                    var vColorR = profile.GetCustomVertexData(VertexDataType.VertexColorR, density, rand);
                    var vColorG = profile.GetCustomVertexData(VertexDataType.VertexColorG, density, rand);
                    var vColorB = profile.GetCustomVertexData(VertexDataType.VertexColorB, density, rand);
                    var vColorA = profile.GetCustomVertexData(VertexDataType.VertexColorA, density, rand);
                    var uv1Z    = profile.GetCustomVertexData(VertexDataType.UV1Z, density, rand);
                    var uv1W    = profile.GetCustomVertexData(VertexDataType.UV1W, density, rand);
                    var color   = new Color(vColorR, vColorG, vColorB, vColorA);

                    Quaternion normalRot = Quaternion.LookRotation(element.normal);
                    Quaternion slant     = Quaternion.AngleAxis(profile.Slant * 90f * (rand - 0.5f), Vector3.right);
                    Quaternion upRot     = Quaternion.AngleAxis(360f * rand, Vector3.up);
                    Quaternion rot       = normalRot *
                                           Quaternion.AngleAxis(90f, Vector3.right) *
                                           upRot *
                                           slant;
                    var instance = new CombineInstance();
                    instance.mesh        = Mesh.Instantiate(cache);
                    instance.mesh.colors = instance.mesh.colors.Select(_ => color).ToArray();
                    var uvs = new List <Vector4>();
                    instance.mesh.GetUVs(0, uvs);
                    instance.mesh.SetUVs(0, uvs.Select(v => new Vector4(v.x, v.y, uv1Z, uv1W)).ToList());
                    instance.transform = Matrix4x4.TRS(
                        element.position + Vector3.up * profile.GroundOffset,
                        rot,
                        scale);
                    combine.Add(instance);
                }
            }
            mesh.CombineMeshes(combine.ToArray());
            return(mesh);
        }
        private async Task <List <Element> > GenerateElements(Terrain terrain, Rect rect, MassiveGrassProfile profile,
                                                              int haltonOffset)
        {
            var context             = SynchronizationContext.Current;
            var terrainPos          = terrain.transform.position;
            var terrainSize         = terrain.terrainData.size.x;
            var terrainXZPos        = new Vector2(terrainPos.x, terrainPos.z);
            var localRect           = new Rect(rect.min - terrainXZPos, rect.size);
            var localNormalizedRect = new Rect(localRect.position / terrainSize, localRect.size / terrainSize);

            var haltons             = new Vector2[profile.AmountPerBlock];
            var normalizedPositions = new Vector2[profile.AmountPerBlock];
            var heights             = new float[profile.AmountPerBlock];
            var normals             = new Vector3[profile.AmountPerBlock];
            var list = new List <Element>();

            var done  = false;
            var range = Enumerable.Range(0, profile.AmountPerBlock).ToArray();

            list.AddRange(range.Select(_ => default(Element)));

            await Task.Run(() =>
            {
                for (var i = 0; i < profile.AmountPerBlock; i++)
                {
                    haltons[i] = new Vector2(
                        HaltonSequence.Base2(i + haltonOffset + profile.Seed),
                        HaltonSequence.Base3(i + haltonOffset + profile.Seed));
                    normalizedPositions[i] = localNormalizedRect.min + haltons[i] * localNormalizedRect.size;
                }
            });

            await Task.Run(async() =>
            {
                context.Post(_ =>
                {
                    for (var i = 0; i < profile.AmountPerBlock; i++)
                    {
                        if (terrain == null)
                        {
                            break;
                        }
                        var normalizedPosition = normalizedPositions[i];
                        heights[i]             =
                            terrain.terrainData.GetInterpolatedHeight(normalizedPosition.x, normalizedPosition.y);
                        normals[i] =
                            terrain.terrainData.GetInterpolatedNormal(normalizedPosition.x, normalizedPosition.y);
                    }

                    done = true;
                }, null);
            });

            while (!done)
            {
                await Task.Delay(1);
            }

            await Task.Run(() =>
            {
                for (var i = 0; i < profile.AmountPerBlock; i++)
                {
                    var haltonPos          = haltons[i];
                    var position           = haltonPos *rect.size + rect.min;
                    var normalizedPosition = localNormalizedRect.min + haltons[i] * localNormalizedRect.size;
                    list[i] = new Element(
                        i,
                        new Vector3(position.x, heights[i], position.y),
                        normalizedPosition,
                        normals[i]);
                }
            });

            return(list);
        }
        public async Task <MeshData> BuildMeshData(Terrain terrain, IReadOnlyCollection <Texture2D> alphaMaps,
                                                   MassiveGrassProfile profile, Element[] elements)
        {
            if (templateData == null)
            {
                var scale = new Vector3(profile.Scale.x, profile.Scale.y, profile.Scale.x);
                templateData = new MeshTemplateData(profile.Mesh, scale);
            }

            if (pool.Count <= 0)
            {
                pool.Push(new MeshData(profile.AmountPerBlock, templateData.vertexCount, templateData.indecesCount));
            }

            var terrainData = terrain.terrainData;
            var w           = terrainData.alphamapWidth;
            var h           = terrainData.alphamapHeight;

            var meshData    = pool.Pop();
            var actualCount = 0;
            var alphas      = new float[elements.Length];
            var layers      = new List <int>(profile.TerrainLayers.Length);

            foreach (var terrainLayer in profile.TerrainLayers)
            {
                for (var i = 0; i < terrainData.terrainLayers.Length; i++)
                {
                    if (terrainData.terrainLayers[i].name == terrainLayer.name)
                    {
                        layers.Add(i);
                    }
                }
            }

            for (var i = 0; i < elements.Length; i++)
            {
                var element = elements[i];
                var alpha   = 0f;

                foreach (var layer in layers)
                {
                    var texIndex = layer / 4;
                    if (texIndex < alphaMaps.Count)
                    {
                        var pixel = alphaMaps.ElementAt(layer / 4).GetPixelBilinear(
                            element.normalizedPosition.x * (w - 1f) / w,
                            element.normalizedPosition.y * (h - 1f) / h);
                        switch (layer % 4)
                        {
                        case 0:
                            alpha = Mathf.Max(alpha, pixel.r);
                            break;

                        case 1:
                            alpha = Mathf.Max(alpha, pixel.g);
                            break;

                        case 2:
                            alpha = Mathf.Max(alpha, pixel.b);
                            break;

                        case 3:
                            alpha = Mathf.Max(alpha, pixel.a);
                            break;
                        }
                    }
                }

                alphas[i] = alpha;
            }

            await Task.Run(() =>
            {
                for (var i = 0; i < elements.Length; i++)
                {
                    var element     = elements[i];
                    var validHeight = profile.HeightRange.x <= element.position.y &&
                                      element.position.y <= profile.HeightRange.y;
                    if (!validHeight)
                    {
                        continue;
                    }
                    var alpha = alphas[i];
                    if (alpha >= profile.AlphaMapThreshold)
                    {
                        Add(meshData, profile, element, alpha, actualCount++);
                    }
                    else
                    {
                        var rand = 1 - Mathf.Repeat(1f, ParkAndMiller.Get(i));
                        if (alpha > profile.DensityFactor *rand *rand)
                        {
                            Add(meshData, profile, element, alpha, actualCount++);
                        }
                    }
                }

                meshData.SetActualCount(
                    templateData.vertexCount *actualCount,
                    templateData.indecesCount *actualCount);
            });

            return(meshData);
        }
        private void Add(MeshData meshData, MassiveGrassProfile profile, Element element, float density, int index)
        {
            var vOrigin = index * templateData.vertexCount;
            var iOrigin = index * templateData.indecesCount;
            var rand    = ParkAndMiller.Get(element.index + 1000);

            var normalRot = Quaternion.LookRotation(element.normal);
            var slant     = Quaternion.AngleAxis(profile.Slant * 90f * (rand - 0.5f), Vector3.right);
            var slantWeak = Quaternion.AngleAxis(profile.Slant * 45f * (rand - 0.5f), Vector3.right);
            var upRot     = Quaternion.AngleAxis(360f * rand, Vector3.up);
            var idealRot  = normalRot *
                            Quaternion.AngleAxis(90f, Vector3.right) *
                            upRot;
            var rot = idealRot * slant;

//            var scale = profile.Scale * (1 + 0.4f * (rand - 0.5f));
            var scale    = Vector3.one * (1 + 0.4f * (rand - 0.5f));
            var rightVec = element.index % 2 == 0 ? rot * Vector3.right : rot * -Vector3.right;
            var upVec    = rot * Vector3.up;

            for (var i = 0; i < templateData.vertexCount; i++)
            {
                var vertPos = element.position + Vector3.up * profile.GroundOffset +
                              rot * Vector3.Scale(templateData.scaledVertices[i], scale);
                meshData.vertices[vOrigin + i] = vertPos;
                switch (profile.NormalType)
                {
                case NormalType.Up:
                    meshData.normals[vOrigin + i] = idealRot * Vector3.up;
                    break;

                default:
                    meshData.normals[vOrigin + i] = templateData.normals[i];
                    break;
                }

                var uv = templateData.uvs[i];

                var attr    = new MassiveGrassProfile.VertAttribute(density, rand, element.position, templateData.vertices[i]);
                var vColorR = profile.GetCustomVertexData(VertexDataType.VertexColorR, attr);
                var vColorG = profile.GetCustomVertexData(VertexDataType.VertexColorG, attr);
                var vColorB = profile.GetCustomVertexData(VertexDataType.VertexColorB, attr);
                var vColorA = profile.GetCustomVertexData(VertexDataType.VertexColorA, attr);
                var uv1Z    = profile.GetCustomVertexData(VertexDataType.UV1Z, attr);
                var uv1W    = profile.GetCustomVertexData(VertexDataType.UV1W, attr);
                var color   = new Color(vColorR, vColorG, vColorB, vColorA);

                meshData.colors[vOrigin + i] = color;
                meshData.uvs[vOrigin + i]    = new Vector4(uv.x, uv.y, uv1Z, uv1W);
            }

            for (var i = 0; i < templateData.indecesCount; i++)
            {
                var vi = vOrigin + templateData.triangles[i];
                if (vi >= vOrigin + templateData.vertexCount)
                {
                    var a = 100;
                }

                meshData.triangles[iOrigin + i] = vOrigin + templateData.triangles[i];
            }
        }
        private void AddQuad(MeshData meshData, MassiveGrassProfile profile, Element element, float density, int index)
        {
            var        vOrigin   = index * 4;
            var        iOrigin   = index * 6;
            var        rand      = ParkAndMiller.Get(element.index);
            Quaternion normalRot = Quaternion.LookRotation(element.normal);
            Quaternion slant     = Quaternion.AngleAxis(profile.Slant * 90f * (rand - 0.5f), Vector3.right);
            Quaternion slantWeak = Quaternion.AngleAxis(profile.Slant * 45f * (rand - 0.5f), Vector3.right);
            Quaternion upRot     = Quaternion.AngleAxis(360f * rand, Vector3.up);
            Quaternion rot       = normalRot *
                                   Quaternion.AngleAxis(90f, Vector3.right) *
                                   upRot *
                                   slant;
            var scale        = profile.Scale;
            var p1           = rot * new Vector3(-0.5f * scale.x, 1f * scale.y, 0f) + Vector3.up * profile.GroundOffset;
            var p2           = rot * new Vector3(0.5f * scale.x, 1f * scale.y, 0f) + Vector3.up * profile.GroundOffset;
            var p3           = rot * new Vector3(0.5f * scale.x, 0f, 0f) + Vector3.up * profile.GroundOffset;
            var p4           = rot * new Vector3(-0.5f * scale.x, 0f, 0f) + Vector3.up * profile.GroundOffset;
            var normal       = element.normal;
            var normalBottom = element.normal;

            switch (profile.NormalType)
            {
            case NormalType.KeepMesh:
                break;

            case NormalType.Up:
                normalBottom = normal = rot * Vector3.up;
                break;

            case NormalType.Shading:
                normal       = rot * Vector3.up;
                normalBottom = rot * Vector3.forward;
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }
            var vColorR = profile.GetCustomVertexData(VertexDataType.VertexColorR, density, rand);
            var vColorG = profile.GetCustomVertexData(VertexDataType.VertexColorG, density, rand);
            var vColorB = profile.GetCustomVertexData(VertexDataType.VertexColorB, density, rand);
            var vColorA = profile.GetCustomVertexData(VertexDataType.VertexColorA, density, rand);
            var uv1Z    = profile.GetCustomVertexData(VertexDataType.UV1Z, density, rand);
            var uv1W    = profile.GetCustomVertexData(VertexDataType.UV1W, density, rand);
            var color   = new Color(vColorR, vColorG, vColorB, vColorA);

            meshData.vertices[vOrigin + 0]  = element.position + p1;
            meshData.vertices[vOrigin + 1]  = element.position + p2;
            meshData.vertices[vOrigin + 2]  = element.position + p3;
            meshData.vertices[vOrigin + 3]  = element.position + p4;
            meshData.normals[vOrigin + 0]   = normal;
            meshData.normals[vOrigin + 1]   = normal;
            meshData.normals[vOrigin + 2]   = normalBottom;
            meshData.normals[vOrigin + 3]   = normalBottom;
            meshData.uvs[vOrigin + 0]       = new Vector4(0f, 1f, uv1Z, uv1W);
            meshData.uvs[vOrigin + 1]       = new Vector4(1f, 1f, uv1Z, uv1W);
            meshData.uvs[vOrigin + 2]       = new Vector4(1f, 0f, uv1Z, uv1W);
            meshData.uvs[vOrigin + 3]       = new Vector4(0f, 0f, uv1Z, uv1W);
            meshData.colors[vOrigin + 0]    = color;
            meshData.colors[vOrigin + 1]    = color;
            meshData.colors[vOrigin + 2]    = color;
            meshData.colors[vOrigin + 3]    = color;
            meshData.triangles[iOrigin + 0] = vOrigin + 0;
            meshData.triangles[iOrigin + 1] = vOrigin + 1;
            meshData.triangles[iOrigin + 2] = vOrigin + 2;
            meshData.triangles[iOrigin + 3] = vOrigin + 2;
            meshData.triangles[iOrigin + 4] = vOrigin + 3;
            meshData.triangles[iOrigin + 5] = vOrigin + 0;
        }
Exemple #12
0
        private async Task <List <Element> > GenerateElements(Terrain terrain, Rect rect, MassiveGrassProfile profile, int haltonOffset)
        {
            var list                = new List <Element>();
            var terrainPos          = terrain.transform.position;
            var terrainSize         = terrain.terrainData.size.x;
            var terrainXZPos        = new Vector2(terrainPos.x, terrainPos.z);
            var localRect           = new Rect(rect.min - terrainXZPos, rect.size);
            var localNormalizedRect = new Rect(localRect.position / terrainSize, localRect.size / terrainSize);

            for (var i = 0; i < profile.AmountPerBlock; i++)
            {
                var haltonPos          = new Vector2(HaltonSequence.Base2(i + haltonOffset), HaltonSequence.Base3(i + haltonOffset));
                var normalizedPosition = localNormalizedRect.min +
                                         haltonPos * localNormalizedRect.size;
                var height   = terrain.terrainData.GetInterpolatedHeight(normalizedPosition.x, normalizedPosition.y);
                var normal   = terrain.terrainData.GetInterpolatedNormal(normalizedPosition.x, normalizedPosition.y);
                var position = haltonPos * rect.size + rect.min;
                list.Add(
                    new Element(
                        i,
                        new Vector3(position.x, height, position.y),
                        normalizedPosition,
                        normal));
            }

            return(list);
        }
Exemple #13
0
        public async Task <MeshData> BuildMeshData(Terrain terrain, IReadOnlyCollection <Texture2D> alphaMaps, MassiveGrassGrid.CellIndex index, Rect rect, MassiveGrassProfile profile)
        {
            var elements = await GenerateElements(terrain, rect, profile, index.hash % 50000);

            builder = builder ?? profile.CreateBuilder();
            return(await builder.BuildMeshData(terrain, alphaMaps, profile, elements));
        }