Пример #1
0
        public void AddGrassInstances(List <GGrassInstance> instances)
        {
            Rect[] uvRects = new Rect[GrassPatches.Length];
            for (int r = 0; r < uvRects.Length; ++r)
            {
                uvRects[r] = GrassPatches[r].GetUvRange();
            }

            int[] dirty = new int[GrassPatches.Length];
            for (int i = 0; i < instances.Count; ++i)
            {
                GGrassInstance grass = instances[i];
                for (int r = 0; r < uvRects.Length; ++r)
                {
                    if (uvRects[r].Contains(new Vector2(grass.Position.x, grass.Position.z)))
                    {
                        grassPatches[r].Instances.Add(grass);
                        dirty[r] = 1;
                        break;
                    }
                }
            }

            for (int i = 0; i < dirty.Length; ++i)
            {
                if (dirty[i] == 1)
                {
                    GrassPatches[i].RecalculateBounds();
                    GrassPatches[i].Changed();
                }
            }
        }
Пример #2
0
        public static GGrassInstance Create(int prototypeIndex)
        {
            GGrassInstance instance = new GGrassInstance();

            instance.PrototypeIndex = prototypeIndex;
            instance.Position       = Vector3.zero;
            instance.Rotation       = Quaternion.identity;
            instance.Scale          = Vector3.one;
            return(instance);
        }
Пример #3
0
        internal void Deserialize()
        {
            if (prototypeIndexSerializeData != null &&
                positionSerializeData != null &&
                rotationSerializeData != null &&
                scaleSerializeData != null)
            {
                prototypeIndexSerializeData = GCompressor.Decompress(prototypeIndexSerializeData);
                positionSerializeData       = GCompressor.Decompress(positionSerializeData);
                rotationSerializeData       = GCompressor.Decompress(rotationSerializeData);
                scaleSerializeData          = GCompressor.Decompress(scaleSerializeData);

                int[]   indices   = new int[prototypeIndexSerializeData.Length / sizeof(int)];
                float[] positions = new float[positionSerializeData.Length / sizeof(float)];
                float[] rotations = new float[rotationSerializeData.Length / sizeof(float)];
                float[] scales    = new float[scaleSerializeData.Length / sizeof(float)];

                Buffer.BlockCopy(prototypeIndexSerializeData, 0, indices, 0, prototypeIndexSerializeData.Length);
                Buffer.BlockCopy(positionSerializeData, 0, positions, 0, positionSerializeData.Length);
                Buffer.BlockCopy(rotationSerializeData, 0, rotations, 0, rotationSerializeData.Length);
                Buffer.BlockCopy(scaleSerializeData, 0, scales, 0, scaleSerializeData.Length);

                Instances.Clear();
                for (int i = 0; i < indices.Length; ++i)
                {
                    GGrassInstance grass = GGrassInstance.Create(indices[i]);
                    grass.Position = new Vector3(
                        positions[i * 3 + 0],
                        positions[i * 3 + 1],
                        positions[i * 3 + 2]);
                    grass.Rotation = new Quaternion(
                        rotations[i * 4 + 0],
                        rotations[i * 4 + 1],
                        rotations[i * 4 + 2],
                        rotations[i * 4 + 3]);
                    grass.Scale = new Vector3(
                        scales[i * 3 + 0],
                        scales[i * 3 + 1],
                        scales[i * 3 + 2]);
                    Instances.Add(grass);
                }
            }
        }
