public static void DrawGPUInstancerPrototypeInfo(GPUInstancerPrototype selectedPrototype, UnityAction <string> DrawHelpText, UnityEngine.Object component, UnityAction OnEditorDataChanged,
                                                         GPUInstancerShaderBindings shaderBindings, GPUInstancerEditorSimulator simulator, GPUInstancerTerrainSettings terrainSettings, int detailLayer)
        {
            GPUInstancerDetailPrototype prototype = (GPUInstancerDetailPrototype)selectedPrototype;

            EditorGUILayout.BeginVertical(GPUInstancerEditorConstants.Styles.box);
            GPUInstancerEditorConstants.DrawCustomLabel(GPUInstancerEditorConstants.TEXT_detailProperties, GPUInstancerEditorConstants.Styles.boldLabel);

            EditorGUI.BeginChangeCheck();

            prototype.detailDensity = EditorGUILayout.Slider(GPUInstancerEditorConstants.TEXT_detailDensity, prototype.detailDensity, 0.0f, terrainSettings.detailDensity);
            DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_detailDensity);
            prototype.detailScale = EditorGUILayout.Vector4Field(GPUInstancerEditorConstants.TEXT_detailScale, prototype.detailScale);
            DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_detailScale);

            prototype.noiseSpread = EditorGUILayout.FloatField(GPUInstancerEditorConstants.TEXT_noiseSpread, prototype.noiseSpread);
            DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_noiseSpread);

            prototype.useCustomHealthyDryNoiseTexture = EditorGUILayout.Toggle(GPUInstancerEditorConstants.TEXT_useCustomHealthyDryNoiseTexture, prototype.useCustomHealthyDryNoiseTexture);
            DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_useCustomHealthyDryNoiseTexture);
            if (prototype.useCustomHealthyDryNoiseTexture)
            {
                prototype.healthyDryNoiseTexture = (Texture2D)EditorGUILayout.ObjectField(GPUInstancerEditorConstants.TEXT_healthyDryNoiseTexture, prototype.healthyDryNoiseTexture, typeof(Texture2D), false);
                DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_healthyDryNoiseTexture);
            }

            if (EditorGUI.EndChangeCheck())
            {
                Undo.RecordObject(component, "Editor data changed.");
                if (OnEditorDataChanged != null)
                {
                    OnEditorDataChanged();
                }
                EditorUtility.SetDirty(prototype);
            }

            EditorGUI.BeginChangeCheck();
            if (!prototype.usePrototypeMesh)
            {
                prototype.useCustomMaterialForTextureDetail = EditorGUILayout.Toggle(GPUInstancerEditorConstants.TEXT_useCustomMaterialForTextureDetail, prototype.useCustomMaterialForTextureDetail);
                DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_useCustomMaterialForTextureDetail);
                if (prototype.useCustomMaterialForTextureDetail)
                {
                    prototype.textureDetailCustomMaterial = (Material)EditorGUILayout.ObjectField(GPUInstancerEditorConstants.TEXT_textureDetailCustomMaterial, prototype.textureDetailCustomMaterial, typeof(Material), false);
                    DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_textureDetailCustomMaterial);
                    prototype.isBillboard = false;
                }
                else
                {
                    prototype.textureDetailCustomMaterial = null;
                }
            }

            EditorGUILayout.EndVertical();

            if (!prototype.usePrototypeMesh && !prototype.isBillboard)
            {
                EditorGUILayout.BeginVertical(GPUInstancerEditorConstants.Styles.box);
                GPUInstancerEditorConstants.DrawCustomLabel(GPUInstancerEditorConstants.TEXT_crossQuads, GPUInstancerEditorConstants.Styles.boldLabel);

                prototype.useCrossQuads = EditorGUILayout.Toggle(GPUInstancerEditorConstants.TEXT_crossQuads, prototype.useCrossQuads);
                DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_crossQuads);

                if (prototype.useCrossQuads)
                {
                    prototype.quadCount = EditorGUILayout.IntSlider(GPUInstancerEditorConstants.TEXT_quadCount, prototype.quadCount, 2, 4);
                    DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_quadCount);

                    if (!prototype.useCustomMaterialForTextureDetail)
                    {
                        prototype.billboardDistance = EditorGUILayout.Slider(GPUInstancerEditorConstants.TEXT_billboardDistance, prototype.billboardDistance, 0.5f, 1f);
                        DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_billboardDistance);
                        prototype.billboardDistanceDebug = EditorGUILayout.Toggle(GPUInstancerEditorConstants.TEXT_billboardDistanceDebug, prototype.billboardDistanceDebug);
                        DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_billboardDistanceDebug);
                        if (prototype.billboardDistanceDebug)
                        {
                            prototype.billboardDistanceDebugColor = EditorGUILayout.ColorField(GPUInstancerEditorConstants.TEXT_billboardDistanceDebugColor, prototype.billboardDistanceDebugColor);
                            DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_billboardDistanceDebugColor);
                        }
                        prototype.billboardFaceCamPos = EditorGUILayout.Toggle(GPUInstancerEditorConstants.TEXT_CQBillboardFaceCamPos, prototype.billboardFaceCamPos);
                        DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_CQBillboardFaceCamPos);
                    }
                }
                else
                {
                    prototype.quadCount = 1;
                }

                EditorGUILayout.EndVertical();
            }
            else
            {
                prototype.useCrossQuads = false;
            }

            if (EditorGUI.EndChangeCheck())
            {
                if (!prototype.usePrototypeMesh && prototype.useCustomMaterialForTextureDetail && prototype.textureDetailCustomMaterial != null)
                {
                    if (!shaderBindings.IsShadersInstancedVersionExists(prototype.textureDetailCustomMaterial.shader.name))
                    {
                        Shader instancedShader;
                        if (GPUInstancerUtility.IsShaderInstanced(prototype.textureDetailCustomMaterial.shader))
                        {
                            instancedShader = prototype.textureDetailCustomMaterial.shader;
                        }
                        else
                        {
                            instancedShader = GPUInstancerUtility.CreateInstancedShader(prototype.textureDetailCustomMaterial.shader, shaderBindings);
                        }

                        if (instancedShader != null)
                        {
                            shaderBindings.AddShaderInstance(prototype.textureDetailCustomMaterial.shader.name, instancedShader);
                        }
                        else
                        {
                            Debug.LogWarning("Can not create instanced version for shader: " + prototype.textureDetailCustomMaterial.shader.name + ". Standard Shader will be used instead.");
                        }
                    }
                }
                EditorUtility.SetDirty(prototype);
            }

            if (!prototype.usePrototypeMesh && !prototype.useCustomMaterialForTextureDetail)
            {
                EditorGUILayout.BeginVertical(GPUInstancerEditorConstants.Styles.box);
                GPUInstancerEditorConstants.DrawCustomLabel(GPUInstancerEditorConstants.TEXT_foliageShaderProperties, GPUInstancerEditorConstants.Styles.boldLabel);

                EditorGUI.BeginChangeCheck();
                prototype.isBillboard = EditorGUILayout.Toggle(GPUInstancerEditorConstants.TEXT_isBillboard, prototype.isBillboard);
                DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_isBillboard);

                if (prototype.isBillboard)
                {
                    prototype.billboardFaceCamPos = EditorGUILayout.Toggle(GPUInstancerEditorConstants.TEXT_billboardFaceCamPos, prototype.billboardFaceCamPos);
                    DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_billboardFaceCamPos);
                }

                if (EditorGUI.EndChangeCheck())
                {
                    EditorUtility.SetDirty(prototype);
                    if (simulator != null && simulator.simulateAtEditor && !simulator.initializingInstances)
                    {
                        GPUInstancerUtility.UpdateDetailInstanceRuntimeDataList(simulator.gpuiManager.runtimeDataList, terrainSettings, false, detailLayer);
                    }
                }

                EditorGUI.BeginChangeCheck();

                prototype.detailHealthyColor = EditorGUILayout.ColorField(GPUInstancerEditorConstants.TEXT_detailHealthyColor, prototype.detailHealthyColor);
                DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_detailHealthyColor);
                prototype.detailDryColor = EditorGUILayout.ColorField(GPUInstancerEditorConstants.TEXT_detailDryColor, prototype.detailDryColor);
                DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_detailDryColor);

                if (EditorGUI.EndChangeCheck())
                {
                    Undo.RecordObject(component, "Editor data changed.");
                    if (OnEditorDataChanged != null)
                    {
                        OnEditorDataChanged();
                    }
                    if (simulator != null && simulator.simulateAtEditor && !simulator.initializingInstances)
                    {
                        GPUInstancerUtility.UpdateDetailInstanceRuntimeDataList(simulator.gpuiManager.runtimeDataList, terrainSettings, false, detailLayer);
                    }
                    EditorUtility.SetDirty(prototype);
                }

                EditorGUI.BeginChangeCheck();

                prototype.ambientOcclusion = EditorGUILayout.Slider(GPUInstancerEditorConstants.TEXT_ambientOcclusion, prototype.ambientOcclusion, 0f, 1f);
                DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_ambientOcclusion);
                prototype.gradientPower = EditorGUILayout.Slider(GPUInstancerEditorConstants.TEXT_gradientPower, prototype.gradientPower, 0f, 1f);
                DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_gradientPower);

                GPUInstancerEditorConstants.DrawCustomLabel(GPUInstancerEditorConstants.TEXT_windSettings, GPUInstancerEditorConstants.Styles.boldLabel);

                prototype.windIdleSway = EditorGUILayout.Slider(GPUInstancerEditorConstants.TEXT_windIdleSway, prototype.windIdleSway, 0f, 1f);
                DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_windIdleSway);
                prototype.windWavesOn = EditorGUILayout.Toggle(GPUInstancerEditorConstants.TEXT_windWavesOn, prototype.windWavesOn);
                DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_windWavesOn);
                if (prototype.windWavesOn)
                {
                    prototype.windWaveTintColor = EditorGUILayout.ColorField(GPUInstancerEditorConstants.TEXT_windWaveTintColor, prototype.windWaveTintColor);
                    DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_windWaveTintColor);
                    prototype.windWaveSize = EditorGUILayout.Slider(GPUInstancerEditorConstants.TEXT_windWaveSize, prototype.windWaveSize, 0f, 1f);
                    DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_windWaveSize);
                    prototype.windWaveTint = EditorGUILayout.Slider(GPUInstancerEditorConstants.TEXT_windWaveTint, prototype.windWaveTint, 0f, 1f);
                    DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_windWaveTint);
                    prototype.windWaveSway = EditorGUILayout.Slider(GPUInstancerEditorConstants.TEXT_windWaveSway, prototype.windWaveSway, 0f, 1f);
                    DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_windWaveSway);
                }
                if (EditorGUI.EndChangeCheck())
                {
                    EditorUtility.SetDirty(prototype);
                    if (simulator != null && simulator.simulateAtEditor && !simulator.initializingInstances)
                    {
                        GPUInstancerUtility.UpdateDetailInstanceRuntimeDataList(simulator.gpuiManager.runtimeDataList, terrainSettings, false, detailLayer);
                    }
                }
                EditorGUILayout.EndVertical();
            }
        }
