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(); } }
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); }
/// <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); }
/// <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); }
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(); }
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]; } } }
/// <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); }
/// <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); }
/// <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); }
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); }
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(); }
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); } }
/// <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); }
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 } }
/// <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); }
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); }
/// <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); }
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); } } }