Пример #4
0
        internal void Serialize()
        {
            int[]   protoIndices = new int[Instances.Count];
            float[] positions    = new float[Instances.Count * 3];
            float[] rotations    = new float[Instances.Count * 4];
            float[] scales       = new float[Instances.Count * 3];
            for (int i = 0; i < Instances.Count; ++i)
            {
                GGrassInstance grass = Instances[i];
                protoIndices[i] = grass.PrototypeIndex;

                positions[i * 3 + 0] = grass.Position.x;
                positions[i * 3 + 1] = grass.Position.y;
                positions[i * 3 + 2] = grass.Position.z;

                rotations[i * 4 + 0] = grass.Rotation.x;
                rotations[i * 4 + 1] = grass.Rotation.y;
                rotations[i * 4 + 2] = grass.Rotation.z;
                rotations[i * 4 + 3] = grass.Rotation.w;

                scales[i * 3 + 0] = grass.Scale.x;
                scales[i * 3 + 1] = grass.Scale.y;
                scales[i * 3 + 2] = grass.Scale.z;
            }

            prototypeIndexSerializeData = new byte[Buffer.ByteLength(protoIndices)];
            Buffer.BlockCopy(protoIndices, 0, prototypeIndexSerializeData, 0, prototypeIndexSerializeData.Length);
            prototypeIndexSerializeData = GCompressor.Compress(prototypeIndexSerializeData);

            positionSerializeData = new byte[Buffer.ByteLength(positions)];
            Buffer.BlockCopy(positions, 0, positionSerializeData, 0, positionSerializeData.Length);
            positionSerializeData = GCompressor.Compress(positionSerializeData);

            rotationSerializeData = new byte[Buffer.ByteLength(rotations)];
            Buffer.BlockCopy(rotations, 0, rotationSerializeData, 0, rotationSerializeData.Length);
            rotationSerializeData = GCompressor.Compress(rotationSerializeData);

            scaleSerializeData = new byte[Buffer.ByteLength(scales)];
            Buffer.BlockCopy(scales, 0, scaleSerializeData, 0, scaleSerializeData.Length);
            scaleSerializeData = GCompressor.Compress(scaleSerializeData);
        }
Пример #5
0
        public void AddGrassInstances(List <GGrassInstance> instances)
        {
            Rect[] uvRects = new Rect[GrassPatches.Length];
            for (int r = 0; r < uvRects.Length; ++r)
            {
                uvRects[r] = GrassPatches[r].GetUvRange();
            }

            for (int i = 0; i < instances.Count; ++i)
            {
                GGrassInstance grass = instances[i];
                for (int r = 0; r < uvRects.Length; ++r)
                {
                    if (uvRects[r].Contains(new Vector2(grass.Position.x, grass.Position.z)))
                    {
                        grassPatches[r].Instances.Add(grass);
                        break;
                    }
                }
            }
            CalculateEstimatedGrassStorage();
        }
Пример #6
0
        private static void RenderPreviewGrass(GStylizedTerrain t, Camera cam)
        {
            if (t.TerrainData.Foliage.Grasses == null ||
                t.TerrainData.Foliage.Grasses.Prototypes.Count == 0)
            {
                return;
            }

            List <GGrassPrototype> prototypes = t.TerrainData.Foliage.Grasses.Prototypes;
            Vector3 dimension = new Vector3(
                t.TerrainData.Geometry.Width,
                t.TerrainData.Geometry.Height,
                t.TerrainData.Geometry.Length);
            Vector3 localPos = Vector3.zero;
            Vector3 worldPos = Vector3.zero;
            Vector3 scale    = Vector3.zero;

            Material mat = GGriffinSettings.Instance.TerrainDataDefault.Foliage.GrassPreviewMaterial;

            Rect[]        dirtyRects = t.TerrainData.Foliage.GetGrassDirtyRegions();
            GGrassPatch[] patches    = t.TerrainData.Foliage.GrassPatches;
            bool[]        dirtyFlags = new bool[patches.Length];
            for (int p = 0; p < patches.Length; ++p)
            {
                dirtyFlags[p] = false;
                Rect uvRange = patches[p].GetUvRange();
                for (int r = 0; r < dirtyRects.Length; ++r)
                {
                    if (uvRange.Overlaps(dirtyRects[r]))
                    {
                        dirtyFlags[p] = true;
                        break;
                    }
                }
            }

            for (int pIndex = 0; pIndex < prototypes.Count; ++pIndex)
            {
                GGrassPrototype proto = prototypes[pIndex];
                //mat.SetTexture(MAINTEX_PROPERTY, proto.Texture);
                mat.SetPass(0);
                for (int p = 0; p < patches.Length; ++p)
                {
                    if (dirtyFlags[p] == false)
                    {
                        continue;
                    }

                    int instanceCount = patches[p].Instances.Count;
                    for (int j = 0; j < instanceCount; ++j)
                    {
                        GGrassInstance grass = patches[p].Instances[j];
                        if (grass.PrototypeIndex != pIndex)
                        {
                            continue;
                        }

                        localPos.Set(
                            dimension.x * grass.Position.x,
                            dimension.y * grass.Position.y,
                            dimension.z * grass.Position.z);
                        worldPos = t.transform.TransformPoint(localPos);
                        scale.Set(
                            prototypes[grass.PrototypeIndex].Size.x * grass.Scale.x,
                            prototypes[grass.PrototypeIndex].Size.y * grass.Scale.y,
                            prototypes[grass.PrototypeIndex].Size.z * grass.Scale.z);

                        Mesh mesh = prototypes[grass.PrototypeIndex].GetBaseMesh();
                        Graphics.DrawMeshNow(
                            mesh,
                            Matrix4x4.TRS(worldPos, grass.Rotation, scale));
                    }
                }
            }
        }