Exemplo n.º 2
0
        public IEnumerator ReplaceUnityTrees()
        {
            TreeInstance[] treeInstances = terrain.terrainData.treeInstances;
            int            instanceTotal = treeInstances.Length;

            if (instanceTotal > 0)
            {
                Vector3 terrainSize     = terrain.terrainData.size;
                Vector3 terrainPosition = terrain.GetPosition();

                Vector3      treePos = Vector3.zero;
                TreeInstance treeInstance;

                Vector4[] treeScales = new Vector4[prototypeList.Count];
                int       count      = 0;
                foreach (GPUInstancerTreePrototype tp in prototypeList)
                {
                    treeScales[count] = tp.prefabObject.transform.localScale;
                    count++;
                }

                terrain.treeDistance = 0f;                                 // will not persist if called at runtime.

                Vector4[] treeDataArray  = new Vector4[instanceTotal * 2]; // prototypeIndex - positionx3 - rotation - scalex2
                int[]     instanceCounts = new int[terrain.terrainData.treePrototypes.Length];

                int index = 0;
                for (int i = 0; i < instanceTotal; i++)
                {
                    treeInstance = treeInstances[i];
                    treePos      = treeInstance.position;

                    treeDataArray[index].x = treeInstance.prototypeIndex;
                    treeDataArray[index].y = treePos.x;
                    treeDataArray[index].z = treePos.y;
                    treeDataArray[index].w = treePos.z;
                    index++;
                    treeDataArray[index].x = treeInstance.rotation;
                    treeDataArray[index].y = treeInstance.widthScale;
                    treeDataArray[index].z = treeInstance.heightScale;
                    index++;

                    instanceCounts[treeInstance.prototypeIndex]++;
                }
                yield return(null);

                ComputeBuffer treeDataBuffer = new ComputeBuffer(treeDataArray.Length, GPUInstancerConstants.STRIDE_SIZE_FLOAT4);
                treeDataBuffer.SetData(treeDataArray);
                ComputeBuffer treeScalesBuffer = new ComputeBuffer(treeScales.Length, GPUInstancerConstants.STRIDE_SIZE_FLOAT4);
                treeScalesBuffer.SetData(treeScales);
                ComputeBuffer counterBuffer    = new ComputeBuffer(1, GPUInstancerConstants.STRIDE_SIZE_INT);
                uint[]        emptyCounterData = new uint[1];

                GPUInstancerRuntimeData runtimeData;
                for (int i = 0; i < runtimeDataList.Count; i++)
                {
                    if (instanceCounts[i] == 0)
                    {
                        continue;
                    }

                    runtimeData = runtimeDataList[i];

                    counterBuffer.SetData(emptyCounterData);
                    runtimeData.transformationMatrixVisibilityBuffer = new ComputeBuffer(instanceCounts[i], GPUInstancerConstants.STRIDE_SIZE_MATRIX4X4);

                    _treeInstantiationComputeShader.SetBuffer(0,
                                                              GPUInstancerConstants.VisibilityKernelPoperties.INSTANCE_DATA_BUFFER, runtimeData.transformationMatrixVisibilityBuffer);
                    _treeInstantiationComputeShader.SetBuffer(0,
                                                              GPUInstancerConstants.TreeKernelProperties.TREE_DATA, treeDataBuffer);
                    _treeInstantiationComputeShader.SetBuffer(0,
                                                              GPUInstancerConstants.TreeKernelProperties.TREE_SCALES, treeScalesBuffer);
                    _treeInstantiationComputeShader.SetBuffer(0,
                                                              GPUInstancerConstants.GrassKernelProperties.COUNTER_BUFFER, counterBuffer);
                    _treeInstantiationComputeShader.SetInt(
                        GPUInstancerConstants.VisibilityKernelPoperties.BUFFER_PARAMETER_BUFFER_SIZE, instanceTotal);
                    _treeInstantiationComputeShader.SetVector(
                        GPUInstancerConstants.GrassKernelProperties.TERRAIN_SIZE_DATA, terrainSize);
                    _treeInstantiationComputeShader.SetVector(
                        GPUInstancerConstants.TreeKernelProperties.TERRAIN_POSITION, terrainPosition);
                    _treeInstantiationComputeShader.SetBool(
                        GPUInstancerConstants.TreeKernelProperties.IS_APPLY_ROTATION, ((GPUInstancerTreePrototype)runtimeData.prototype).isApplyRotation);
                    _treeInstantiationComputeShader.SetInt(
                        GPUInstancerConstants.TreeKernelProperties.PROTOTYPE_INDEX, i);

                    _treeInstantiationComputeShader.Dispatch(0,
                                                             Mathf.CeilToInt(instanceTotal / GPUInstancerConstants.VISIBILITY_SHADER_THREAD_COUNT), 1, 1);

                    runtimeData.bufferSize    = instanceCounts[i];
                    runtimeData.instanceCount = instanceCounts[i];
                    GPUInstancerUtility.InitializeGPUBuffer(runtimeData);

                    yield return(null);
                }

                treeDataBuffer.Release();
                treeScalesBuffer.Release();
                counterBuffer.Release();
            }

            isInitial = true;
            GPUInstancerUtility.TriggerEvent(GPUInstancerEventType.TreeInitializationFinished);
        }
Exemplo n.º 3
0
 /// <summary>
 ///     <para>Stops listening the specified process and unregisters the given callback function that was registered with <see cref="StartListeningGPUIEvent"/>.</para>
 ///     <para>Use this in your callback function to unregister it (e.g. after hiding the loading bar).</para>
 ///     <para>For an example, see: <seealso cref="DetailDemoSceneController"/></para>
 /// </summary>
 /// <param name="eventType">The event type that was registered with <see cref="StartListeningGPUIEvent"/></param>
 /// <param name="callback">The callback function that was registered with <see cref="StartListeningGPUIEvent"/></param>
 public static void StopListeningGPUIEvent(GPUInstancerEventType eventType, UnityAction callback)
 {
     GPUInstancerUtility.StopListening(eventType, callback);
 }
Exemplo n.º 4
0
 /// <summary>
 /// Updates all transform values in GPU memory with the given offset position.
 /// </summary>
 /// <param name="manager">GPUI Manager to apply the offset</param>
 /// <param name="offsetPosition">Offset Position</param>
 public static void SetGlobalPositionOffset(GPUInstancerManager manager, Vector3 offsetPosition)
 {
     GPUInstancerUtility.SetGlobalPositionOffset(manager, offsetPosition);
 }
