Beispiel #1
0
        private void DoImportTrees()
        {
            if (!ImportTreeInstancesOnly)
            {
                GTreePrototypeGroup treeGroup = DesData.Foliage.Trees;
                if (treeGroup == null ||
                    treeGroup == GRuntimeSettings.Instance.foliageDefault.trees)
                {
                    CreateNewTreePrototypesGroup = true;
                }

                if (CreateNewTreePrototypesGroup)
                {
                    treeGroup = ScriptableObject.CreateInstance <GTreePrototypeGroup>();

#if UNITY_EDITOR
                    if (!Application.isPlaying)
                    {
                        string path      = AssetDatabase.GetAssetPath(DesData);
                        string directory = Path.GetDirectoryName(path);
                        string filePath  = Path.Combine(directory, string.Format("Trees_{0}_{1}.asset", DesData.Id, System.DateTime.Now.Ticks));
                        AssetDatabase.CreateAsset(treeGroup, filePath);
                    }
#endif
                    DesData.Foliage.Trees = treeGroup;
                }

                treeGroup.Prototypes.Clear();
                TreePrototype[] treePrototypes = SrcData.treePrototypes;
                for (int i = 0; i < treePrototypes.Length; ++i)
                {
                    GTreePrototype proto = (GTreePrototype)treePrototypes[i];
                    treeGroup.Prototypes.Add(proto);
                }
                GCommon.SetDirty(treeGroup);
            }

            DesData.Foliage.TreeInstances.Clear();
            TreeInstance[] treeInstances = SrcData.treeInstances;
            for (int i = 0; i < treeInstances.Length; ++i)
            {
                GTreeInstance t = (GTreeInstance)treeInstances[i];
                DesData.Foliage.TreeInstances.Add(t);
            }

            if (DesTerrain != null)
            {
                DesData.Foliage.SetTreeRegionDirty(GCommon.UnitRect);
                DesTerrain.UpdateTreesPosition();
                DesData.Foliage.ClearTreeDirtyRegions();
            }

            DesData.SetDirty(GTerrainData.DirtyFlags.Foliage);
            //GC.Collect();
        }
Beispiel #2
0
        private bool IsInstancingEnabledForAllMaterials(GTreePrototype p)
        {
            if (!enableInstancing)
            {
                return(false);
            }
            if (p.SharedMaterials == null || p.SharedMaterials.Length == 0)
            {
                return(false);
            }
            for (int i = 0; i < p.SharedMaterials.Length; ++i)
            {
                if (!p.SharedMaterials[i].enableInstancing)
                {
                    return(false);
                }
            }

            return(true);
        }
Beispiel #3
0
        private void ConvertToTreePrototypeGroup()
        {
            GTreePrototypeGroup group = ScriptableObject.CreateInstance <GTreePrototypeGroup>();

            for (int i = 0; i < instance.Prototypes.Count; ++i)
            {
                GameObject prefab = instance.Prototypes[i];
                if (prefab != null)
                {
                    group.Prototypes.Add(GTreePrototype.Create(prefab));
                }
            }

            string path      = AssetDatabase.GetAssetPath(instance);
            string directory = Path.GetDirectoryName(path);
            string filePath  = Path.Combine(directory, string.Format("{0}_{1}_{2}.asset", instance.name, "Trees", GCommon.GetUniqueID()));

            AssetDatabase.CreateAsset(group, filePath);

            Selection.activeObject = group;
        }