Пример #7
0
        private static void RenderGrass(GStylizedTerrain t, Camera cam)
        {
            if (t.TerrainData.Foliage.Grasses == null ||
                t.TerrainData.Foliage.Grasses.Prototypes.Count == 0)
            {
                return;
            }
            List <GGrassPrototype> prototypes = t.TerrainData.Foliage.Grasses.Prototypes;

            GGrassPatch[] patches = t.TerrainData.Foliage.GrassPatches;
            if (patches == null)
            {
                return;
            }

            float   grassDistance = t.TerrainData.Rendering.GrassDistance;
            Vector3 dimension     = new Vector3(
                t.TerrainData.Geometry.Width,
                t.TerrainData.Geometry.Height,
                t.TerrainData.Geometry.Length);
            float   patchWorldRadius = dimension.x * 0.5f / t.TerrainData.Foliage.PatchGridSize;
            Vector3 boundLocalPos    = Vector3.zero;
            Vector3 boundWorldPos    = Vector3.zero;

            int FLAG_CULLED  = 0;
            int FLAG_DIRTY   = 1;
            int FLAG_BATCHED = 2;

            int[]  flags     = new int[patches.Length];
            Rect[] dirtyRect = t.TerrainData.Foliage.GetGrassDirtyRegions();
            for (int i = 0; i < patches.Length; ++i)
            {
                Rect uvRect = patches[i].GetUvRange();
                boundLocalPos.Set(
                    uvRect.center.x * dimension.x,
                    0,
                    uvRect.center.y * dimension.z);
                boundWorldPos   = t.transform.TransformPoint(boundLocalPos);
                boundWorldPos.y = cam.transform.position.y;
                if (Vector3.Distance(boundWorldPos, cam.transform.position) - patchWorldRadius > grassDistance)
                {
                    flags[i] = FLAG_CULLED;
                    continue;
                }

                for (int r = 0; r < dirtyRect.Length; ++r)
                {
                    if (dirtyRect[r].Overlaps(uvRect))
                    {
                        flags[i] = FLAG_DIRTY;
                        break;
                    }
                }

                if (flags[i] == FLAG_DIRTY)
                {
                    continue;
                }

                flags[i] = FLAG_BATCHED;
            }

            Vector3 meshLocalPos = Vector3.zero;
            Vector3 meshWorldPos = Vector3.zero;

            grassMaterialPropertyBlock.Clear();
            if (t.TerrainData.Foliage.EnableInteractiveGrass)
            {
                grassMaterialPropertyBlock.SetTexture(VECTOR_FIELD_PROPERTY, t.GetGrassVectorFieldRenderTexture());
                grassMaterialPropertyBlock.SetMatrix(WORLD_TO_NORMALIZED_PROPERTY, t.GetWorldToNormalizedMatrix());
            }

            grassMaterialPropertyBlock.SetTexture(NOISETEX_PROPERTY, GGriffinSettings.Instance.DefaultNoiseTexture);
            IEnumerator <GWindZone> windZone = GWindZone.ActiveWindZones.GetEnumerator();

            if (windZone.MoveNext())
            {
                GWindZone w = windZone.Current;
                grassMaterialPropertyBlock.SetVector(WIND_PROPERTY, w.GetWindParams());
            }

            //draw batched
            //Material grassMat = GCommon.CurrentRenderPipeline == GRenderPipelineType.Lightweight ?
            //    GGriffinSettings.Instance.TerrainDataDefault.Foliage.GrassMaterialLW :
            //    GGriffinSettings.Instance.TerrainDataDefault.Foliage.GrassMaterial;
            Material grassMat = null;

            if (GCommon.CurrentRenderPipeline == GRenderPipelineType.Builtin)
            {
                grassMat = t.TerrainData.Foliage.EnableInteractiveGrass ?
                           GGriffinSettings.Instance.TerrainDataDefault.Foliage.GrassInteractiveMaterial :
                           GGriffinSettings.Instance.TerrainDataDefault.Foliage.GrassMaterial;
                if (grassMat == null)
                {
                    Debug.Log("Grass material missing. Try re-installing the Polaris V2 package.");
                }
            }
            else if (GCommon.CurrentRenderPipeline == GRenderPipelineType.Lightweight)
            {
                grassMat = t.TerrainData.Foliage.EnableInteractiveGrass ?
                           GGriffinSettings.Instance.TerrainDataDefault.Foliage.GrassInteractiveMaterialLWRP :
                           GGriffinSettings.Instance.TerrainDataDefault.Foliage.GrassMaterialLWRP;
                if (grassMat == null)
                {
                    Debug.Log("Grass material missing. Try installing the 'Lightweight Render Pipeline Support' extension from the Extension Window (Window>Griffin>Tools>Extension)");
                }
            }
            else if (GCommon.CurrentRenderPipeline == GRenderPipelineType.Universal)
            {
                grassMat = t.TerrainData.Foliage.EnableInteractiveGrass ?
                           GGriffinSettings.Instance.TerrainDataDefault.Foliage.GrassInteractiveMaterialURP :
                           GGriffinSettings.Instance.TerrainDataDefault.Foliage.GrassMaterialURP;
                if (grassMat == null)
                {
                    Debug.Log("Grass material missing. Try installing the 'Universal Render Pipeline Support' extension from the Extension Window (Window>Griffin>Tools>Extension)");
                }
            }

            if (grassMat == null)
            {
                return;
            }

            for (int i = 0; i < patches.Length; ++i)
            {
                if (flags[i] != FLAG_BATCHED)
                {
                    continue;
                }
                for (int p = 0; p < prototypes.Count; ++p)
                {
                    grassMaterialPropertyBlock.SetColor(COLOR_PROPERTY, prototypes[p].Color);
                    grassMaterialPropertyBlock.SetFloat(BEND_FACTOR_PROPERTY, prototypes[p].BendFactor);
                    if (prototypes[p].Shape != GGrassShape.DetailObject && prototypes[p].Texture != null)
                    {
                        grassMaterialPropertyBlock.SetTexture(MAINTEX_PROPERTY, prototypes[p].Texture);
                    }
                    Mesh mesh = patches[i].GetMesh(p);
                    if (mesh != null)
                    {
                        meshLocalPos = mesh.bounds.center;
                        meshWorldPos = t.transform.TransformPoint(meshLocalPos);
                        if (Vector3.Distance(meshWorldPos, cam.transform.position) - patchWorldRadius > grassDistance)
                        {
                            continue;
                        }

                        Graphics.DrawMesh(
                            mesh,
                            Matrix4x4.TRS(t.transform.position, Quaternion.identity, Vector3.one),
                            prototypes[p].Shape == GGrassShape.DetailObject ? prototypes[p].DetailMaterial : grassMat,
                            prototypes[p].Layer,
                            cam,
                            0,
                            prototypes[p].Shape == GGrassShape.DetailObject ? null : grassMaterialPropertyBlock,
                            prototypes[p].Shape == GGrassShape.DetailObject ? prototypes[p].ShadowCastingMode : ShadowCastingMode.On,
                            prototypes[p].Shape == GGrassShape.DetailObject ? prototypes[p].ReceiveShadow : true,
                            null,
                            LightProbeUsage.BlendProbes,
                            null);
                    }
                }
            }

            if (GCommon.CurrentRenderPipeline == GRenderPipelineType.Builtin)
            {
                return;
            }

            Vector3 localPos = Vector3.zero;
            Vector3 worldPos = Vector3.zero;
            Vector3 scale    = Vector3.zero;

            Material previewMat = GGriffinSettings.Instance.TerrainDataDefault.Foliage.GrassPreviewMaterial;

            for (int pIndex = 0; pIndex < prototypes.Count; ++pIndex)
            {
                GGrassPrototype proto = prototypes[pIndex];
                //grassMaterialPropertyBlock.Clear();
                //grassMaterialPropertyBlock.SetTexture(MAINTEX_PROPERTY, proto.Texture);

                for (int i = 0; i < patches.Length; ++i)
                {
                    if (flags[i] != FLAG_DIRTY)
                    {
                        continue;
                    }
                    GGrassPatch patch         = patches[i];
                    int         instanceCount = patch.Instances.Count;
                    for (int j = 0; j < instanceCount; ++j)
                    {
                        GGrassInstance grass = patch.Instances[j];
                        if (grass.PrototypeIndex != pIndex)
                        {
                            continue;
                        }

                        localPos.Set(
                            dimension.x * grass.Position.x,
                            dimension.y * grass.Position.y,
                            dimension.z * grass.Position.z);
                        worldPos = t.transform.TransformPoint(localPos);
                        scale.Set(
                            prototypes[grass.PrototypeIndex].Size.x * grass.Scale.x,
                            prototypes[grass.PrototypeIndex].Size.y * grass.Scale.y,
                            prototypes[grass.PrototypeIndex].Size.z * grass.Scale.z);

                        Mesh mesh = prototypes[grass.PrototypeIndex].GetBaseMesh();
                        Graphics.DrawMesh(
                            mesh,
                            Matrix4x4.TRS(worldPos, grass.Rotation, scale),
                            previewMat,
                            prototypes[grass.PrototypeIndex].Layer,
                            cam,
                            0,
                            null,     //grassMaterialPropertyBlock
                            ShadowCastingMode.On,
                            true,
                            null,
                            LightProbeUsage.BlendProbes,
                            null);
                    }
                }
            }
        }