Exemplo n.º 5
0
        public virtual void CheckPrototypeChanges()
        {
            if (GPUInstancerConstants.gpuiSettings == null)
            {
                GPUInstancerConstants.gpuiSettings = GPUInstancerSettings.GetDefaultGPUInstancerSettings();
            }
            GPUInstancerConstants.gpuiSettings.SetDefultBindings();

            if (prototypeList == null)
            {
                GeneratePrototypes();
            }
            else
            {
                prototypeList.RemoveAll(p => p == null);
            }

            if (GPUInstancerConstants.gpuiSettings != null && GPUInstancerConstants.gpuiSettings.shaderBindings != null)
            {
                GPUInstancerConstants.gpuiSettings.shaderBindings.ClearEmptyShaderInstances();
                foreach (GPUInstancerPrototype prototype in prototypeList)
                {
                    if (prototype.prefabObject != null)
                    {
                        GPUInstancerUtility.GenerateInstancedShadersForGameObject(prototype);
                        if (string.IsNullOrEmpty(prototype.warningText))
                        {
                            if (prototype.prefabObject.GetComponentInChildren <MeshRenderer>() == null)
                            {
                                prototype.warningText = "Prefab object does not contain any Mesh Renderers.";
                            }
                        }
                    }
                    else
                    {
                        if (GPUInstancerConstants.gpuiSettings.IsStandardRenderPipeline())
                        {
                            GPUInstancerConstants.gpuiSettings.AddShaderVariantToCollection(GPUInstancerConstants.SHADER_GPUI_FOLIAGE);
                        }
                        else if (GPUInstancerConstants.gpuiSettings.isURP)
                        {
                            if (Shader.Find(GPUInstancerConstants.SHADER_GPUI_FOLIAGE_URP) != null)
                            {
                                GPUInstancerConstants.gpuiSettings.AddShaderVariantToCollection(GPUInstancerConstants.SHADER_GPUI_FOLIAGE_URP);
                            }
                        }
                        else if (GPUInstancerConstants.gpuiSettings.isLWRP)
                        {
                            if (Shader.Find(GPUInstancerConstants.SHADER_GPUI_FOLIAGE_LWRP) != null)
                            {
                                GPUInstancerConstants.gpuiSettings.AddShaderVariantToCollection(GPUInstancerConstants.SHADER_GPUI_FOLIAGE_LWRP);
                            }
                        }
                    }
                }
            }
            if (GPUInstancerConstants.gpuiSettings != null && GPUInstancerConstants.gpuiSettings.billboardAtlasBindings != null)
            {
                GPUInstancerConstants.gpuiSettings.billboardAtlasBindings.ClearEmptyBillboardAtlases();
                //foreach (GPUInstancerPrototype prototype in prototypeList)
                //{
                //    if (prototype.prefabObject != null && prototype.useGeneratedBillboard &&
                //        (prototype.billboard == null || prototype.billboard.albedoAtlasTexture == null || prototype.billboard.normalAtlasTexture == null))
                //        GPUInstancerUtility.GeneratePrototypeBillboard(prototype, billboardAtlasBindings);
                //}
            }
        }
        public virtual void DrawGPUInstancerPrototypeBillboardSettings(GPUInstancerPrototype selectedPrototype,
                                                                       GPUInstancerShaderBindings shaderBindings, GPUInstancerBillboardAtlasBindings billboardAtlasBindings)
        {
            if (selectedPrototype.isBillboardDisabled || (selectedPrototype is GPUInstancerDetailPrototype && !((GPUInstancerDetailPrototype)selectedPrototype).usePrototypeMesh))
            {
                if (selectedPrototype.useGeneratedBillboard)
                {
                    selectedPrototype.useGeneratedBillboard = false;
                }
                if (selectedPrototype.billboard != null)
                {
                    selectedPrototype.billboard = null;
                }
                return;
            }

            if (Event.current.type == EventType.Repaint && !selectedPrototype.checkedForBillboardExtentions)
            {
                selectedPrototype.checkedForBillboardExtentions = true;
                if (CheckForBillboardExtentions(selectedPrototype, billboardAtlasBindings))
                {
                    return;
                }
            }

            EditorGUILayout.BeginVertical(GPUInstancerEditorConstants.Styles.box);

            GPUInstancerEditorConstants.DrawCustomLabel(GPUInstancerEditorConstants.TEXT_billboardSettings, GPUInstancerEditorConstants.Styles.boldLabel);

            selectedPrototype.useGeneratedBillboard = EditorGUILayout.Toggle(GPUInstancerEditorConstants.TEXT_useGeneratedBillboard, selectedPrototype.useGeneratedBillboard);
            DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_useGeneratedBillboard);

            if (selectedPrototype.useGeneratedBillboard && selectedPrototype.billboard == null)
            {
                selectedPrototype.billboard = new GPUInstancerBillboard();
            }
            else if (!selectedPrototype.useGeneratedBillboard && selectedPrototype.billboard != null)
            {
                if (selectedPrototype.billboard.albedoAtlasTexture != null)
                {
                    billboardAtlasBindings.DeleteBillboardTextures(selectedPrototype);
                }
                if (!selectedPrototype.billboard.useCustomBillboard)
                {
                    selectedPrototype.billboard = null;
                }
            }

            if (selectedPrototype.useGeneratedBillboard)
            {
                if (selectedPrototype.treeType != GPUInstancerTreeType.SpeedTree && selectedPrototype.treeType != GPUInstancerTreeType.TreeCreatorTree && selectedPrototype.treeType != GPUInstancerTreeType.SoftOcclusionTree &&
                    !selectedPrototype.billboard.useCustomBillboard)
                {
                    EditorGUILayout.HelpBox(GPUInstancerEditorConstants.HELPTEXT_unsupportedBillboardWarning, MessageType.Warning);
                }

                bool previousUseCustomBillboard = selectedPrototype.billboard.useCustomBillboard;
                selectedPrototype.billboard.useCustomBillboard = EditorGUILayout.Toggle(GPUInstancerEditorConstants.TEXT_useCustomBillboard, selectedPrototype.billboard.useCustomBillboard);
                DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_useCustomBillboard);

                if (selectedPrototype.billboard.useCustomBillboard)
                {
                    selectedPrototype.billboard.customBillboardMesh = (Mesh)EditorGUILayout.ObjectField(GPUInstancerEditorConstants.TEXT_customBillboardMesh,
                                                                                                        selectedPrototype.billboard.customBillboardMesh, typeof(Mesh), false);
                    selectedPrototype.billboard.customBillboardMaterial = (Material)EditorGUILayout.ObjectField(GPUInstancerEditorConstants.TEXT_customBillboardMaterial,
                                                                                                                selectedPrototype.billboard.customBillboardMaterial, typeof(Material), false);
                    selectedPrototype.billboard.isBillboardShadowCasting = EditorGUILayout.Toggle(GPUInstancerEditorConstants.TEXT_isBillboardShadowCasting,
                                                                                                  selectedPrototype.billboard.isBillboardShadowCasting);

                    if (!previousUseCustomBillboard && selectedPrototype.billboard.albedoAtlasTexture != null)
                    {
                        billboardAtlasBindings.DeleteBillboardTextures(selectedPrototype);
                    }


                    if (shaderBindings != null && selectedPrototype.billboard.customBillboardMaterial != null)
                    {
                        if (!shaderBindings.IsShadersInstancedVersionExists(selectedPrototype.billboard.customBillboardMaterial.shader.name))
                        {
                            Shader instancedShader = GPUInstancerUtility.CreateInstancedShader(selectedPrototype.billboard.customBillboardMaterial.shader, shaderBindings);
                            if (instancedShader != null)
                            {
                                shaderBindings.AddShaderInstance(selectedPrototype.billboard.customBillboardMaterial.shader.name, instancedShader);
                            }
                        }
                    }
                }
                else
                {
                    if (selectedPrototype.billboard.customBillboardInLODGroup)
                    {
                        selectedPrototype.billboard.customBillboardInLODGroup = false;
                    }

                    selectedPrototype.billboard.billboardQuality = (BillboardQuality)EditorGUILayout.Popup(GPUInstancerEditorConstants.TEXT_billboardQuality,
                                                                                                           (int)selectedPrototype.billboard.billboardQuality, GPUInstancerEditorConstants.TEXT_BillboardQualityOptions);
                    DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_billboardQuality);

                    switch (selectedPrototype.billboard.billboardQuality)
                    {
                    case BillboardQuality.Low:
                        selectedPrototype.billboard.atlasResolution = 1024;
                        break;

                    case BillboardQuality.Mid:
                        selectedPrototype.billboard.atlasResolution = 2048;
                        break;

                    case BillboardQuality.High:
                        selectedPrototype.billboard.atlasResolution = 4096;
                        break;

                    case BillboardQuality.VeryHigh:
                        selectedPrototype.billboard.atlasResolution = 8192;
                        break;
                    }

                    selectedPrototype.billboard.frameCount = EditorGUILayout.IntSlider(GPUInstancerEditorConstants.TEXT_billboardFrameCount, selectedPrototype.billboard.frameCount, 8, 32);
                    DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_billboardFrameCount);
                    selectedPrototype.billboard.frameCount = Mathf.NextPowerOfTwo(selectedPrototype.billboard.frameCount);

                    selectedPrototype.billboard.billboardBrightness = EditorGUILayout.Slider(GPUInstancerEditorConstants.TEXT_billboardBrightness, selectedPrototype.billboard.billboardBrightness, 0.0f, 1.0f);
                    DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_billboardBrightness);

                    selectedPrototype.billboard.isOverridingOriginalCutoff = EditorGUILayout.Toggle(GPUInstancerEditorConstants.TEXT_overrideOriginalCutoff, selectedPrototype.billboard.isOverridingOriginalCutoff);
                    if (selectedPrototype.billboard.isOverridingOriginalCutoff)
                    {
                        selectedPrototype.billboard.cutoffOverride = EditorGUILayout.Slider(GPUInstancerEditorConstants.TEXT_overrideCutoffAmount, selectedPrototype.billboard.cutoffOverride, 0.01f, 1.0f);
                    }
                    else
                    {
                        selectedPrototype.billboard.cutoffOverride = -1f;
                    }
                    DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_overrideOriginalCutoff);
                }

                if (!selectedPrototype.billboard.customBillboardInLODGroup)
                {
                    bool hasLODGroup        = selectedPrototype.prefabObject.GetComponent <LODGroup>() != null;
                    bool speedTreeBillboard = selectedPrototype.treeType == GPUInstancerTreeType.SpeedTree && hasLODGroup &&
                                              selectedPrototype.prefabObject.GetComponentInChildren <BillboardRenderer>() != null;
                    if (hasLODGroup && !speedTreeBillboard)
                    {
                        selectedPrototype.billboard.replaceLODCullWithBillboard = EditorGUILayout.Toggle(GPUInstancerEditorConstants.TEXT_replaceLODCull, selectedPrototype.billboard.replaceLODCullWithBillboard);
                        DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_replaceLODCull);
                    }
                    if ((!hasLODGroup || !selectedPrototype.billboard.replaceLODCullWithBillboard) && !speedTreeBillboard)
                    {
                        selectedPrototype.billboard.billboardDistance = EditorGUILayout.Slider(GPUInstancerEditorConstants.TEXT_generatedBillboardDistance, selectedPrototype.billboard.billboardDistance, 0.01f, 1f);
                        DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_generatedBillboardDistance);
                    }
                }

                if (!selectedPrototype.billboard.useCustomBillboard)
                {
                    selectedPrototype.billboard.billboardFaceCamPos = EditorGUILayout.Toggle(GPUInstancerEditorConstants.TEXT_billboardFaceCamPos, selectedPrototype.billboard.billboardFaceCamPos);
                    DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_billboardFaceCamPos);

                    if (selectedPrototype.billboard.albedoAtlasTexture == null)
                    {
                        GPUInstancerUtility.AssignBillboardBinding(selectedPrototype, billboardAtlasBindings);
                    }

                    EditorGUI.BeginDisabledGroup(true);
                    EditorGUILayout.ObjectField(GPUInstancerEditorConstants.TEXT_billboardAlbedo, selectedPrototype.billboard.albedoAtlasTexture, typeof(GameObject), false);
                    EditorGUILayout.ObjectField(GPUInstancerEditorConstants.TEXT_billboardNormal, selectedPrototype.billboard.normalAtlasTexture, typeof(GameObject), false);
                    EditorGUI.EndDisabledGroup();
                }

                GUILayout.Space(10);

                EditorGUILayout.BeginHorizontal();

                if (!selectedPrototype.billboard.useCustomBillboard)
                {
                    GPUInstancerEditorConstants.DrawColoredButton(selectedPrototype.billboard.albedoAtlasTexture == null ?
                                                                  GPUInstancerEditorConstants.Contents.generateBillboard : GPUInstancerEditorConstants.Contents.regenerateBillboard,
                                                                  GPUInstancerEditorConstants.Colors.green, Color.white, FontStyle.Bold, Rect.zero,
                                                                  () =>
                    {
                        GPUInstancerUtility.GeneratePrototypeBillboard(selectedPrototype, billboardAtlasBindings, selectedPrototype.billboard.albedoAtlasTexture != null);
                    });
                }

                if ((!selectedPrototype.billboard.useCustomBillboard && selectedPrototype.billboard.albedoAtlasTexture != null) ||
                    (selectedPrototype.billboard.useCustomBillboard &&
                     selectedPrototype.billboard.customBillboardMesh != null &&
                     selectedPrototype.billboard.customBillboardMaterial != null))
                {
                    GPUInstancerEditorConstants.DrawColoredButton(GPUInstancerEditorConstants.Contents.showBillboard, GPUInstancerEditorConstants.Colors.lightBlue, Color.white, FontStyle.Bold, Rect.zero,
                                                                  () =>
                    {
                        GPUInstancerUtility.ShowBillboardQuad(selectedPrototype, Vector3.zero);
                    });
                }

                EditorGUILayout.EndHorizontal();

                DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_regenerateBillboard);
                DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_showBillboard);
            }

            if (selectedPrototype.useGeneratedBillboard && selectedPrototype.billboard != null && selectedPrototype.billboard.useCustomBillboard && GPUInstancerDefines.billboardExtentions != null && GPUInstancerDefines.billboardExtentions.Count > 0)
            {
                GUILayout.Space(10);

                EditorGUILayout.BeginVertical(GPUInstancerEditorConstants.Styles.box);

                GPUInstancerEditorConstants.DrawCustomLabel("External Billboard Generators", GPUInstancerEditorConstants.Styles.boldLabel);

                GUILayout.Space(5);

                foreach (Extention.GPUInstancerBillboardExtention billboardExtention in GPUInstancerDefines.billboardExtentions)
                {
                    try
                    {
                        EditorGUILayout.BeginHorizontal();
                        GUILayout.Label(billboardExtention.GetTitle(), GPUInstancerEditorConstants.Styles.label);

                        GPUInstancerEditorConstants.DrawColoredButton(new GUIContent(billboardExtention.GetButtonText()), GPUInstancerEditorConstants.Colors.green, Color.white, FontStyle.Bold, Rect.zero,
                                                                      () =>
                        {
                            _redirectObject = billboardExtention.GenerateBillboard(selectedPrototype.prefabObject);
                            selectedPrototype.checkedForBillboardExtentions = false;
                        });
                        EditorGUILayout.EndHorizontal();

                        GUILayout.Space(5);
                    }
                    catch (System.Exception e)
                    {
                        EditorUtility.ClearProgressBar();
                        Debug.LogError("Error generating billboard: " + e.Message + " StackTrace:" + e.StackTrace);
                    }
                }

                EditorGUILayout.EndVertical();
            }

            EditorGUILayout.EndVertical();
        }
        public void DrawGPUInstancerManagerGUILayout()
        {
            int prototypeRowCount = Mathf.FloorToInt((EditorGUIUtility.currentViewWidth - 30f) / PROTOTYPE_RECT_SIZE);

            EditorGUILayout.BeginVertical(GPUInstancerEditorConstants.Styles.box);
            GPUInstancerEditorConstants.DrawCustomLabel(GPUInstancerEditorConstants.TEXT_prototypes, GPUInstancerEditorConstants.Styles.boldLabel);
            DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_prototypes);

            if (!Application.isPlaying)
            {
                GPUInstancerEditorConstants.DrawColoredButton(GPUInstancerEditorConstants.Contents.generatePrototypes, GPUInstancerEditorConstants.Colors.darkBlue, Color.white, FontStyle.Bold, Rect.zero,
                                                              () =>
                {
                    if (EditorUtility.DisplayDialog(GPUInstancerEditorConstants.TEXT_generatePrototypesConfirmation, GPUInstancerEditorConstants.TEXT_generatePrototypeAreYouSure, GPUInstancerEditorConstants.TEXT_generatePrototypes, GPUInstancerEditorConstants.TEXT_cancel))
                    {
                        _treeManager.GeneratePrototypes(true);
                    }
                });
                DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_generatePrototypesTree);

                GPUInstancerEditorConstants.DrawColoredButton(GPUInstancerEditorConstants.Contents.regenerateBillboards, GPUInstancerEditorConstants.Colors.darkBlue, Color.white, FontStyle.Bold, Rect.zero,
                                                              () =>
                {
                    if (EditorUtility.DisplayDialog(GPUInstancerEditorConstants.TEXT_regenerateBillboardsConfirmation, GPUInstancerEditorConstants.TEXT_regenerateBillboardsAreYouSure, GPUInstancerEditorConstants.TEXT_regenerateBillboards, GPUInstancerEditorConstants.TEXT_cancel))
                    {
                        foreach (GPUInstancerPrototype prototype in _treeManager.prototypeList)
                        {
                            if (prototype.useGeneratedBillboard)
                            {
                                GPUInstancerUtility.GeneratePrototypeBillboard(prototype, _treeManager.billboardAtlasBindings, true);
                            }
                        }
                    }
                });
                DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_regenerateBillboards);
            }

            if (prototypeContents == null || prototypeContents.Length != _treeManager.prototypeList.Count)
            {
                GeneratePrototypeContents();
            }

            int i = 0;

            EditorGUILayout.BeginHorizontal();
            foreach (GPUInstancerPrototype prototype in _treeManager.prototypeList)
            {
                if (prototype == null)
                {
                    continue;
                }
                if (i != 0 && i % prototypeRowCount == 0)
                {
                    EditorGUILayout.EndHorizontal();
                    EditorGUILayout.BeginHorizontal();
                }

                DrawGPUInstancerPrototypeButton(prototype, prototypeContents[i]);
                i++;
            }

            if (i != 0 && i % prototypeRowCount == 0)
            {
                EditorGUILayout.EndHorizontal();
                EditorGUILayout.BeginHorizontal();
            }
            if (!Application.isPlaying)
            {
                DrawGPUInstancerPrototypeAddButton();
            }

            EditorGUILayout.EndHorizontal();
            DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_addprototypetree);

            DrawGPUInstancerPrototypeBox(_treeManager.selectedPrototype, prop_isManagerFrustumCulling.boolValue, prop_isManagerOcclusionCulling.boolValue,
                                         _treeManager.shaderBindings, _treeManager.billboardAtlasBindings);

            EditorGUILayout.EndVertical();
        }
