public static void FixMissingPrefab()
        {
            Object o = Selection.activeObject;

            if (o is GTreePrototypeGroup)
            {
                string[] prefabAssetPaths = new string[]
                {
                    "Assets/Griffin - PolarisV2/_Demo/Prefabs/AutumnTree1.prefab",
                    "Assets/Griffin - PolarisV2/_Demo/Prefabs/SpringTree1.prefab",
                    "Assets/Griffin - PolarisV2/_Demo/Prefabs/Pine_00.prefab",
                    "Assets/Griffin - PolarisV2/_Demo/Prefabs/Pine_01.prefab",
                    "Assets/Griffin - PolarisV2/_Demo/Prefabs/Dead.prefab",
                    "Assets/Griffin - PolarisV2/_Demo/Prefabs/Dead_Break.prefab"
                };

                GTreePrototypeGroup group = o as GTreePrototypeGroup;
                group.Prototypes.Clear();
                for (int i = 0; i < prefabAssetPaths.Length; ++i)
                {
                    GameObject     p     = AssetDatabase.LoadAssetAtPath <GameObject>(prefabAssetPaths[i]);
                    GTreePrototype proto = GTreePrototype.Create(p);
                    proto.Refresh();
                    group.Prototypes.Add(proto);
                }

                EditorUtility.SetDirty(group);
            }
        }
        public static void FixMissingTreeDemo00()
        {
            Object o = Selection.activeObject;

            if (o is GTreePrototypeGroup)
            {
                string[] prefabAssetPaths = new string[]
                {
                    "Assets/Polaris - Low Poly Ecosystem/Polaris - Low Poly Terrain Engine/Samples/Pinwheel Studio/Prefabs/Pine_00.prefab",
                    "Assets/Polaris - Low Poly Ecosystem/Polaris - Low Poly Terrain Engine/Samples/Pinwheel Studio/Prefabs/Dead.prefab",
                    "Assets/Polaris - Low Poly Ecosystem/Polaris - Low Poly Terrain Engine/Samples/Pinwheel Studio/Prefabs/Pine_01.prefab",
                    "Assets/Polaris - Low Poly Ecosystem/Polaris - Low Poly Terrain Engine/Samples/Pinwheel Studio/Prefabs/Dead_Break.prefab"
                };

                GTreePrototypeGroup group = o as GTreePrototypeGroup;
                group.Prototypes.Clear();
                for (int i = 0; i < prefabAssetPaths.Length; ++i)
                {
                    GameObject     p     = AssetDatabase.LoadAssetAtPath <GameObject>(prefabAssetPaths[i]);
                    GTreePrototype proto = GTreePrototype.Create(p);
                    proto.Refresh();
                    group.Prototypes.Add(proto);
                }

                EditorUtility.SetDirty(group);
            }
        }
        private void DrawPrototypesListGUI()
        {
            string label, id;

            for (int i = 0; i < instance.Prototypes.Count; ++i)
            {
                GTreePrototype p = instance.Prototypes[i];
                CachePrefabPath(p);

                label = p.Prefab != null && !string.IsNullOrEmpty(p.Prefab.name) ? p.Prefab.name : "Tree " + i;
                id    = "treeprototype" + i + instance.GetInstanceID().ToString();

                int         index = i;
                GenericMenu menu  = new GenericMenu();
                menu.AddItem(
                    new GUIContent("Remove"),
                    false,
                    () => { ConfirmAndRemovePrototypeAtIndex(index); });
                menu.AddItem(
                    new GUIContent("Sync with Prefab"),
                    false,
                    () => { p.Refresh(); });

                GEditorCommon.Foldout(label, false, id, () =>
                {
                    if (p.Prefab != null)
                    {
                        DrawPreview(p.Prefab);
                    }

                    p.Prefab    = EditorGUILayout.ObjectField("Prefab", p.Prefab, typeof(GameObject), false) as GameObject;
                    p.Billboard = EditorGUILayout.ObjectField("Billboard", p.Billboard, typeof(BillboardAsset), false) as BillboardAsset;

                    EditorGUI.BeginChangeCheck();
                    p.PivotOffset  = EditorGUILayout.Slider("Pivot Offset", p.PivotOffset, -1f, 1f);
                    p.BaseRotation = Quaternion.Euler(GEditorCommon.InlineVector3Field("Base Rotation", p.BaseRotation.eulerAngles));
                    p.BaseScale    = GEditorCommon.InlineVector3Field("Base Scale", p.BaseScale);
                    if (EditorGUI.EndChangeCheck())
                    {
                        ResetNativeArrays();
                    }
                    GUI.enabled       = !p.KeepPrefabLayer;
                    p.Layer           = EditorGUILayout.LayerField("Layer", p.Layer);
                    GUI.enabled       = true;
                    p.KeepPrefabLayer = EditorGUILayout.Toggle("Keep Prefab Layer", p.KeepPrefabLayer);

                    p.ShadowCastingMode = (ShadowCastingMode)EditorGUILayout.EnumPopup("Cast Shadow", p.ShadowCastingMode);
                    p.ReceiveShadow     = EditorGUILayout.Toggle("Receive Shadow", p.ReceiveShadow);

                    p.BillboardShadowCastingMode = (ShadowCastingMode)EditorGUILayout.EnumPopup("Billboard Cast Shadow", p.BillboardShadowCastingMode);
                    p.BillboardReceiveShadow     = EditorGUILayout.Toggle("Billboard Receive Shadow", p.BillboardReceiveShadow);

                    GUI.enabled = false;
                    EditorGUILayout.Toggle("Has Collider", p.HasCollider);
                    GUI.enabled = true;
                }, menu);
            }
        }
        public static GTreePrototype Create(GameObject g)
        {
            GTreePrototype prototype = new GTreePrototype();

            prototype.Prefab       = g;
            prototype.PivotOffset  = 0;
            prototype.BaseRotation = Quaternion.identity;
            prototype.BaseScale    = Vector3.one;
            return(prototype);
        }