Beispiel #4
0
        private void LateUpdate()
        {
            if (Terrain == null)
            {
                return;
            }
            if (Terrain.TerrainData == null)
            {
                return;
            }
            if (Terrain.TerrainData.Foliage.Trees == null)
            {
                return;
            }
            if (Terrain.TerrainData.Foliage.Trees.Prototypes.Count == 0)
            {
                return;
            }
            if (treeInstances == null || treeInstances.Length == 0)
            {
                return;
            }

            GameObject actualTarget = null;

            if (Target != null)
            {
                actualTarget = Target;
            }
            else if (Camera.main != null)
            {
                actualTarget = Camera.main.gameObject;
            }

            if (actualTarget == null)
            {
                return;
            }
            Vector3 targetLocalPos   = Terrain.transform.InverseTransformPoint(actualTarget.transform.position);
            GTreeColliderCullJob job = new GTreeColliderCullJob()
            {
                instances   = nativeTreeInstances,
                cullResults = nativeCullResults,
                maxDistance = distance,
                targetPos   = targetLocalPos
            };
            JobHandle handle = job.Schedule(nativeTreeInstances.Length, 100);

            handle.Complete();

            if (cullResults == null || cullResults.Length != nativeCullResults.Length)
            {
                cullResults = new bool[nativeCullResults.Length];
            }

            nativeCullResults.CopyTo(cullResults);

            List <GTreePrototype> prototypes = Terrain.TerrainData.Foliage.Trees.Prototypes;
            int     colliderIndex            = 0;
            Vector3 terrainPos = Terrain.transform.position;
            Vector3 worldPos   = Vector3.zero;

            if (terrain.TerrainData.Rendering.DrawTrees)
            {
                for (int i = 0; i < treeInstances.Length; ++i)
                {
                    if (cullResults[i] == false)
                    {
                        continue;
                    }

                    GTreeInstance  tree      = treeInstances[i];
                    GTreePrototype prototype = prototypes[tree.prototypeIndex];
                    if (prototype.prefab == null)
                    {
                        continue;
                    }
                    if (!prototype.hasCollider)
                    {
                        continue;
                    }

                    CapsuleCollider col = GetCollider(colliderIndex);
                    colliderIndex += 1;

                    worldPos.Set(
                        tree.position.x + terrainPos.x,
                        tree.position.y + terrainPos.y,
                        tree.position.z + terrainPos.z);
                    col.transform.position   = worldPos;
                    col.transform.rotation   = tree.rotation;
                    col.transform.localScale = tree.scale;
                    GTreeColliderInfo colliderInfo = prototype.colliderInfo;
                    col.center           = colliderInfo.center;
                    col.radius           = colliderInfo.radius;
                    col.height           = colliderInfo.height;
                    col.direction        = colliderInfo.direction;
                    col.gameObject.layer = prototype.layer;
                    if (CopyTreeTag)
                    {
                        col.gameObject.tag = prototype.prefab.tag;
                    }
                    col.gameObject.SetActive(true);
                }
            }

            int colliderCount = Colliders.Count;

            for (int i = colliderIndex; i < colliderCount; ++i)
            {
                CapsuleCollider col = GetCollider(i);
                col.gameObject.SetActive(false);
            }
        }
Beispiel #5
0
        private void DrawInstanced(int prototypeIndex)
        {
            GTreePrototype proto = prototypes[prototypeIndex];
            Mesh           mesh  = proto.sharedMesh;

            Material[] materials    = proto.sharedMaterials;
            int        submeshCount = prototypeCache[prototypeIndex].subMeshCount;
            int        drawCount    = Mathf.Min(submeshCount, materials.Length);

            Mesh           billboardMesh     = null;
            Material       billboardMaterial = null;
            BillboardAsset billboard         = proto.billboard;

            if (billboard != null)
            {
                billboardMesh     = GBillboardUtilities.GetMesh(billboard);
                billboardMaterial = billboard.material;
            }

            bool canDrawInstanced          = prototypeCache[prototypeIndex].canDrawInstanced;
            bool canDrawBillboardInstanced = prototypeCache[prototypeIndex].canDrawBillboardInstanced;

            batchInstanceCount          = 0;
            billboardBatchInstanceCount = 0;
            int count = instancePrototypeIndices.Length;

            for (int i = 0; i <= count; ++i)
            {
                if (i == count || batchInstanceCount == BATCH_MAX_INSTANCE_COUNT)
                {
                    if (canDrawInstanced)
                    {
                        for (int d = 0; d < drawCount; ++d)
                        {
                            Graphics.DrawMeshInstanced(
                                mesh, d, materials[d],
                                batchContainer, batchInstanceCount, null,
                                proto.shadowCastingMode, proto.receiveShadow, proto.layer,
                                camera, LightProbeUsage.BlendProbes);
                        }
                        batchInstanceCount = 0;
                    }
                }

                if (i == count || billboardBatchInstanceCount == BATCH_MAX_INSTANCE_COUNT)
                {
                    if (billboard != null && canDrawBillboardInstanced)
                    {
                        Graphics.DrawMeshInstanced(
                            billboardMesh, 0, billboardMaterial,
                            billboardBatchContainer, billboardBatchInstanceCount, null,
                            proto.billboardShadowCastingMode, proto.BillboardReceiveShadow, proto.layer,
                            camera, LightProbeUsage.BlendProbes);
                        billboardBatchInstanceCount = 0;
                    }
                }

                if (i == count)
                {
                    break;
                }

                if (instanceCullResults[i] == CULLED)
                {
                    continue;
                }
                if (instancePrototypeIndices[i] != prototypeIndex)
                {
                    continue;
                }

                if (instanceCullResults[i] == VISIBLE)
                {
                    if (canDrawInstanced)
                    {
                        batchContainer[batchInstanceCount] = instanceTransforms[i];
                        batchInstanceCount += 1;
                    }
                    else
                    {
                        for (int d = 0; d < drawCount; ++d)
                        {
                            Graphics.DrawMesh(
                                mesh, instanceTransforms[i], materials[d],
                                proto.layer, camera, d, null,
                                proto.shadowCastingMode, proto.receiveShadow,
                                null, LightProbeUsage.BlendProbes, null);
                        }
                    }
                }
                else if (instanceCullResults[i] == BILLBOARD && billboard != null)
                {
                    if (canDrawBillboardInstanced)
                    {
                        billboardBatchContainer[billboardBatchInstanceCount] = instanceTransforms[i];
                        billboardBatchInstanceCount += 1;
                    }
                    else
                    {
                        Graphics.DrawMesh(
                            billboardMesh, instanceTransforms[i], billboardMaterial,
                            proto.layer, camera, 0, null,
                            proto.billboardShadowCastingMode, proto.BillboardReceiveShadow,
                            null, LightProbeUsage.BlendProbes, null);
                    }
                }
            }
        }