Exemplo n.º 8
0
        private static void GetPrefabInstanceCounts()
        {
            GameObject[] prefabInstances = (GameObject[])FindObjectsOfType(typeof(GameObject));
#if UNITY_2018_3_OR_NEWER
            List <GameObject> prefabAssetList = GPUInstancerUtility.GetCorrespondingPrefabAssetsOfGameObjects(prefabInstances);
            foreach (GameObject prefab in prefabAssetList)
            {
                int prefabIndex = prefabList.IndexOf(prefab);
                if (prefabIndex >= 0)
                {
                    instanceCountArray[prefabIndex]++;
                }

                GameObject       prefabContents  = GPUInstancerUtility.LoadPrefabContents(prefab);
                List <Transform> childTransforms = new List <Transform>(prefabContents.GetComponentsInChildren <Transform>());
                childTransforms.Remove(prefabContents.transform);
                foreach (Transform childTransform in childTransforms)
                {
                    GameObject cgo = childTransform.gameObject;
                    if (PrefabUtility.GetPrefabAssetType(cgo) == PrefabAssetType.Regular)
                    {
                        GameObject cprefab = PrefabUtility.GetCorrespondingObjectFromSource(cgo);
                        if (cprefab != null && cprefab.transform.parent == null)
                        {
                            int cprefabIndex = prefabList.IndexOf(cprefab);
                            if (cprefabIndex >= 0)
                            {
                                instanceCountArray[cprefabIndex]++;
                            }
                        }
                    }
                }
                GPUInstancerUtility.UnloadPrefabContents(prefab, prefabContents, false);
            }
#else
            foreach (GameObject go in prefabInstances)
            {
                bool isPrefabInstance = PrefabUtility.GetPrefabType(go) == PrefabType.PrefabInstance;
                if (isPrefabInstance)
                {
#if UNITY_2018_2_OR_NEWER
                    GameObject prefab = (GameObject)PrefabUtility.GetCorrespondingObjectFromSource(go);
#else
                    GameObject prefab = (GameObject)PrefabUtility.GetPrefabParent(go);
#endif
                    int prefabIndex = prefabList.IndexOf(prefab);
                    if (prefabIndex >= 0)
                    {
                        instanceCountArray[prefabIndex]++;
                    }
                }
            }
#endif
            maxInstanceCount = 0;
            for (int i = 0; i < instanceCountArray.Length; i++)
            {
                if (maxInstanceCount < instanceCountArray[i])
                {
                    maxInstanceCount = instanceCountArray[i];
                }
            }
        }