Esempio n. 5
0
 private void CachePrefabPath(GTreePrototype p)
 {
     if (p.Prefab == null)
     {
         p.Editor_PrefabAssetPath = null;
     }
     else
     {
         p.Editor_PrefabAssetPath = AssetDatabase.GetAssetPath(p.Prefab);
     }
 }
Esempio n. 6
0
        private void DrawAddPrototypeGUI()
        {
            EditorGUILayout.GetControlRect(GUILayout.Height(1));
            Rect       r = EditorGUILayout.GetControlRect(GUILayout.Height(GEditorCommon.objectSelectorDragDropHeight));
            GameObject g = GEditorCommon.ObjectSelectorDragDrop <GameObject>(r, "Drop a Game Object here!", "t:GameObject");

            if (g != null)
            {
                GTreePrototype p = GTreePrototype.Create(g);
                instance.Prototypes.Add(p);
            }
        }
Esempio n. 7
0
        private void ConfirmAndRemovePrototypeAtIndex(int index)
        {
            GTreePrototype p     = instance.Prototypes[index];
            string         label = p.Prefab != null ? p.Prefab.name : "Tree " + index;

            if (EditorUtility.DisplayDialog(
                    "Confirm",
                    "Remove " + label,
                    "OK", "Cancel"))
            {
                instance.Prototypes.RemoveAt(index);
            }
        }
        public void Add(GTreePrototype p)
        {
            if (p == null)
            {
                return;
            }
            if (p.Prefab == null)
            {
                return;
            }
            Texture t = AssetPreview.GetAssetPreview(p.Prefab);

            if (t != null)
            {
                Textures.Add(t);
                Colors.Add(Color.white);
            }
        }