Пример #8
0
        public void UpdateMesh(int prototypeIndex)
        {
            if (Foliage.Grasses == null)
            {
                return;
            }
            if (prototypeIndex < 0 || prototypeIndex >= Foliage.Grasses.Prototypes.Count)
            {
                return;
            }

            StripInstances(prototypeIndex);
            string key = GetPatchMeshName(Index, prototypeIndex);
            Mesh   m   = Foliage.TerrainData.FoliageData.GetMesh(key);

            if (m != null && Foliage.TerrainData.Foliage.GrassInstanceCount == 0)
            {
                Foliage.TerrainData.FoliageData.DeleteMesh(key);
                return;
            }
            else if (m == null)
            {
                m = new Mesh();
                m.MarkDynamic();
                m.name = key;
                Foliage.TerrainData.FoliageData.SetMesh(key, m);
            }

            GGrassPrototype prototype   = Foliage.Grasses.Prototypes[prototypeIndex];
            Mesh            baseMesh    = prototype.GetBaseMesh();
            Vector3         terrainSize = new Vector3(
                Foliage.TerrainData.Geometry.Width,
                Foliage.TerrainData.Geometry.Height,
                Foliage.TerrainData.Geometry.Length);

            GCombineInfo meshTemplate = new GCombineInfo(baseMesh);

            List <Matrix4x4> transforms = new List <Matrix4x4>();
            Rect             uvRange    = GetUvRange();

            for (int i = 0; i < Instances.Count; ++i)
            {
                GGrassInstance grass = Instances[i];
                if (grass.PrototypeIndex != prototypeIndex)
                {
                    continue;
                }
                if (!uvRange.Contains(new Vector2(grass.Position.x, grass.Position.z)))
                {
                    continue;
                }

                Matrix4x4 t = Matrix4x4.TRS(
                    new Vector3(grass.Position.x * terrainSize.x, grass.Position.y * terrainSize.y + prototype.PivotOffset, grass.Position.z * terrainSize.z),
                    grass.Rotation,
                    new Vector3(prototype.Size.x * grass.Scale.x, prototype.Size.y * grass.Scale.y, prototype.Size.z * grass.Scale.z));
                transforms.Add(t);
            }

            int vertexCount = meshTemplate.Vertices.Length * transforms.Count;

            if (vertexCount > 65000)
            {
                string warning = string.Format("Failed to batch grass meshes at patch {0}, prototypeIndex {1} due to vertices limit (batch: {2}, limit: 65000). Consider removing some instances or increase Patch Grid Size and try again!", Index.ToString("0"), prototypeIndex, vertexCount);
                Debug.LogWarning(warning);
            }

            GJobSystem.RunOnBackground(() =>
            {
                GCombineInfo result = GCombiner.Combine(meshTemplate, transforms);
                System.Action task  = () =>
                {
                    if (result.Vertices.Length == 0)
                    {
                        Foliage.TerrainData.FoliageData.DeleteMesh(key);
                    }
                    else
                    {
                        m.Clear();
                        m.vertices = result.Vertices;
                        m.uv       = result.UVs;
                        //m.colors32 = result.Colors;
                        m.triangles = result.Triangles;
                        m.RecalculateBounds();

                        //Reduce mesh storage space
                        m.colors32 = null;
                        m.normals  = null;
                        m.tangents = null;
                        m.uv2      = null;
                        //m.RecalculateNormals();
                        //m.RecalculateTangents();

                        GCommon.SetDirty(m);
                        //System.GC.Collect(); ==>This line will cause the editor to hang soooooo long!
                    }
                };

                if (result.Vertices.Length < 1000)
                {
                    GJobSystem.RunOnMainThread(task);
                }
                else
                {
                    GJobSystem.ScheduleOnMainThread(task, 0);
                }
            });
        }