Exemplo n.º 9
0
 /// <summary>
 /// Use this method to update transform data of all prefab instances with a float4x4 native array. By default all the data from the array will be
 /// uploaded to the GPU. You can make partial uploads by setting the arrayStartIndex, bufferStartIndex, and count parameters.
 /// </summary>
 /// <param name="prefabManager">The GPUI Prefab Manager that the prefab prototype is defined on</param>
 /// <param name="prototype">GPUI Prefab Prototype</param>
 /// <param name="float4x4Array">Array of float4x4 that store the transform data of prefab instances. Struct reference is not forced so you can use any float4x4 struct (e.g. Matrix4x4 or float4x4 from Mathematics package)</param>
 /// <param name="arrayStartIndex">(Optional) Start index of the given array that the data will be uploaded to the buffer</param>
 /// <param name="bufferStartIndex">(Optional) Start index of the buffer to set the data from the array</param>
 /// <param name="count">(Optional) Total number of matrices to set to the buffer from the array</param>
 public static void UpdateVisibilityBufferWithNativeArray <T>(GPUInstancerPrefabManager prefabManager, GPUInstancerPrefabPrototype prototype, NativeArray <T> float4x4Array,
                                                              int arrayStartIndex = 0, int bufferStartIndex = 0, int count = 0) where T : struct
 {
     GPUInstancerUtility.UpdateVisibilityBufferWithNativeArray(prefabManager, prototype, float4x4Array, arrayStartIndex, bufferStartIndex, count);
 }
Exemplo n.º 10
0
 /// <summary>
 /// Use this method to update transform data of all prefab instances with a Matrix4x4 array
 /// </summary>
 /// <param name="prefabManager">The GPUI Prefab Manager that the prefab prototype is defined on</param>
 /// <param name="prototype">GPUI Prefab Prototype</param>
 /// <param name="matrix4x4Array">Array of Matrix4x4 that store the transform data of prefab instances</param>
 public static void UpdateVisibilityBufferWithMatrix4x4Array(GPUInstancerPrefabManager prefabManager, GPUInstancerPrefabPrototype prototype, Matrix4x4[] matrix4x4Array)
 {
     GPUInstancerUtility.UpdateVisibilityBufferWithMatrix4x4Array(prefabManager, prototype, matrix4x4Array);
 }
Exemplo n.º 11
0
 /// <summary>
 /// Use this method to initialize buffers for the given prototype and set the buffer data later with UpdateVisibilityBuffer API methods. Please note that you will
 /// need to provide a positive integer buffer size to initialize the buffers successfully.
 /// </summary>
 /// <param name="prefabManager">The GPUI Prefab Manager that the prefab prototype is defined on</param>
 /// <param name="prototype">GPUI Prefab Prototype</param>
 /// <param name="bufferSize">Size of the buffer to allocate in GPU memory</param>
 /// <param name="instanceCount">(Optional) Initial instance count to render. Can also be set later with SetInstanceCount API method</param>
 public static void InitializePrototype(GPUInstancerPrefabManager prefabManager, GPUInstancerPrefabPrototype prototype, int bufferSize, int instanceCount = 0)
 {
     GPUInstancerUtility.InitializePrototype(prefabManager, prototype, bufferSize, instanceCount);
 }
Exemplo n.º 12
0
        public static void SetRenderersEnabled(GPUInstancerPrefabPrototype prefabPrototype, bool enabled)
        {
#if UNITY_2018_3_OR_NEWER
            GameObject prefabContents = GPUInstancerUtility.LoadPrefabContents(prefabPrototype.prefabObject);
#else
            GameObject prefabContents = prefabPrototype.prefabObject;
#endif
            MeshRenderer[] meshRenderers = prefabContents.GetComponentsInChildren <MeshRenderer>(true);
            if (meshRenderers != null && meshRenderers.Length > 0)
            {
                for (int mr = 0; mr < meshRenderers.Length; mr++)
                {
                    meshRenderers[mr].enabled = enabled;
                }
            }

            BillboardRenderer[] billboardRenderers = prefabContents.GetComponentsInChildren <BillboardRenderer>(true);
            if (billboardRenderers != null && billboardRenderers.Length > 0)
            {
                for (int mr = 0; mr < billboardRenderers.Length; mr++)
                {
                    billboardRenderers[mr].enabled = enabled;
                }
            }

            LODGroup lodGroup = prefabContents.GetComponent <LODGroup>();
            if (lodGroup != null)
            {
                lodGroup.enabled = enabled;
            }

            if (prefabPrototype.hasRigidBody)
            {
                Rigidbody rigidbody = prefabContents.GetComponent <Rigidbody>();

                if (enabled || prefabPrototype.autoUpdateTransformData)
                {
                    if (rigidbody == null)
                    {
                        GPUInstancerPrefabPrototype.RigidbodyData rigidbodyData = prefabPrototype.rigidbodyData;
                        if (rigidbodyData != null)
                        {
                            rigidbody                  = prefabPrototype.prefabObject.AddComponent <Rigidbody>();
                            rigidbody.useGravity       = rigidbodyData.useGravity;
                            rigidbody.angularDrag      = rigidbodyData.angularDrag;
                            rigidbody.mass             = rigidbodyData.mass;
                            rigidbody.constraints      = rigidbodyData.constraints;
                            rigidbody.detectCollisions = true;
                            rigidbody.drag             = rigidbodyData.drag;
                            rigidbody.isKinematic      = rigidbodyData.isKinematic;
                            rigidbody.interpolation    = rigidbodyData.interpolation;
                        }
                    }
                }
                else if (rigidbody != null && !prefabPrototype.autoUpdateTransformData)
                {
                    DestroyImmediate(rigidbody, true);
                }
            }

#if UNITY_2018_3_OR_NEWER
            GPUInstancerUtility.UnloadPrefabContents(prefabPrototype.prefabObject, prefabContents, true);
#endif
            EditorUtility.SetDirty(prefabPrototype.prefabObject);
            prefabPrototype.meshRenderersDisabled = !enabled;
            EditorUtility.SetDirty(prefabPrototype);
        }