Esempio n. 9
0
        private static void RenderTreesInstanced_NonInstanced(GStylizedTerrain t, Camera cam, List <int> flags, List <Vector3> worldPositions)
        {
            List <GTreePrototype> prototypes = t.TerrainData.Foliage.Trees.Prototypes;
            List <GTreeInstance>  instances  = t.TerrainData.Foliage.TreeInstances;
            int instanceCount = instances.Count;
            int subMeshCount  = 0;
            int materialCount = 0;
            int drawCallCount = 0;
            int d;

            for (int i = 0; i < instanceCount; ++i)
            {
                if (flags[i] != FLAG_NON_INSTANCED)
                {
                    continue;
                }
                GTreeInstance  tree  = instances[i];
                GTreePrototype proto = prototypes[tree.PrototypeIndex];
                subMeshCount  = proto.SharedMesh.subMeshCount;
                materialCount = proto.SharedMaterials.Length;
                drawCallCount = Mathf.Min(subMeshCount, materialCount);
                for (d = 0; d < drawCallCount; ++d)
                {
                    Graphics.DrawMesh(
                        proto.SharedMesh,
                        Matrix4x4.TRS(worldPositions[i] + Vector3.up * proto.PivotOffset, tree.Rotation * proto.BaseRotation, tree.Scale.Mul(proto.BaseScale)),
                        proto.SharedMaterials[d],
                        proto.Layer,
                        cam,  //camera
                        d,    //sub mesh index
                        null, //properties block
                        proto.ShadowCastingMode,
                        proto.ReceiveShadow,
                        null,  //probe anchor
                        LightProbeUsage.BlendProbes,
                        null); //proxy volume
                }
            }
        }
        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;
            }

            GameObject actualTarget = null;

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

            if (actualTarget == null)
            {
                return;
            }
            Vector3 terrainSize = new Vector3(
                Terrain.TerrainData.Geometry.Width,
                Terrain.TerrainData.Geometry.Height,
                Terrain.TerrainData.Geometry.Length);
            Vector3 targetLocalPos = Terrain.transform.InverseTransformPoint(actualTarget.transform.position);
            Vector3 treeLocalPos   = Vector3.zero;
            float   sqrDistance    = distance * distance;

            TreeInstances.Clear();
            List <GTreeInstance> instances = Terrain.TerrainData.Foliage.TreeInstances;

            for (int i = 0; i < instances.Count; ++i)
            {
                GTreeInstance tree = instances[i];
                treeLocalPos.Set(
                    tree.Position.x * terrainSize.x,
                    tree.Position.y * terrainSize.y,
                    tree.Position.z * terrainSize.z);
                if (Vector3.SqrMagnitude(targetLocalPos - treeLocalPos) <= sqrDistance)
                {
                    TreeInstances.Add(tree);
                }
            }

            Vector3 targetNormalizePos = Terrain.WorldPointToNormalized(actualTarget.transform.position);

            TreeInstances.Sort((t0, t1) =>
            {
                float d0 = Vector3.SqrMagnitude(targetNormalizePos - t0.Position);
                float d1 = Vector3.SqrMagnitude(targetNormalizePos - t1.Position);
                return(d0.CompareTo(d1));
            });

            List <GTreePrototype> prototypes = Terrain.TerrainData.Foliage.Trees.Prototypes;
            int colliderIndex = 0;

            for (int i = 0; i < TreeInstances.Count; ++i)
            {
                GTreeInstance  tree      = TreeInstances[i];
                GTreePrototype prototype = prototypes[tree.PrototypeIndex];
                if (!prototype.HasCollider)
                {
                    continue;
                }

                if (colliderIndex >= ColliderBudget)
                {
                    break;
                }
                CapsuleCollider col = GetCollider(colliderIndex);
                colliderIndex += 1;

                Vector3 localPos = new Vector3(
                    terrainSize.x * tree.Position.x,
                    terrainSize.y * tree.Position.y,
                    terrainSize.z * tree.Position.z);
                Vector3 worldPos = Terrain.transform.TransformPoint(localPos);
                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;
                col.gameObject.tag   = prototype.Prefab.tag;
                col.gameObject.SetActive(true);
            }

            for (int i = colliderIndex; i < ColliderBudget; ++i)
            {
                CapsuleCollider col = GetCollider(i);
                col.gameObject.SetActive(false);
            }
        }