Пример #9
0
        private void StripInstances(int prototypeIndex)
        {
            if (Foliage.Grasses == null)
            {
                return;
            }
            int count = 0;

            for (int i = 0; i < Instances.Count; ++i)
            {
                if (Instances[i].PrototypeIndex == prototypeIndex)
                {
                    count += 1;
                }
            }

            if (count == 0)
            {
                return;
            }

            Mesh baseMesh = Foliage.Grasses.Prototypes[prototypeIndex].GetBaseMesh();

            if (baseMesh == null)
            {
                return;
            }

            int baseVertexCount = baseMesh.vertexCount;
            int vertexCount     = baseVertexCount * count;

            if (vertexCount < 65000)
            {
                return;
            }

            int        toRemoveCount = 1 + (vertexCount - 65000) / baseVertexCount;
            List <int> indices       = new List <int>();

            for (int i = 0; i < Instances.Count; ++i)
            {
                if (Instances[i].PrototypeIndex == prototypeIndex)
                {
                    indices.Add(i);
                }
            }

            GUtilities.ShuffleList(indices);
            for (int i = 0; i < toRemoveCount; ++i)
            {
                GGrassInstance instance = Instances[indices[i]];
                instance.PrototypeIndex = -1;
                Instances[indices[i]]   = instance;
            }

            int removedCount = Instances.RemoveAll(g => g.PrototypeIndex < 0);

            Debug.Log(string.Format(
                          "Stripped {0} instance{1} at patch {2}, prototype {3}.",
                          removedCount,
                          removedCount > 1 ? "s" : "",
                          Index.ToString("0"),
                          prototypeIndex));
        }