Exemplo n.º 13
0
        public static void DrawGPUInstancerPrototypeInfo(GPUInstancerPrototype selectedPrototype, UnityAction <string> DrawHelpText)
        {
            EditorGUILayout.BeginVertical(GPUInstancerEditorConstants.Styles.box);
            GPUInstancerEditorConstants.DrawCustomLabel(GPUInstancerEditorConstants.TEXT_prefabRuntimeSettings, GPUInstancerEditorConstants.Styles.boldLabel);

            GPUInstancerPrefabPrototype prototype = (GPUInstancerPrefabPrototype)selectedPrototype;

            prototype.enableRuntimeModifications = EditorGUILayout.Toggle(GPUInstancerEditorConstants.TEXT_enableRuntimeModifications, prototype.enableRuntimeModifications);
            DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_enableRuntimeModifications);

            EditorGUI.BeginDisabledGroup(!prototype.enableRuntimeModifications);

            EditorGUI.BeginDisabledGroup(!prototype.hasRigidBody || prototype.autoUpdateTransformData);
            prototype.startWithRigidBody = EditorGUILayout.Toggle(GPUInstancerEditorConstants.TEXT_startWithRigidBody, prototype.startWithRigidBody);
            DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_startWithRigidBody);
            EditorGUI.EndDisabledGroup();

            prototype.addRemoveInstancesAtRuntime = EditorGUILayout.Toggle(GPUInstancerEditorConstants.TEXT_addRemoveInstancesAtRuntime, prototype.addRemoveInstancesAtRuntime);
            DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_addRemoveInstancesAtRuntime);

            EditorGUI.BeginDisabledGroup(!prototype.addRemoveInstancesAtRuntime);
            prototype.extraBufferSize = EditorGUILayout.IntSlider(GPUInstancerEditorConstants.TEXT_extraBufferSize, prototype.extraBufferSize, 0, GPUInstancerConstants.PREFAB_EXTRA_BUFFER_SIZE);
            DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_extraBufferSize);

            prototype.addRuntimeHandlerScript = EditorGUILayout.Toggle(GPUInstancerEditorConstants.TEXT_addRuntimeHandlerScript, prototype.addRuntimeHandlerScript);
            DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_addRuntimeHandlerScript);

            if (prototype.addRemoveInstancesAtRuntime && !Application.isPlaying)
            {
                GPUInstancerPrefabRuntimeHandler prefabRuntimeHandler = prototype.prefabObject.GetComponent <GPUInstancerPrefabRuntimeHandler>();
                if (prototype.addRuntimeHandlerScript && prefabRuntimeHandler == null)
                {
#if UNITY_2018_3_OR_NEWER
                    GPUInstancerUtility.AddComponentToPrefab <GPUInstancerPrefabRuntimeHandler>(prototype.prefabObject);
#else
                    prototype.prefabObject.AddComponent <GPUInstancerPrefabRuntimeHandler>();
#endif
                    EditorUtility.SetDirty(prototype.prefabObject);
                }
                else if (!prototype.addRuntimeHandlerScript && prefabRuntimeHandler != null)
                {
#if UNITY_2018_3_OR_NEWER
                    GPUInstancerUtility.RemoveComponentFromPrefab <GPUInstancerPrefabRuntimeHandler>(prototype.prefabObject);
#else
                    DestroyImmediate(prefabRuntimeHandler, true);
#endif
                    EditorUtility.SetDirty(prototype.prefabObject);
                }
            }
            EditorGUI.EndDisabledGroup();

            bool autoUpdateTransformData = prototype.autoUpdateTransformData;
            prototype.autoUpdateTransformData = EditorGUILayout.Toggle(GPUInstancerEditorConstants.TEXT_autoUpdateTransformData, prototype.autoUpdateTransformData);
            DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_autoUpdateTransformData);
            if (autoUpdateTransformData != prototype.autoUpdateTransformData && prototype.meshRenderersDisabled)
            {
                SetRenderersEnabled(prototype, !prototype.meshRenderersDisabled);
            }
            EditorGUI.EndDisabledGroup();

            if (!prototype.enableRuntimeModifications)
            {
                if (prototype.addRemoveInstancesAtRuntime)
                {
                    prototype.addRemoveInstancesAtRuntime = false;
                }
                if (prototype.startWithRigidBody)
                {
                    prototype.startWithRigidBody = false;
                }
                if (prototype.autoUpdateTransformData)
                {
                    prototype.autoUpdateTransformData = false;
                    if (prototype.meshRenderersDisabled)
                    {
                        SetRenderersEnabled(prototype, !prototype.meshRenderersDisabled);
                    }
                }
            }

            if ((!prototype.enableRuntimeModifications || !prototype.addRemoveInstancesAtRuntime) && prototype.extraBufferSize > 0)
            {
                prototype.extraBufferSize = 0;
            }

            if ((!prototype.enableRuntimeModifications || !prototype.addRemoveInstancesAtRuntime) && prototype.addRuntimeHandlerScript)
            {
                prototype.addRuntimeHandlerScript = false;
                GPUInstancerPrefabRuntimeHandler prefabRuntimeHandler = prototype.prefabObject.GetComponent <GPUInstancerPrefabRuntimeHandler>();
                if (prefabRuntimeHandler != null)
                {
#if UNITY_2018_3_OR_NEWER
                    GPUInstancerUtility.RemoveComponentFromPrefab <GPUInstancerPrefabRuntimeHandler>(prototype.prefabObject);
#else
                    DestroyImmediate(prefabRuntimeHandler, true);
#endif
                    EditorUtility.SetDirty(prototype.prefabObject);
                }
            }

            EditorGUILayout.EndVertical();
        }
Exemplo n.º 14
0
        public override void AddPickerObject(UnityEngine.Object pickerObject)
        {
            base.AddPickerObject(pickerObject);

            if (pickerObject == null)
            {
                return;
            }

            if (!(pickerObject is GameObject))
            {
                EditorUtility.DisplayDialog(GPUInstancerConstants.TEXT_PREFAB_TYPE_WARNING_TITLE, GPUInstancerConstants.TEXT_TREE_PREFAB_TYPE_WARNING, GPUInstancerConstants.TEXT_OK);
                return;
            }

            GameObject prefabObject = (GameObject)pickerObject;

#if UNITY_2018_3_OR_NEWER
            PrefabAssetType prefabType = PrefabUtility.GetPrefabAssetType(pickerObject);

            if (prefabType == PrefabAssetType.Regular || prefabType == PrefabAssetType.Variant || prefabType == PrefabAssetType.Model)
            {
                GameObject newPrefabObject = (GameObject)PrefabUtility.GetCorrespondingObjectFromSource(prefabObject);
                if (newPrefabObject != null)
                {
                    while (newPrefabObject.transform.parent != null)
                    {
                        newPrefabObject = newPrefabObject.transform.parent.gameObject;
                    }
                    prefabObject = newPrefabObject;
                }
            }
            else
            {
                EditorUtility.DisplayDialog(GPUInstancerConstants.TEXT_PREFAB_TYPE_WARNING_TITLE, GPUInstancerConstants.TEXT_TREE_PREFAB_TYPE_WARNING, GPUInstancerConstants.TEXT_OK);
                return;
            }
#else
            PrefabType prefabType = PrefabUtility.GetPrefabType(pickerObject);

            if (prefabType != PrefabType.Prefab && prefabType != PrefabType.ModelPrefab)
            {
                bool instanceFound = false;
                if (prefabType == PrefabType.PrefabInstance || prefabType == PrefabType.ModelPrefabInstance)
                {
#if UNITY_2018_2_OR_NEWER
                    GameObject newPrefabObject = (GameObject)PrefabUtility.GetCorrespondingObjectFromSource(prefabObject);
#else
                    GameObject newPrefabObject = (GameObject)PrefabUtility.GetPrefabParent(prefabObject);
#endif
                    if (PrefabUtility.GetPrefabType(newPrefabObject) == PrefabType.Prefab || PrefabUtility.GetPrefabType(newPrefabObject) == PrefabType.ModelPrefab)
                    {
                        while (newPrefabObject.transform.parent != null)
                        {
                            newPrefabObject = newPrefabObject.transform.parent.gameObject;
                        }
                        prefabObject  = newPrefabObject;
                        instanceFound = true;
                    }
                }
                if (!instanceFound)
                {
                    EditorUtility.DisplayDialog(GPUInstancerConstants.TEXT_PREFAB_TYPE_WARNING_TITLE, GPUInstancerConstants.TEXT_TREE_PREFAB_TYPE_WARNING, GPUInstancerConstants.TEXT_OK);
                    return;
                }
            }
#endif

            Undo.RecordObject(this, "Add tree prototype");

            if (terrainSettings != null && terrain != null && terrain.terrainData != null)
            {
                List <TreePrototype> newTreePrototypes = new List <TreePrototype>(terrain.terrainData.treePrototypes);

                TreePrototype terrainTreePrototype = new TreePrototype()
                {
                    prefab     = prefabObject,
                    bendFactor = 0
                };
                newTreePrototypes.Add(terrainTreePrototype);

                terrain.terrainData.treePrototypes = newTreePrototypes.ToArray();
                terrain.terrainData.RefreshPrototypes();
                GPUInstancerUtility.AddTreeInstancePrototypeFromTerrainPrototype(gameObject, prototypeList, terrainTreePrototype, newTreePrototypes.Count - 1, shaderBindings, billboardAtlasBindings, terrainSettings);
            }
        }
Exemplo n.º 15
0
 /// <summary>
 /// Use this method to create prefab instances with the given transform information without creating GameObjects.
 /// </summary>
 /// <param name="prefabManager">The GPUI Prefab Manager that the prefab prototype is defined on</param>
 /// <param name="prototype">GPUI Prefab Prototype</param>
 /// <param name="matrix4x4Array">Array of Matrix4x4 that store the transform data of prefab instances</param>
 public static void InitializeWithMatrix4x4Array(GPUInstancerPrefabManager prefabManager, GPUInstancerPrefabPrototype prototype, Matrix4x4[] matrix4x4Array)
 {
     GPUInstancerUtility.InitializeWithMatrix4x4Array(prefabManager, prototype, matrix4x4Array);
 }