Esempio n. 11
0
        private static void RenderTreesNonInstanced(GStylizedTerrain t, Camera cam)
        {
            if (t.TerrainData.Foliage.Trees == null ||
                t.TerrainData.Foliage.Trees.Prototypes.Count == 0)
            {
                return;
            }
            List <GTreePrototype> prototypes = t.TerrainData.Foliage.Trees.Prototypes;
            List <GTreeInstance>  instances  = t.TerrainData.Foliage.TreeInstances;
            int prototypeCount = prototypes.Count;
            int instanceCount  = instances.Count;

            bool[] prototypeValidation   = new bool[prototypeCount];
            int[]  prototypeSubMeshCount = new int[prototypeCount];
            for (int pIndex = 0; pIndex < prototypeCount; ++pIndex)
            {
                prototypeValidation[pIndex]   = prototypes[pIndex].IsValid;
                prototypeSubMeshCount[pIndex] = prototypeValidation[pIndex] ? prototypes[pIndex].SharedMesh.subMeshCount : 0;

                if (prototypeValidation[pIndex] == true &&
                    prototypes[pIndex].Billboard != null &&
                    prototypes[pIndex].Billboard.material != null)
                {
                    try
                    {
                        Material mat = prototypes[pIndex].Billboard.material;
                        mat.SetVectorArray(IMAGE_TEXCOORDS_PROPERTY, prototypes[pIndex].Billboard.GetImageTexCoords());
                        mat.SetInt(IMAGE_COUNT_PROPERTY, prototypes[pIndex].Billboard.imageCount);
                    }
                    catch { }
                }
            }

            Quaternion billboardShadowCasterRotation = Quaternion.identity;

            Light[] directionalLights = Light.GetLights(LightType.Directional, 0);
            Light   firstDirLight     = null;

            if (directionalLights.Length > 0)
            {
                firstDirLight = directionalLights[0];
                billboardShadowCasterRotation = Quaternion.Euler(0, firstDirLight.transform.root.eulerAngles.y, 0);
            }

            float   sqrBillboardStart = t.TerrainData.Rendering.BillboardStart * t.TerrainData.Rendering.BillboardStart;
            float   sqrTreeDistance   = t.TerrainData.Rendering.TreeDistance * t.TerrainData.Rendering.TreeDistance;
            float   sqrDistance       = 0;
            Vector3 dimension         = new Vector3(
                t.TerrainData.Geometry.Width,
                t.TerrainData.Geometry.Height,
                t.TerrainData.Geometry.Length);
            Vector3        localPos          = Vector3.zero;
            Vector3        worldPos          = Vector3.zero;
            int            prototypeMaxIndex = prototypeCount - 1;
            GTreePrototype p             = null;
            int            subMeshCount  = 0;
            int            materialCount = 0;
            int            drawCallCount = 0;
            int            i             = 0;
            int            d             = 0;
            Vector3        camLocalPos   = t.transform.InverseTransformPoint(cam.transform.position);

            for (i = 0; i < instanceCount; ++i)
            {
                GTreeInstance tree = instances[i];
                if (tree.PrototypeIndex < 0 || tree.PrototypeIndex > prototypeMaxIndex)
                {
                    continue;
                }
                if (!prototypeValidation[tree.PrototypeIndex])
                {
                    continue;
                }
                localPos.Set(
                    tree.Position.x * dimension.x,
                    tree.Position.y * dimension.y,
                    tree.Position.z * dimension.z);

                sqrDistance = Vector3.SqrMagnitude(localPos - camLocalPos);
                if (sqrDistance > sqrTreeDistance)
                {
                    continue;
                }

                worldPos = t.transform.TransformPoint(localPos);
                p        = prototypes[tree.PrototypeIndex];

                if (sqrDistance < sqrBillboardStart)
                {
                    subMeshCount  = prototypeSubMeshCount[tree.PrototypeIndex];
                    materialCount = p.SharedMaterials.Length;
                    drawCallCount = Mathf.Min(subMeshCount, materialCount);
                    for (d = 0; d < drawCallCount; ++d)
                    {
                        Graphics.DrawMesh(
                            p.SharedMesh,
                            Matrix4x4.TRS(worldPos + Vector3.up * p.PivotOffset, p.BaseRotation * tree.Rotation, tree.Scale.Mul(p.BaseScale)),
                            p.SharedMaterials[d],
                            p.Layer,
                            cam,  //camera
                            d,    //sub mesh index
                            null, //properties block
                            p.ShadowCastingMode,
                            p.ReceiveShadow,
                            null,  //probe anchor
                            LightProbeUsage.BlendProbes,
                            null); //proxy volume
                    }
                }
                else
                {
                    if (p.Billboard == null)
                    {
                        continue;
                    }
                    if (p.Billboard.material == null)
                    {
                        continue;
                    }
                    Vector3 lookDir = cam.transform.position - worldPos;
                    lookDir.y = 0;
                    Quaternion rotation      = Quaternion.LookRotation(-lookDir, Vector3.up);
                    Mesh       billboardMesh = ResourceManager.GetBillboardMesh(p.Billboard);
                    Graphics.DrawMesh(
                        billboardMesh,
                        Matrix4x4.TRS(worldPos + Vector3.up * p.PivotOffset, rotation, tree.Scale),
                        p.Billboard.material,
                        p.Layer,
                        cam,   //camera
                        0,     //sub mesh index
                        null,  //properties block
                        ShadowCastingMode.Off,
                        false, //receive shadow
                        null,  //probe anchor
                        LightProbeUsage.BlendProbes,
                        null); //proxy volume

                    if (p.ShadowCastingMode == ShadowCastingMode.Off)
                    {
                        continue;
                    }
                    if (firstDirLight == null)
                    {
                        continue;
                    }

                    Graphics.DrawMesh(
                        billboardMesh,
                        Matrix4x4.TRS(worldPos + Vector3.up * p.PivotOffset, billboardShadowCasterRotation, tree.Scale),
                        p.Billboard.material,
                        p.Layer,
                        cam,   //camera
                        0,     //sub mesh index
                        null,  //properties block
                        ShadowCastingMode.ShadowsOnly,
                        false, //receive shadow
                        null,  //probe anchor
                        LightProbeUsage.Off,
                        null); //proxy volume
                }
            }
        }