Beispiel #6
0
        private void InitFrame(Camera cam)
        {
            foliage = terrain.TerrainData.Foliage;

            terrainPosition = terrain.transform.position;
            terrainSize     = terrain.TerrainData.Geometry.Size;
            treeDistance    = terrain.TerrainData.Rendering.TreeDistance;
            billboardStart  = terrain.TerrainData.Rendering.BillboardStart;
            cullVolumeBias  = GRuntimeSettings.Instance.renderingDefault.cullVolumeBias;

            if (terrain.TerrainData.Foliage.Trees != null)
            {
                prototypes = terrain.TerrainData.Foliage.Trees.Prototypes;
            }
            else
            {
                prototypes = new List <GTreePrototype>();
            }

            if (prototypeCache == null || prototypeCache.Length != prototypes.Count)
            {
                prototypeCache = new PrototypeCache[prototypes.Count];
            }

            for (int i = 0; i < prototypes.Count; ++i)
            {
                GTreePrototype p     = prototypes[i];
                PrototypeCache cache = prototypeCache[i];

                bool valid = prototypes[i].IsValid;
                cache.validation = valid;
                if (valid)
                {
                    cache.subMeshCount              = p.sharedMesh.subMeshCount;
                    cache.canDrawInstanced          = IsInstancingEnabledForAllMaterials(p);
                    cache.canDrawBillboardInstanced =
                        p.billboard != null &&
                        p.billboard.material != null &&
                        p.billboard.material.enableInstancing;
                }
                if (p.billboard != null)
                {
                    cache.billboardMesh = GBillboardUtilities.GetMesh(p.billboard);
                }
                if (p.billboard != null && p.billboard.material != null)
                {
                    if (cache.billboardImageTexcoords == null ||
                        cache.billboardImageTexcoords.Length != p.billboard.imageCount)
                    {
                        cache.billboardImageTexcoords = p.billboard.GetImageTexCoords();
                    }
                    Material mat = p.billboard.material;
                    mat.SetVectorArray(BILLBOARD_IMAGE_TEXCOORDS, cache.billboardImageTexcoords);
                    mat.SetInt(BILLBOARD_IMAGE_COUNT, p.billboard.imageCount);
                }

                prototypeCache[i] = cache;
            }

            enableInstancing = terrain.TerrainData.Rendering.EnableInstancing && SystemInfo.supportsInstancing;

            normalizedToLocalMatrix = Matrix4x4.Scale(terrainSize);
            localToWorldMatrix      = terrain.transform.localToWorldMatrix;
            normalizedToWorldMatrix = localToWorldMatrix * normalizedToLocalMatrix;

            camera = cam;
            if (frustum == null)
            {
                frustum = new Plane[6];
            }
            GFrustumUtilities.Calculate(camera, frustum, treeDistance);
            if (nearFrustumCorners == null)
            {
                nearFrustumCorners = new Vector3[4];
            }
            if (farFrustumCorners == null)
            {
                farFrustumCorners = new Vector3[4];
            }

            if (batchContainer == null)
            {
                batchContainer = new Matrix4x4[BATCH_MAX_INSTANCE_COUNT];
            }
            if (billboardBatchContainer == null)
            {
                billboardBatchContainer = new Matrix4x4[BATCH_MAX_INSTANCE_COUNT];
            }

            if (!isWarningLogged)
            {
                for (int i = 0; i < prototypes.Count; ++i)
                {
                    if (!prototypes[i].IsValid)
                    {
                        string msg = string.Format(
                            "Tree prototye {0}: " +
                            "The prototype is not valid, make sure you've assigned a prefab with correct mesh and materials setup.",
                            i);
                        Debug.LogWarning(msg);
                    }
                    if (enableInstancing && prototypes[i].IsValid)
                    {
                        if (!IsInstancingEnabledForAllMaterials(prototypes[i]))
                        {
                            string msg = string.Format(
                                "Tree prototype {0} ({1}): " +
                                "Instancing need to be enabled for all materials for the renderer to work at its best. " +
                                "Otherwise it will fallback to non-instanced for this prototype.",
                                i, prototypes[i].Prefab.name);
                            Debug.LogWarning(msg);
                        }
                        if (prototypes[i].billboard != null &&
                            prototypes[i].billboard.material != null &&
                            prototypes[i].billboard.material.enableInstancing == false)
                        {
                            string msg = string.Format(
                                "Tree prototype {0} ({1}): " +
                                "Instancing need to be enabled for billboard material for the renderer to work at its best. " +
                                "Otherwise it will fallback to non-instanced for this prototype when render billboards.",
                                i, prototypes[i].Prefab.name);
                            Debug.LogWarning(msg);
                        }
                    }
                }

                isWarningLogged = true;
            }
        }