Exemplo n.º 16
0
        public virtual void ClearEmptyShaderInstances()
        {
            if (shaderInstances != null)
            {
#if UNITY_EDITOR
                bool modified = false;
                if (shaderBindingsExtensions != null && shaderBindingsExtensions.Count > 0)
                {
                    foreach (GPUInstancerShaderBindingsExtension extension in shaderBindingsExtensions)
                    {
                        modified |= extension.ClearEmptyShaderInstances(shaderInstances);
                    }
                }

                modified |= shaderInstances.RemoveAll(si => si == null || si.instancedShader == null || string.IsNullOrEmpty(si.name)) > 0;
                for (int i = 0; i < shaderInstances.Count; i++)
                {
                    if (shaderInstances[i].isOriginalInstanced || !string.IsNullOrEmpty(shaderInstances[i].extensionCode))
                    {
                        continue;
                    }

                    Shader originalShader = Shader.Find(shaderInstances[i].name);
                    if (!GPUInstancerUtility.IsShaderInstanced(originalShader))
                    {
                        string   originalAssetPath = UnityEditor.AssetDatabase.GetAssetPath(originalShader);
                        DateTime lastWriteTime     = System.IO.File.GetLastWriteTime(originalAssetPath);
                        if (lastWriteTime >= DateTime.Now)
                        {
                            continue;
                        }

                        DateTime instancedTime = DateTime.MinValue;
                        bool     isValidDate   = false;
                        if (!string.IsNullOrEmpty(shaderInstances[i].modifiedDate))
                        {
                            isValidDate = DateTime.TryParseExact(shaderInstances[i].modifiedDate, "MM/dd/yyyy HH:mm:ss.fff", System.Globalization.CultureInfo.InvariantCulture,
                                                                 System.Globalization.DateTimeStyles.None, out instancedTime);
                        }
                        if (!isValidDate || lastWriteTime > Convert.ToDateTime(shaderInstances[i].modifiedDate, System.Globalization.CultureInfo.InvariantCulture))
                        {
                            shaderInstances[i].instancedShader = GPUInstancerUtility.CreateInstancedShader(originalShader);
                            shaderInstances[i].modifiedDate    = DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss.fff",
                                                                                       System.Globalization.CultureInfo.InvariantCulture);
                            modified = true;
                        }
                    }
                    else
                    {
                        shaderInstances[i].isOriginalInstanced = true;
                        modified = true;
                    }
                }

                // remove non unique instances
                List <string> shaderNames = new List <string>();
                foreach (ShaderInstance si in shaderInstances.ToArray())
                {
                    if (shaderNames.Contains(si.name + si.extensionCode))
                    {
                        shaderInstances.Remove(si);
                        modified = true;
                    }
                    else
                    {
                        shaderNames.Add(si.name + si.extensionCode);
                    }
                }

                if (modified)
                {
                    UnityEditor.EditorUtility.SetDirty(this);
                }
#endif
            }
        }
Exemplo n.º 17
0
 /// <summary>
 /// Use this method to update transform data of all prefab instances with a Matrix4x4 array. By default all the data from the array will be
 /// uploaded to the GPU. You can make partial uploads by setting the arrayStartIndex, bufferStartIndex, and count parameters.
 /// </summary>
 /// <param name="prefabManager">The GPUI Prefab Manager that the prefab prototype is defined on</param>
 /// <param name="prototype">GPUI Prefab Prototype</param>
 /// <param name="matrix4x4Array">Array of Matrix4x4 that store the transform data of prefab instances</param>
 /// <param name="arrayStartIndex">Start index of the given array that the data will be uploaded to the buffer</param>
 /// <param name="bufferStartIndex">Start index of the buffer to set the data from the array</param>
 /// <param name="count">Total number of matrices to set to the buffer from the array</param>
 public static void UpdateVisibilityBufferWithMatrix4x4Array(GPUInstancerPrefabManager prefabManager, GPUInstancerPrefabPrototype prototype, Matrix4x4[] matrix4x4Array,
                                                             int arrayStartIndex = 0, int bufferStartIndex = 0, int count = 0)
 {
     GPUInstancerUtility.UpdateVisibilityBufferWithMatrix4x4Array(prefabManager, prototype, matrix4x4Array, arrayStartIndex, bufferStartIndex, count);
 }
Exemplo n.º 18
0
        private GPUInstancerTerrainSettings GenerateTerrainSettings(Terrain terrain, GameObject gameObject)
        {
#if UNITY_EDITOR
            if (!Application.isPlaying)
            {
                string[] guids = AssetDatabase.FindAssets("t:GPUInstancerTerrainSettings");
                string   guid  = GPUInstancerUtility.GetAssetGUID(terrain.terrainData);
                for (int i = 0; i < guids.Length; i++)
                {
                    GPUInstancerTerrainSettings ts = AssetDatabase.LoadAssetAtPath <GPUInstancerTerrainSettings>(AssetDatabase.GUIDToAssetPath(guids[i]));
                    if (ts != null && !string.IsNullOrEmpty(guid) && ts.terrainDataGUID == guid)
                    {
                        prototypeList.Clear();
                        if (this is GPUInstancerDetailManager)
                        {
                            List <GPUInstancerPrototype> detailPrototypeList = new List <GPUInstancerPrototype>();
                            GPUInstancerUtility.SetPrototypeListFromAssets(ts, detailPrototypeList, typeof(GPUInstancerDetailPrototype));
                            for (int p = 0; p < detailPrototypeList.Count; p++)
                            {
                                foreach (GPUInstancerDetailPrototype detailPrototype in detailPrototypeList)
                                {
                                    if (detailPrototype.prototypeIndex == p)
                                    {
                                        prototypeList.Add(detailPrototype);
                                        break;
                                    }
                                }
                            }
                        }
                        if (this is GPUInstancerTreeManager)
                        {
                            List <GPUInstancerPrototype> treePrototypeList = new List <GPUInstancerPrototype>();
                            GPUInstancerUtility.SetPrototypeListFromAssets(ts, treePrototypeList, typeof(GPUInstancerTreePrototype));
                            for (int p = 0; p < treePrototypeList.Count; p++)
                            {
                                foreach (GPUInstancerTreePrototype treePrototype in treePrototypeList)
                                {
                                    if (treePrototype.prototypeIndex == p)
                                    {
                                        prototypeList.Add(treePrototype);
                                        break;
                                    }
                                }
                            }
                        }
                        return(ts);
                    }
                }
            }
#endif

            GPUInstancerTerrainSettings terrainSettings = ScriptableObject.CreateInstance <GPUInstancerTerrainSettings>();
            terrainSettings.name                   = (string.IsNullOrEmpty(terrain.terrainData.name) ? terrain.gameObject.name : terrain.terrainData.name) + "_" + terrain.terrainData.GetInstanceID();
            terrainSettings.terrainDataGUID        = GPUInstancerUtility.GetAssetGUID(terrain.terrainData);
            terrainSettings.maxDetailDistance      = terrain.detailObjectDistance;
            terrainSettings.maxTreeDistance        = terrain.treeDistance;
            terrainSettings.detailDensity          = terrain.detailObjectDensity;
            terrainSettings.healthyDryNoiseTexture = Resources.Load <Texture2D>(GPUInstancerConstants.NOISE_TEXTURES_PATH + GPUInstancerConstants.DEFAULT_HEALTHY_DRY_NOISE);
            terrainSettings.windWaveNormalTexture  = Resources.Load <Texture2D>(GPUInstancerConstants.NOISE_TEXTURES_PATH + GPUInstancerConstants.DEFAULT_WIND_WAVE_NOISE);

#if UNITY_EDITOR
            if (!Application.isPlaying)
            {
                string assetPath = GPUInstancerConstants.GetDefaultPath() + GPUInstancerConstants.PROTOTYPES_TERRAIN_PATH + terrainSettings.name + ".asset";

                // If there is already a file with the same name, change file name
                int counter = 2;
                while (System.IO.File.Exists(assetPath))
                {
                    assetPath = GPUInstancerConstants.GetDefaultPath() + GPUInstancerConstants.PROTOTYPES_TERRAIN_PATH + terrainSettings.name + "_" + counter + ".asset";
                    counter++;
                }

                if (!System.IO.Directory.Exists(GPUInstancerConstants.GetDefaultPath() + GPUInstancerConstants.PROTOTYPES_TERRAIN_PATH))
                {
                    System.IO.Directory.CreateDirectory(GPUInstancerConstants.GetDefaultPath() + GPUInstancerConstants.PROTOTYPES_TERRAIN_PATH);
                }

                AssetDatabase.CreateAsset(terrainSettings, assetPath);

                AssetDatabase.SaveAssets();
                AssetDatabase.Refresh();
            }
#endif
            return(terrainSettings);
        }
Exemplo n.º 19
0
 /// <summary>
 ///     <para>Updates and synchronizes the GPU Instancer detail prototypes with the modifications made in the manager at runtime.</para>
 ///     <para>Use this if you want to make changes to the detail prototypes at runtime. Prototypes in the manager must be modified before using this.</para>
 ///     <para>For example usages, see: <see cref="DetailDemoSceneController"/> and <seealso cref="TerrainGenerator"/></para>
 /// </summary>
 /// <param name="manager">The manager that defines the prototypes you want to GPU instance.</param>
 /// <param name="updateMeshes">Whether GPU Instancer should also update meshes. Send this value as "true" if you change properties
 /// related to cross quadding, noise spread and/or detail scales</param>
 public static void UpdateDetailInstances(GPUInstancerDetailManager manager, bool updateMeshes = false)
 {
     GPUInstancerUtility.UpdateDetailInstanceRuntimeDataList(manager.runtimeDataList, manager.terrainSettings, updateMeshes, manager.detailLayer);
 }