Esempio n. 12
0
        private static void RenderTreesInstanced_NonInstancedBillboard(GStylizedTerrain t, Camera cam, List <int> flags, List <Vector3> worldPositions)
        {
            List <GTreePrototype> prototypes = t.TerrainData.Foliage.Trees.Prototypes;
            List <GTreeInstance>  instances  = t.TerrainData.Foliage.TreeInstances;
            int instanceCount = instances.Count;

            Light[] directionalLights = Light.GetLights(LightType.Directional, 0);
            Light   firstDirLight     = null;

            if (directionalLights.Length > 0)
            {
                firstDirLight = directionalLights[0];
            }
            Quaternion billboardShadowCasterRotation = Quaternion.Euler(0, firstDirLight.transform.root.eulerAngles.y, 0);

            for (int i = 0; i < instanceCount; ++i)
            {
                if (flags[i] != FLAG_NON_INSTANCED_BILLBOARD)
                {
                    continue;
                }
                GTreeInstance  tree  = instances[i];
                GTreePrototype proto = prototypes[tree.PrototypeIndex];

                Vector3 lookDir = cam.transform.position - worldPositions[i];
                lookDir.y = 0;
                Quaternion rotation      = Quaternion.LookRotation(-lookDir, Vector3.up);
                Mesh       billboardMesh = ResourceManager.GetBillboardMesh(proto.Billboard);
                Graphics.DrawMesh(
                    billboardMesh,
                    Matrix4x4.TRS(worldPositions[i] + Vector3.up * proto.PivotOffset, rotation, instances[i].Scale),
                    proto.Billboard.material,
                    proto.Layer,
                    cam,   //camera
                    0,     //sub mesh index
                    null,  //properties block
                    ShadowCastingMode.Off,
                    false, //receive shadow
                    null,  //probe anchor
                    LightProbeUsage.BlendProbes,
                    null); //proxy volume

                if (proto.ShadowCastingMode == ShadowCastingMode.Off)
                {
                    continue;
                }
                if (firstDirLight == null)
                {
                    continue;
                }

                Graphics.DrawMesh(
                    billboardMesh,
                    Matrix4x4.TRS(worldPositions[i], billboardShadowCasterRotation, instances[i].Scale),
                    proto.Billboard.material,
                    proto.Layer,
                    cam,   //camera
                    0,     //sub mesh index
                    null,  //properties block
                    ShadowCastingMode.ShadowsOnly,
                    false, //receive shadow
                    null,  //probe anchor
                    LightProbeUsage.Off,
                    null); //proxy volume
            }
        }