Exemplo n.º 20
0
        public virtual void Awake()
        {
            if (GPUInstancerConstants.gpuiSettings == null)
            {
                GPUInstancerConstants.gpuiSettings = GPUInstancerSettings.GetDefaultGPUInstancerSettings();
            }
            GPUInstancerConstants.gpuiSettings.SetDefultBindings();
            GPUInstancerUtility.SetPlatformDependentVariables();

#if UNITY_EDITOR
            if (!Application.isPlaying)
            {
                CheckPrototypeChanges();
            }
#endif
            if (Application.isPlaying && activeManagerList == null)
            {
                activeManagerList = new List <GPUInstancerManager>();
            }

            if (SystemInfo.supportsComputeShaders)
            {
                if (_visibilityComputeShader == null)
                {
                    switch (GPUInstancerUtility.matrixHandlingType)
                    {
                    case GPUIMatrixHandlingType.MatrixAppend:
                        _visibilityComputeShader = (ComputeShader)Resources.Load(GPUInstancerConstants.VISIBILITY_COMPUTE_RESOURCE_PATH_VULKAN);
                        GPUInstancerConstants.DETAIL_STORE_INSTANCE_DATA = true;
                        GPUInstancerConstants.COMPUTE_MAX_LOD_BUFFER     = 3;
                        break;

                    case GPUIMatrixHandlingType.CopyToTexture:
                        _visibilityComputeShader        = (ComputeShader)Resources.Load(GPUInstancerConstants.VISIBILITY_COMPUTE_RESOURCE_PATH);
                        _bufferToTextureComputeShader   = (ComputeShader)Resources.Load(GPUInstancerConstants.BUFFER_TO_TEXTURE_COMPUTE_RESOURCE_PATH);
                        _bufferToTextureComputeKernelID = _bufferToTextureComputeShader.FindKernel(GPUInstancerConstants.BUFFER_TO_TEXTURE_KERNEL);
                        break;

                    default:
                        _visibilityComputeShader = (ComputeShader)Resources.Load(GPUInstancerConstants.VISIBILITY_COMPUTE_RESOURCE_PATH);
                        break;
                    }

                    _instanceVisibilityComputeKernelIDs = new int[GPUInstancerConstants.VISIBILITY_COMPUTE_KERNELS.Length];
                    for (int i = 0; i < _instanceVisibilityComputeKernelIDs.Length; i++)
                    {
                        _instanceVisibilityComputeKernelIDs[i] = _visibilityComputeShader.FindKernel(GPUInstancerConstants.VISIBILITY_COMPUTE_KERNELS[i]);
                    }
                    GPUInstancerConstants.TEXTURE_MAX_SIZE = SystemInfo.maxTextureSize;

                    _cameraComputeShader = (ComputeShader)Resources.Load(GPUInstancerConstants.CAMERA_COMPUTE_RESOURCE_PATH);
#if UNITY_2017_2_OR_NEWER
                    if (isOcclusionCulling && UnityEngine.XR.XRSettings.enabled && GPUInstancerConstants.gpuiSettings.testBothEyesForVROcclusion)
#else
                    if (isOcclusionCulling && UnityEngine.VR.VRSettings.enabled && GPUInstancerConstants.gpuiSettings.testBothEyesForVROcclusion)
#endif
                    {
                        _cameraComputeShader = (ComputeShader)Resources.Load(GPUInstancerConstants.CAMERA_VR_COMPUTE_RESOURCE_PATH);
                    }
                    _cameraComputeKernelIDs = new int[GPUInstancerConstants.CAMERA_COMPUTE_KERNELS.Length];
                    for (int i = 0; i < _cameraComputeKernelIDs.Length; i++)
                    {
                        _cameraComputeKernelIDs[i] = _cameraComputeShader.FindKernel(GPUInstancerConstants.CAMERA_COMPUTE_KERNELS[i]);
                    }
                }

                GPUInstancerConstants.SetupComputeRuntimeModification();
                GPUInstancerConstants.SetupComputeSetDataPartial();
            }
            else if (Application.isPlaying)
            {
                Debug.LogError("Target Graphics API does not support Compute Shaders. Please refer to Minimum Requirements on GPUInstancer/ReadMe.txt for detailed information.");
                this.enabled = false;
            }

            showRenderedAmount = false;

            InitializeCameraData();

#if UNITY_EDITOR && UNITY_2017_2_OR_NEWER
            EditorApplication.playModeStateChanged -= HandlePlayModeStateChanged;
            EditorApplication.playModeStateChanged += HandlePlayModeStateChanged;
#endif
        }
        public override void AddPickerObject(UnityEngine.Object pickerObject, GPUInstancerPrototype overridePrototype = null)
        {
            base.AddPickerObject(pickerObject, overridePrototype);

            if (pickerObject == null)
            {
                return;
            }

            if (!(pickerObject is GameObject))
            {
                EditorUtility.DisplayDialog(GPUInstancerConstants.TEXT_PREFAB_TYPE_WARNING_TITLE, GPUInstancerConstants.TEXT_TREE_PREFAB_TYPE_WARNING, GPUInstancerConstants.TEXT_OK);
                return;
            }

            GameObject prefabObject = (GameObject)pickerObject;

#if UNITY_2018_3_OR_NEWER
            PrefabAssetType prefabType = PrefabUtility.GetPrefabAssetType(pickerObject);

            if (prefabType == PrefabAssetType.Regular || prefabType == PrefabAssetType.Variant || prefabType == PrefabAssetType.Model)
            {
                GameObject newPrefabObject = (GameObject)PrefabUtility.GetCorrespondingObjectFromSource(prefabObject);
                if (newPrefabObject != null)
                {
                    while (newPrefabObject.transform.parent != null)
                    {
                        newPrefabObject = newPrefabObject.transform.parent.gameObject;
                    }
                    prefabObject = newPrefabObject;
                }
            }
            else
            {
                EditorUtility.DisplayDialog(GPUInstancerConstants.TEXT_PREFAB_TYPE_WARNING_TITLE, GPUInstancerConstants.TEXT_TREE_PREFAB_TYPE_WARNING, GPUInstancerConstants.TEXT_OK);
                return;
            }
#else
            PrefabType prefabType = PrefabUtility.GetPrefabType(pickerObject);

            if (prefabType != PrefabType.Prefab && prefabType != PrefabType.ModelPrefab)
            {
                bool instanceFound = false;
                if (prefabType == PrefabType.PrefabInstance || prefabType == PrefabType.ModelPrefabInstance)
                {
#if UNITY_2018_2_OR_NEWER
                    GameObject newPrefabObject = (GameObject)PrefabUtility.GetCorrespondingObjectFromSource(prefabObject);
#else
                    GameObject newPrefabObject = (GameObject)PrefabUtility.GetPrefabParent(prefabObject);
#endif
                    if (PrefabUtility.GetPrefabType(newPrefabObject) == PrefabType.Prefab || PrefabUtility.GetPrefabType(newPrefabObject) == PrefabType.ModelPrefab)
                    {
                        while (newPrefabObject.transform.parent != null)
                        {
                            newPrefabObject = newPrefabObject.transform.parent.gameObject;
                        }
                        prefabObject  = newPrefabObject;
                        instanceFound = true;
                    }
                }
                if (!instanceFound)
                {
                    EditorUtility.DisplayDialog(GPUInstancerConstants.TEXT_PREFAB_TYPE_WARNING_TITLE, GPUInstancerConstants.TEXT_TREE_PREFAB_TYPE_WARNING, GPUInstancerConstants.TEXT_OK);
                    return;
                }
            }
#endif

            Undo.RecordObject(this, "Add tree prototype");

            if (_treeManager.terrainSettings != null && _treeManager.terrain != null && _treeManager.terrain.terrainData != null)
            {
                if (overridePrototype != null)
                {
                    int prototypeIndex = prototypeList.IndexOf(overridePrototype);
                    if (prototypeIndex >= 0 && prototypeIndex < _treeManager.terrain.terrainData.treePrototypes.Length)
                    {
                        TreePrototype[] treePrototypes = _treeManager.terrain.terrainData.treePrototypes;

                        treePrototypes[prototypeIndex].prefab           = prefabObject;
                        overridePrototype.prefabObject                  = prefabObject;
                        _treeManager.terrain.terrainData.treePrototypes = treePrototypes;
                        _treeManager.terrain.terrainData.RefreshPrototypes();

                        GPUInstancerUtility.DetermineTreePrototypeType(overridePrototype);

                        if (overridePrototype.billboard != null && overridePrototype.useGeneratedBillboard)
                        {
                            GPUInstancerUtility.GeneratePrototypeBillboard(overridePrototype, true);
                        }
                    }
                }
                else
                {
                    List <TreePrototype> newTreePrototypes = new List <TreePrototype>(_treeManager.terrain.terrainData.treePrototypes);

                    TreePrototype terrainTreePrototype = new TreePrototype()
                    {
                        prefab     = prefabObject,
                        bendFactor = 0
                    };
                    newTreePrototypes.Add(terrainTreePrototype);

                    _treeManager.terrain.terrainData.treePrototypes = newTreePrototypes.ToArray();
                    _treeManager.terrain.terrainData.RefreshPrototypes();
                    GPUInstancerUtility.AddTreeInstancePrototypeFromTerrainPrototype(_treeManager.gameObject, prototypeList, terrainTreePrototype,
                                                                                     newTreePrototypes.Count - 1, _treeManager.terrainSettings);
                }
            }
        }