Esempio n. 13
0
        private static void PreprocessRendering(GStylizedTerrain t, Camera cam, List <int> flags, List <Vector3> worldPositions)
        {
            flags.Clear();
            worldPositions.Clear();

            List <GTreePrototype> prototypes = t.TerrainData.Foliage.Trees.Prototypes;
            List <GTreeInstance>  instances  = t.TerrainData.Foliage.TreeInstances;
            int prototypeCount = prototypes.Count;
            int instanceCount  = instances.Count;

            bool[] prototypeValidation = new bool[prototypeCount];
            for (int pIndex = 0; pIndex < prototypeCount; ++pIndex)
            {
                prototypeValidation[pIndex] = prototypes[pIndex].IsValid;
            }

            float   sqrTreeDistance      = t.TerrainData.Rendering.TreeDistance * t.TerrainData.Rendering.TreeDistance;
            float   sqrBillboardDistance = t.TerrainData.Rendering.BillboardStart * t.TerrainData.Rendering.BillboardStart;
            float   sqrDistance          = 0;
            Bounds  bound       = new Bounds();
            Vector3 boundSize   = Vector3.zero;
            Vector3 boundCenter = Vector3.zero;
            Vector3 dimension   = new Vector3(
                t.TerrainData.Geometry.Width,
                t.TerrainData.Geometry.Height,
                t.TerrainData.Geometry.Length);
            Vector3 localPos = Vector3.zero;
            Vector3 worldPos = Vector3.zero;
            bool    isInstancingEnabledForAllSharedMaterials = true;

            frustumPlanes = GeometryUtility.CalculateFrustumPlanes(cam);

            for (int i = 0; i < instanceCount; ++i)
            {
                GTreeInstance tree = instances[i];
                //invalid prototype index
                if (tree.PrototypeIndex < 0 || tree.PrototypeIndex >= prototypeCount)
                {
                    flags.Add(FLAG_CULLED);
                    worldPositions.Add(Vector3.zero);
                    continue;
                }

                if (prototypeValidation[tree.PrototypeIndex] == false)
                {
                    flags.Add(FLAG_CULLED);
                    worldPositions.Add(Vector3.zero);
                    continue;
                }

                GTreePrototype proto = prototypes[tree.PrototypeIndex];
                //cull layer
                if (cam.cullingMask >= 0 && (cam.cullingMask & (1 << proto.Layer)) == 0)
                {
                    flags.Add(FLAG_CULLED);
                    worldPositions.Add(Vector3.zero);
                    continue;
                }

                localPos.Set(
                    dimension.x * tree.Position.x,
                    dimension.y * tree.Position.y,
                    dimension.z * tree.Position.z);
                worldPos    = t.transform.TransformPoint(localPos);
                sqrDistance = Vector3.SqrMagnitude(worldPos - cam.transform.position);

                //cull distance
                if (sqrDistance > sqrTreeDistance)
                {
                    flags.Add(FLAG_CULLED);
                    worldPositions.Add(Vector3.zero);
                    continue;
                }

                //cull frustum
                boundSize.Set(
                    proto.SharedMesh.bounds.size.x * tree.Scale.x,
                    proto.SharedMesh.bounds.size.y * tree.Scale.y,
                    proto.SharedMesh.bounds.size.z * tree.Scale.z);
                boundCenter  = worldPos;
                bound.size   = boundSize;
                bound.center = boundCenter;

                if (!GeometryUtility.TestPlanesAABB(frustumPlanes, bound))
                {
                    flags.Add(FLAG_CULLED);
                    worldPositions.Add(Vector3.zero);
                    continue;
                }

                //cull no billboard
                if (sqrDistance >= sqrBillboardDistance &&
                    (proto.Billboard == null || proto.Billboard.material == null))
                {
                    flags.Add(FLAG_CULLED);
                    worldPositions.Add(Vector3.zero);
                    continue;
                }

                //the object will be rendered
                worldPositions.Add(worldPos);

                //determine render mode
                if (sqrDistance >= sqrBillboardDistance)
                {
                    if (proto.Billboard.material.enableInstancing)
                    {
                        flags.Add(FLAG_INSTANCED_BILLBOARD);
                    }
                    else
                    {
                        flags.Add(FLAG_NON_INSTANCED_BILLBOARD);
                    }
                }
                else
                {
                    isInstancingEnabledForAllSharedMaterials = true;
                    for (int mIndex = 0; mIndex < proto.SharedMaterials.Length; ++mIndex)
                    {
                        if (!proto.SharedMaterials[mIndex].enableInstancing)
                        {
                            isInstancingEnabledForAllSharedMaterials = false;
                            break;
                        }
                    }

                    if (isInstancingEnabledForAllSharedMaterials)
                    {
                        flags.Add(FLAG_INSTANCED);
                    }
                    else
                    {
                        flags.Add(FLAG_NON_INSTANCED);
                    }
                }
            }
        }