1571 lines
86 KiB
C#
1571 lines
86 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using UnityEditor;
|
|
using UnityEngine;
|
|
using UnityEngine.Events;
|
|
using UnityEngine.Rendering;
|
|
|
|
namespace GPUInstancer
|
|
{
|
|
public abstract class GPUInstancerEditor : Editor
|
|
{
|
|
public static readonly float PROTOTYPE_RECT_SIZE = 80;
|
|
public static readonly float PROTOTYPE_RECT_PADDING = 5;
|
|
public static readonly Vector2 PROTOTYPE_RECT_PADDING_VECTOR = new Vector2(PROTOTYPE_RECT_PADDING, PROTOTYPE_RECT_PADDING);
|
|
public static readonly Vector2 PROTOTYPE_RECT_SIZE_VECTOR = new Vector2(PROTOTYPE_RECT_SIZE - PROTOTYPE_RECT_PADDING * 2, PROTOTYPE_RECT_SIZE - PROTOTYPE_RECT_PADDING * 2);
|
|
|
|
public static readonly float PROTOTYPE_TEXT_RECT_SIZE_X = 200;
|
|
public static readonly float PROTOTYPE_TEXT_RECT_SIZE_Y = 30;
|
|
public static readonly Vector2 PROTOTYPE_TEXT_RECT_SIZE_VECTOR = new Vector2(PROTOTYPE_TEXT_RECT_SIZE_X - PROTOTYPE_RECT_PADDING * 2, PROTOTYPE_TEXT_RECT_SIZE_Y - PROTOTYPE_RECT_PADDING * 2);
|
|
|
|
//protected SerializedProperty prop_settings;
|
|
protected SerializedProperty prop_autoSelectCamera;
|
|
protected SerializedProperty prop_mainCamera;
|
|
protected SerializedProperty prop_renderOnlySelectedCamera;
|
|
protected SerializedProperty prop_isManagerFrustumCulling;
|
|
protected SerializedProperty prop_isManagerOcclusionCulling;
|
|
protected SerializedProperty prop_minCullingDistance;
|
|
|
|
protected bool showSceneSettingsBox = true;
|
|
protected bool showPrototypeBox = true;
|
|
protected bool showAdvancedBox = false;
|
|
protected bool showHelpText = false;
|
|
protected bool showDebugBox = true;
|
|
protected bool showGlobalValuesBox = true;
|
|
protected bool showRegisteredPrefabsBox = true;
|
|
protected bool showPrototypesBox = true;
|
|
|
|
protected Texture2D helpIcon;
|
|
protected Texture2D helpIconActive;
|
|
protected Texture2D previewBoxIcon;
|
|
|
|
protected GUIContent[] prototypeContents = null;
|
|
|
|
protected List<GPUInstancerPrototype> prototypeList;
|
|
protected Dictionary<GPUInstancerPrototype, bool> prototypeSelection;
|
|
|
|
protected string wikiHash;
|
|
protected string versionNo;
|
|
|
|
protected bool useCustomPreviewBackgroundColor = false;
|
|
protected Color previewBackgroundColor;
|
|
|
|
protected bool isTextMode = false;
|
|
|
|
private GameObject _redirectObject;
|
|
|
|
// Previews
|
|
private GPUInstancerPreviewDrawer _previewDrawer;
|
|
|
|
protected virtual void OnEnable()
|
|
{
|
|
GPUInstancerConstants.gpuiSettings.SetDefultBindings();
|
|
|
|
prototypeContents = null;
|
|
|
|
helpIcon = Resources.Load<Texture2D>(GPUInstancerConstants.EDITOR_TEXTURES_PATH + GPUInstancerEditorConstants.HELP_ICON);
|
|
helpIconActive = Resources.Load<Texture2D>(GPUInstancerConstants.EDITOR_TEXTURES_PATH + GPUInstancerEditorConstants.HELP_ICON_ACTIVE);
|
|
previewBoxIcon = Resources.Load<Texture2D>(GPUInstancerConstants.EDITOR_TEXTURES_PATH + GPUInstancerEditorConstants.PREVIEW_BOX_ICON);
|
|
|
|
prop_autoSelectCamera = serializedObject.FindProperty("autoSelectCamera");
|
|
prop_mainCamera = serializedObject.FindProperty("cameraData").FindPropertyRelative("mainCamera");
|
|
prop_renderOnlySelectedCamera = serializedObject.FindProperty("cameraData").FindPropertyRelative("renderOnlySelectedCamera");
|
|
prop_isManagerFrustumCulling = serializedObject.FindProperty("isFrustumCulling");
|
|
prop_isManagerOcclusionCulling = serializedObject.FindProperty("isOcclusionCulling");
|
|
prop_minCullingDistance = serializedObject.FindProperty("minCullingDistance");
|
|
|
|
GPUInstancerDefines.previewCache.ClearEmptyPreviews();
|
|
}
|
|
|
|
protected virtual void OnDisable()
|
|
{
|
|
EditorApplication.update -= GeneratePrototypeContentTextures;
|
|
prototypeContents = null;
|
|
|
|
if (_previewDrawer != null)
|
|
_previewDrawer.Cleanup();
|
|
_previewDrawer = null;
|
|
}
|
|
|
|
public override void OnInspectorGUI()
|
|
{
|
|
if (prototypeContents == null || prototypeList.Count != prototypeContents.Length)
|
|
GeneratePrototypeContents();
|
|
|
|
GPUInstancerEditorConstants.Styles.foldout.fontStyle = FontStyle.Bold;
|
|
GPUInstancerEditorConstants.Styles.richLabel.richText = true;
|
|
|
|
EditorGUILayout.BeginHorizontal(GPUInstancerEditorConstants.Styles.box);
|
|
EditorGUILayout.LabelField(string.IsNullOrEmpty(versionNo) ? GPUInstancerEditorConstants.GPUI_VERSION : versionNo, GPUInstancerEditorConstants.Styles.boldLabel);
|
|
GUILayout.FlexibleSpace();
|
|
DrawWikiButton(GUILayoutUtility.GetRect(40, 20), wikiHash);
|
|
GUILayout.Space(10);
|
|
DrawHelpButton(GUILayoutUtility.GetRect(20, 20), showHelpText);
|
|
EditorGUILayout.EndHorizontal();
|
|
}
|
|
|
|
public virtual void InspectorGUIEnd()
|
|
{
|
|
if (_redirectObject != null)
|
|
{
|
|
Selection.activeGameObject = _redirectObject;
|
|
_redirectObject = null;
|
|
}
|
|
}
|
|
|
|
public virtual void FillPrototypeList() { }
|
|
|
|
public void GeneratePrototypeContents()
|
|
{
|
|
FillPrototypeList();
|
|
prototypeContents = new GUIContent[prototypeList.Count];
|
|
if (prototypeList == null || prototypeList.Count == 0)
|
|
return;
|
|
for (int i = 0; i < prototypeList.Count; i++)
|
|
{
|
|
prototypeContents[i] = new GUIContent(GPUInstancerDefines.previewCache.GetPreview(prototypeList[i]), prototypeList[i].ToString());
|
|
}
|
|
|
|
EditorApplication.update -= GeneratePrototypeContentTextures;
|
|
EditorApplication.update += GeneratePrototypeContentTextures;
|
|
}
|
|
|
|
public void GeneratePrototypeContentTextures()
|
|
{
|
|
if (isTextMode)
|
|
return;
|
|
|
|
if (prototypeContents == null || prototypeContents.Length == 0 || prototypeList == null)
|
|
return;
|
|
|
|
for (int i = 0; i < prototypeContents.Length && i < prototypeList.Count; i++)
|
|
{
|
|
if (prototypeContents[i].image == null)
|
|
{
|
|
if (_previewDrawer == null)
|
|
_previewDrawer = new GPUInstancerPreviewDrawer(previewBoxIcon);
|
|
|
|
prototypeContents[i].image = GPUInstancerDefines.previewCache.GetPreview(prototypeList[i]);
|
|
|
|
if (prototypeContents[i].image == null)
|
|
{
|
|
Texture2D texture = GetPreviewTexture(prototypeList[i]);
|
|
prototypeContents[i].image = texture;
|
|
GPUInstancerDefines.previewCache.AddPreview(prototypeList[i], texture);
|
|
if (!GPUInstancerConstants.gpuiSettings.IsStandardRenderPipeline())
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (_previewDrawer != null)
|
|
_previewDrawer.Cleanup();
|
|
_previewDrawer = null;
|
|
EditorApplication.update -= GeneratePrototypeContentTextures;
|
|
}
|
|
|
|
public Texture2D GetPreviewTexture(GPUInstancerPrototype prototype)
|
|
{
|
|
try
|
|
{
|
|
if (prototype.prefabObject == null)
|
|
{
|
|
if (prototype.GetPreviewTexture() != null)
|
|
{
|
|
_previewDrawer.SetAdditionalTexture(prototype.GetPreviewTexture());
|
|
Texture2D result = _previewDrawer.GetPreviewForGameObject(null, new Rect(0, 0, PROTOTYPE_RECT_SIZE - 10, PROTOTYPE_RECT_SIZE - 10),
|
|
useCustomPreviewBackgroundColor ? previewBackgroundColor : Color.clear);
|
|
_previewDrawer.SetAdditionalTexture(null);
|
|
return result;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (prototype.prefabObject.GetComponentInChildren<MeshFilter>() == null && prototype.prefabObject.GetComponentInChildren<SkinnedMeshRenderer>() == null)
|
|
return null;
|
|
|
|
return _previewDrawer.GetPreviewForGameObject(prototype.prefabObject, new Rect(0, 0, PROTOTYPE_RECT_SIZE - 10, PROTOTYPE_RECT_SIZE - 10),
|
|
useCustomPreviewBackgroundColor ? previewBackgroundColor : Color.clear);
|
|
}
|
|
|
|
if (Application.isPlaying && GPUInstancerManager.activeManagerList != null)
|
|
{
|
|
for (int i = 0; i < GPUInstancerManager.activeManagerList.Count; i++)
|
|
{
|
|
GPUInstancerManager manager = GPUInstancerManager.activeManagerList[i];
|
|
if (manager != null && manager.isInitialized)
|
|
{
|
|
GPUInstancerRuntimeData runtimeData = manager.GetRuntimeData(prototype);
|
|
if (runtimeData != null && runtimeData.instanceLODs != null && runtimeData.instanceLODs.Count > 0)
|
|
{
|
|
return _previewDrawer.GetPreviewForGameObject(null, new Rect(0, 0, PROTOTYPE_RECT_SIZE - 10, PROTOTYPE_RECT_SIZE - 10),
|
|
useCustomPreviewBackgroundColor ? previewBackgroundColor : Color.clear, runtimeData);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.LogError(e);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public Texture2D GetPreviewTextureFromTexture2D(Texture2D texture)
|
|
{
|
|
if (!texture)
|
|
return null;
|
|
try
|
|
{
|
|
// Create a temporary RenderTexture of the same size as the texture
|
|
RenderTexture tempRT = RenderTexture.GetTemporary(
|
|
texture.width,
|
|
texture.height,
|
|
0,
|
|
RenderTextureFormat.Default,
|
|
RenderTextureReadWrite.Linear);
|
|
|
|
// Blit the pixels on texture to the RenderTexture
|
|
Graphics.Blit(texture, tempRT);
|
|
// Backup the currently set RenderTexture
|
|
RenderTexture previous = RenderTexture.active;
|
|
// Set the current RenderTexture to the temporary one we created
|
|
RenderTexture.active = tempRT;
|
|
// Create a new readable Texture2D to copy the pixels to it
|
|
#if UNITY_2017_1_OR_NEWER
|
|
Texture2D myTexture2D = new Texture2D(texture.width, texture.height, TextureFormat.RGBAFloat, true, false);
|
|
#else
|
|
Texture2D myTexture2D = new Texture2D(texture.width, texture.height);
|
|
#endif
|
|
// Copy the pixels from the RenderTexture to the new Texture
|
|
myTexture2D.ReadPixels(new Rect(0, 0, tempRT.width, tempRT.height), 0, 0);
|
|
myTexture2D.Apply();
|
|
// Reset the active RenderTexture
|
|
RenderTexture.active = previous;
|
|
// Release the temporary RenderTexture
|
|
RenderTexture.ReleaseTemporary(tempRT);
|
|
|
|
return myTexture2D;
|
|
}
|
|
catch (Exception) { }
|
|
return null;
|
|
}
|
|
|
|
public void DrawCameraDataFields()
|
|
{
|
|
EditorGUILayout.PropertyField(prop_autoSelectCamera);
|
|
if (!prop_autoSelectCamera.boolValue)
|
|
EditorGUILayout.PropertyField(prop_mainCamera, GPUInstancerEditorConstants.Contents.useCamera);
|
|
DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_camera);
|
|
EditorGUILayout.PropertyField(prop_renderOnlySelectedCamera, GPUInstancerEditorConstants.Contents.renderOnlySelectedCamera);
|
|
DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_renderOnlySelectedCamera);
|
|
}
|
|
|
|
public virtual void DrawFloatingOriginFields()
|
|
{
|
|
|
|
}
|
|
|
|
public virtual void DrawLayerMaskFields()
|
|
{
|
|
|
|
}
|
|
|
|
public void DrawCullingSettings(List<GPUInstancerPrototype> protoypeList)
|
|
{
|
|
EditorGUILayout.PropertyField(prop_isManagerFrustumCulling, GPUInstancerEditorConstants.Contents.useManagerFrustumCulling);
|
|
DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_managerFrustumCulling);
|
|
EditorGUILayout.PropertyField(prop_isManagerOcclusionCulling, GPUInstancerEditorConstants.Contents.useManagerOcclusionCulling);
|
|
DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_managerOcclusionCulling);
|
|
|
|
#if GPUI_URP
|
|
if (prop_isManagerOcclusionCulling.boolValue
|
|
&& QualitySettings.renderPipeline is UnityEngine.Rendering.Universal.UniversalRenderPipelineAsset urpAsset
|
|
&& urpAsset != null)
|
|
{
|
|
if (!urpAsset.supportsCameraDepthTexture)
|
|
EditorGUILayout.HelpBox("The Occlusion Culling feature requires the Depth Texture option to be enabled in the URP pipeline settings. It is currently disabled.", MessageType.Warning);
|
|
if (!urpAsset.supportsHDR)
|
|
EditorGUILayout.HelpBox("The Occlusion Culling feature requires the HDR option to be enabled in the URP pipeline settings. It is currently disabled.", MessageType.Warning);
|
|
}
|
|
#endif
|
|
|
|
// Min Culling Distance
|
|
EditorGUI.BeginChangeCheck();
|
|
float newCullingDistanceValue = EditorGUILayout.Slider(GPUInstancerEditorConstants.Contents.minManagerCullingDistance, prop_minCullingDistance.floatValue, 0, 100);
|
|
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
if (protoypeList != null)
|
|
{
|
|
foreach (GPUInstancerPrototype prototype in protoypeList)
|
|
{
|
|
if (prototype.minCullingDistance == prop_minCullingDistance.floatValue)
|
|
{
|
|
prototype.minCullingDistance = newCullingDistanceValue;
|
|
EditorUtility.SetDirty(prototype);
|
|
}
|
|
}
|
|
}
|
|
prop_minCullingDistance.floatValue = newCullingDistanceValue;
|
|
}
|
|
DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_minCullingDistance);
|
|
|
|
if (protoypeList != null)
|
|
{
|
|
foreach (GPUInstancerPrototype prototype in protoypeList)
|
|
{
|
|
if (prototype.minCullingDistance < newCullingDistanceValue)
|
|
{
|
|
prototype.minCullingDistance = newCullingDistanceValue;
|
|
EditorUtility.SetDirty(prototype);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void DrawSceneSettingsBox()
|
|
{
|
|
EditorGUILayout.BeginVertical(GPUInstancerEditorConstants.Styles.box);
|
|
|
|
Rect foldoutRect = GUILayoutUtility.GetRect(0, 20, GUILayout.ExpandWidth(true), GUILayout.ExpandHeight(false));
|
|
foldoutRect.x += 12;
|
|
showSceneSettingsBox = EditorGUI.Foldout(foldoutRect, showSceneSettingsBox, GPUInstancerEditorConstants.TEXT_sceneSettings, true, GPUInstancerEditorConstants.Styles.foldout);
|
|
|
|
if (showSceneSettingsBox)
|
|
{
|
|
DrawSettingContents();
|
|
}
|
|
EditorGUILayout.EndVertical();
|
|
}
|
|
|
|
public abstract void DrawSettingContents();
|
|
|
|
public virtual void DrawGPUInstancerPrototypeButton(GPUInstancerPrototype prototype, GUIContent prototypeContent, bool isSelected, UnityAction handleSelect, bool isTextMode = false)
|
|
{
|
|
if (isTextMode)
|
|
{
|
|
DrawGPUInstancerPrototypeButtonTextMode(prototype, prototypeContent, isSelected, handleSelect);
|
|
return;
|
|
}
|
|
|
|
if (prototypeContent.image == null)
|
|
{
|
|
prototypeContent = new GUIContent(prototypeContent.text, prototypeContent.tooltip);
|
|
}
|
|
|
|
Rect prototypeRect = GUILayoutUtility.GetRect(PROTOTYPE_RECT_SIZE, PROTOTYPE_RECT_SIZE, GUILayout.ExpandWidth(false), GUILayout.ExpandHeight(false));
|
|
|
|
Rect iconRect = new Rect(prototypeRect.position + PROTOTYPE_RECT_PADDING_VECTOR, PROTOTYPE_RECT_SIZE_VECTOR);
|
|
|
|
GUI.SetNextControlName(prototypeContent.tooltip);
|
|
Color prototypeColor;
|
|
if (isSelected)
|
|
prototypeColor = string.IsNullOrEmpty(prototype.warningText) ? GPUInstancerEditorConstants.Colors.lightGreen : GPUInstancerEditorConstants.Colors.dimgray;
|
|
else
|
|
prototypeColor = string.IsNullOrEmpty(prototype.warningText) ? GUI.backgroundColor : GPUInstancerEditorConstants.Colors.darkBlue;
|
|
|
|
GPUInstancerEditorConstants.DrawColoredButton(prototypeContent, prototypeColor, GPUInstancerEditorConstants.Styles.label.normal.textColor, FontStyle.Normal, iconRect,
|
|
() =>
|
|
{
|
|
if (handleSelect != null)
|
|
handleSelect();
|
|
});
|
|
}
|
|
|
|
public virtual void DrawGPUInstancerPrototypeButtonTextMode(GPUInstancerPrototype prototype, GUIContent prototypeContent, bool isSelected, UnityAction handleSelect)
|
|
{
|
|
Rect prototypeRect = GUILayoutUtility.GetRect(PROTOTYPE_TEXT_RECT_SIZE_X, PROTOTYPE_TEXT_RECT_SIZE_Y, GUILayout.ExpandWidth(false), GUILayout.ExpandHeight(false));
|
|
|
|
Rect iconRect = new Rect(prototypeRect.position + PROTOTYPE_RECT_PADDING_VECTOR, PROTOTYPE_TEXT_RECT_SIZE_VECTOR);
|
|
|
|
GUI.SetNextControlName(prototypeContent.tooltip);
|
|
Color prototypeColor;
|
|
if (isSelected)
|
|
prototypeColor = string.IsNullOrEmpty(prototype.warningText) ? GPUInstancerEditorConstants.Colors.lightGreen : GPUInstancerEditorConstants.Colors.dimgray;
|
|
else
|
|
prototypeColor = string.IsNullOrEmpty(prototype.warningText) ? GUI.backgroundColor : GPUInstancerEditorConstants.Colors.darkBlue;
|
|
|
|
prototypeContent = new GUIContent(prototypeContent.tooltip);
|
|
GPUInstancerEditorConstants.DrawColoredButton(prototypeContent, prototypeColor, GPUInstancerEditorConstants.Styles.label.normal.textColor, FontStyle.Normal, iconRect,
|
|
() =>
|
|
{
|
|
if (handleSelect != null)
|
|
handleSelect();
|
|
});
|
|
}
|
|
|
|
public virtual void DrawGPUInstancerPrototypeBox(List<GPUInstancerPrototype> selectedPrototypeList, bool isManagerFrustumCulling, bool isManagerOcclusionCulling)
|
|
{
|
|
if (selectedPrototypeList == null || selectedPrototypeList.Count == 0)
|
|
return;
|
|
|
|
if (selectedPrototypeList.Count == 1)
|
|
{
|
|
DrawGPUInstancerPrototypeBox(selectedPrototypeList[0], isManagerFrustumCulling, isManagerOcclusionCulling);
|
|
return;
|
|
}
|
|
|
|
EditorGUILayout.BeginVertical(GPUInstancerEditorConstants.Styles.box);
|
|
// title
|
|
Rect foldoutRect = GUILayoutUtility.GetRect(0, 20, GUILayout.ExpandWidth(true), GUILayout.ExpandHeight(false));
|
|
foldoutRect.x += 12;
|
|
showPrototypeBox = EditorGUI.Foldout(foldoutRect, showPrototypeBox, "Multiple Selection", true, GPUInstancerEditorConstants.Styles.foldout);
|
|
|
|
if (showPrototypeBox)
|
|
{
|
|
GPUInstancerPrototype prototype0 = selectedPrototypeList[0];
|
|
#region Determine Multiple Values
|
|
bool hasChanged = false;
|
|
bool isShadowCastingMixed = false;
|
|
bool isShadowCasting = prototype0.isShadowCasting;
|
|
bool useOriginalShaderForShadowMixed = false;
|
|
bool useOriginalShaderForShadow = prototype0.useOriginalShaderForShadow;
|
|
bool useCustomShadowDistanceMixed = false;
|
|
bool useCustomShadowDistance = prototype0.useCustomShadowDistance;
|
|
bool shadowDistanceMixed = false;
|
|
float shadowDistance = prototype0.shadowDistance;
|
|
bool cullShadowsMixed = false;
|
|
bool cullShadows = prototype0.cullShadows;
|
|
bool minDistanceMixed = false;
|
|
float minDistance = prototype0.minDistance;
|
|
bool maxDistanceMixed = false;
|
|
float maxDistance = prototype0.maxDistance;
|
|
bool isFrustumCullingMixed = false;
|
|
bool isFrustumCulling = prototype0.isFrustumCulling;
|
|
bool frustumOffsetMixed = false;
|
|
float frustumOffset = prototype0.frustumOffset;
|
|
bool isOcclusionCullingMixed = false;
|
|
bool isOcclusionCulling = prototype0.isOcclusionCulling;
|
|
bool occlusionOffsetMixed = false;
|
|
float occlusionOffset = prototype0.occlusionOffset;
|
|
bool occlusionAccuracyMixed = false;
|
|
int occlusionAccuracy = prototype0.occlusionAccuracy;
|
|
bool minCullingDistanceMixed = false;
|
|
float minCullingDistance = prototype0.minCullingDistance;
|
|
bool boundsOffsetMixed = false;
|
|
Vector3 boundsOffset = prototype0.boundsOffset;
|
|
|
|
bool isLODCrossFadeMixed = false;
|
|
bool isLODCrossFade = prototype0.isLODCrossFade;
|
|
bool isLODCrossFadeAnimateMixed = false;
|
|
bool isLODCrossFadeAnimate = prototype0.isLODCrossFadeAnimate;
|
|
bool lodFadeTransitionWidthMixed = false;
|
|
float lodFadeTransitionWidth = prototype0.lodFadeTransitionWidth;
|
|
bool lodBiasAdjustmentMixed = false;
|
|
float lodBiasAdjustment = prototype0.lodBiasAdjustment;
|
|
|
|
for (int i = 1; i < selectedPrototypeList.Count; i++)
|
|
{
|
|
if (!isShadowCastingMixed && isShadowCasting != selectedPrototypeList[i].isShadowCasting)
|
|
isShadowCastingMixed = true;
|
|
if (!useOriginalShaderForShadowMixed && useOriginalShaderForShadow != selectedPrototypeList[i].useOriginalShaderForShadow)
|
|
useOriginalShaderForShadowMixed = true;
|
|
if (!useCustomShadowDistanceMixed && useCustomShadowDistance != selectedPrototypeList[i].useCustomShadowDistance)
|
|
useCustomShadowDistanceMixed = true;
|
|
if (!shadowDistanceMixed && shadowDistance != selectedPrototypeList[i].shadowDistance)
|
|
shadowDistanceMixed = true;
|
|
if (!cullShadowsMixed && cullShadows != selectedPrototypeList[i].cullShadows)
|
|
cullShadowsMixed = true;
|
|
if (!minDistanceMixed && minDistance != selectedPrototypeList[i].minDistance)
|
|
minDistanceMixed = true;
|
|
if (!maxDistanceMixed && maxDistance != selectedPrototypeList[i].maxDistance)
|
|
maxDistanceMixed = true;
|
|
if (!isFrustumCullingMixed && isFrustumCulling != selectedPrototypeList[i].isFrustumCulling)
|
|
isFrustumCullingMixed = true;
|
|
if (!frustumOffsetMixed && frustumOffset != selectedPrototypeList[i].frustumOffset)
|
|
frustumOffsetMixed = true;
|
|
if (!isOcclusionCullingMixed && isOcclusionCulling != selectedPrototypeList[i].isOcclusionCulling)
|
|
isOcclusionCullingMixed = true;
|
|
if (!occlusionOffsetMixed && occlusionOffset != selectedPrototypeList[i].occlusionOffset)
|
|
occlusionOffsetMixed = true;
|
|
if (!occlusionAccuracyMixed && occlusionAccuracy != selectedPrototypeList[i].occlusionAccuracy)
|
|
occlusionAccuracyMixed = true;
|
|
if (!minCullingDistanceMixed && minCullingDistance != selectedPrototypeList[i].minCullingDistance)
|
|
minCullingDistanceMixed = true;
|
|
if (!boundsOffsetMixed && boundsOffset != selectedPrototypeList[i].boundsOffset)
|
|
boundsOffsetMixed = true;
|
|
|
|
if (!isLODCrossFadeMixed && isLODCrossFade != selectedPrototypeList[i].isLODCrossFade)
|
|
isLODCrossFadeMixed = true;
|
|
if (!isLODCrossFadeAnimateMixed && isLODCrossFadeAnimate != selectedPrototypeList[i].isLODCrossFadeAnimate)
|
|
isLODCrossFadeAnimateMixed = true;
|
|
if (!lodFadeTransitionWidthMixed && lodFadeTransitionWidth != selectedPrototypeList[i].lodFadeTransitionWidth)
|
|
lodFadeTransitionWidthMixed = true;
|
|
if (!lodBiasAdjustmentMixed && lodBiasAdjustment != selectedPrototypeList[i].lodBiasAdjustment)
|
|
lodBiasAdjustmentMixed = true;
|
|
}
|
|
#endregion Determine Multiple Values
|
|
|
|
hasChanged |= DrawGPUInstancerPrototypeBeginningInfo(selectedPrototypeList);
|
|
|
|
#region Shadows
|
|
EditorGUILayout.BeginVertical(GPUInstancerEditorConstants.Styles.box);
|
|
GPUInstancerEditorConstants.DrawCustomLabel(GPUInstancerEditorConstants.TEXT_shadows, GPUInstancerEditorConstants.Styles.boldLabel);
|
|
|
|
EditorGUI.BeginDisabledGroup(Application.isPlaying);
|
|
hasChanged |= MultiToggle(selectedPrototypeList, GPUInstancerEditorConstants.TEXT_isShadowCasting, isShadowCasting, isShadowCastingMixed, (p, v) => p.isShadowCasting = v);
|
|
DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_isShadowCasting);
|
|
if (!isShadowCastingMixed && isShadowCasting && GPUInstancerConstants.gpuiSettings.IsStandardRenderPipeline())
|
|
{
|
|
if (prototype0 is GPUInstancerPrefabPrototype)
|
|
{
|
|
hasChanged |= MultiToggle(selectedPrototypeList, GPUInstancerEditorConstants.TEXT_useOriginalShaderForShadow, useOriginalShaderForShadow, useOriginalShaderForShadowMixed, (p, v) => p.useOriginalShaderForShadow = v);
|
|
DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_useOriginalShaderForShadow);
|
|
}
|
|
}
|
|
EditorGUI.EndDisabledGroup();
|
|
|
|
if (!(prototype0 is GPUInstancerDetailPrototype))
|
|
{
|
|
if (!isShadowCastingMixed && isShadowCasting)
|
|
{
|
|
hasChanged |= MultiToggle(selectedPrototypeList, GPUInstancerEditorConstants.TEXT_useCustomShadowDistance, useCustomShadowDistance, useCustomShadowDistanceMixed, (p, v) => p.useCustomShadowDistance = v);
|
|
if (!useCustomShadowDistanceMixed && useCustomShadowDistance)
|
|
{
|
|
hasChanged |= MultiSlider(selectedPrototypeList, GPUInstancerEditorConstants.TEXT_shadowDistance, shadowDistance, 0.0f, GPUInstancerConstants.gpuiSettings.MAX_PREFAB_DISTANCE, shadowDistanceMixed, (p, v) => p.shadowDistance = v);
|
|
}
|
|
DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_useCustomShadowDistance);
|
|
|
|
hasChanged |= MultiToggle(selectedPrototypeList, GPUInstancerEditorConstants.TEXT_cullShadows, cullShadows, cullShadowsMixed, (p, v) => p.cullShadows = v);
|
|
DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_cullShadows);
|
|
}
|
|
}
|
|
|
|
EditorGUILayout.EndVertical();
|
|
#endregion Shadows
|
|
|
|
#region Culling
|
|
EditorGUILayout.BeginVertical(GPUInstancerEditorConstants.Styles.box);
|
|
GPUInstancerEditorConstants.DrawCustomLabel(GPUInstancerEditorConstants.TEXT_culling, GPUInstancerEditorConstants.Styles.boldLabel);
|
|
|
|
hasChanged |= MultiMinMaxSlider(selectedPrototypeList, GPUInstancerEditorConstants.TEXT_maxDistance, minDistance, maxDistance, 0.0f, GetMaxDistance(prototype0), minDistanceMixed || maxDistanceMixed, (p, vMin, vMax) => { p.minDistance = vMin; p.maxDistance = vMax; });
|
|
EditorGUILayout.BeginHorizontal();
|
|
hasChanged |= MultiFloat(selectedPrototypeList, " ", minDistance, minDistanceMixed, (p, v) => p.minDistance = v);
|
|
hasChanged |= MultiFloat(selectedPrototypeList, null, maxDistance, minDistanceMixed, (p, v) => p.maxDistance = v);
|
|
EditorGUILayout.EndHorizontal();
|
|
DrawHelpText(prototype0 is GPUInstancerDetailPrototype ? GPUInstancerEditorConstants.HELPTEXT_maxDistanceDetail : GPUInstancerEditorConstants.HELPTEXT_maxDistance);
|
|
if (isManagerFrustumCulling)
|
|
{
|
|
hasChanged |= MultiToggle(selectedPrototypeList, GPUInstancerEditorConstants.TEXT_isFrustumCulling, isFrustumCulling, isFrustumCullingMixed, (p, v) => p.isFrustumCulling = v);
|
|
DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_isFrustumCulling);
|
|
|
|
hasChanged |= MultiSlider(selectedPrototypeList, GPUInstancerEditorConstants.TEXT_frustumOffset, frustumOffset, 0.0f, 0.5f, frustumOffsetMixed, (p, v) => p.frustumOffset = v);
|
|
DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_frustumOffset);
|
|
}
|
|
|
|
if (isManagerOcclusionCulling)
|
|
{
|
|
hasChanged |= MultiToggle(selectedPrototypeList, GPUInstancerEditorConstants.TEXT_isOcclusionCulling, isOcclusionCulling, isOcclusionCullingMixed, (p, v) => p.isOcclusionCulling = v);
|
|
DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_isOcclusionCulling);
|
|
|
|
hasChanged |= MultiSlider(selectedPrototypeList, GPUInstancerEditorConstants.TEXT_occlusionOffset, occlusionOffset, 0.0f, 0.1f, occlusionOffsetMixed, (p, v) => p.occlusionOffset = v);
|
|
DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_occlusionOffset);
|
|
|
|
hasChanged |= MultiIntSlider(selectedPrototypeList, GPUInstancerEditorConstants.TEXT_occlusionAccuracy, occlusionAccuracy, 1, 3, occlusionAccuracyMixed, (p, v) => p.occlusionAccuracy = v);
|
|
DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_occlusionAccuracy);
|
|
}
|
|
|
|
if (isManagerFrustumCulling || isManagerOcclusionCulling)
|
|
{
|
|
hasChanged |= MultiSlider(selectedPrototypeList, GPUInstancerEditorConstants.TEXT_minCullingDistance, minCullingDistance, 0, 100, minCullingDistanceMixed, (p, v) => p.minCullingDistance = v);
|
|
DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_minCullingDistance);
|
|
}
|
|
hasChanged |= MultiVector3(selectedPrototypeList, GPUInstancerEditorConstants.TEXT_boundsOffset, boundsOffset, boundsOffsetMixed, false, (p, v) => p.boundsOffset = v);
|
|
DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_boundsOffset);
|
|
|
|
EditorGUILayout.EndVertical();
|
|
#endregion Culling
|
|
|
|
EditorGUI.BeginDisabledGroup(Application.isPlaying);
|
|
#region LOD
|
|
bool isAnyLOD = false;
|
|
foreach (GPUInstancerPrototype p in selectedPrototypeList)
|
|
{
|
|
if (p.prefabObject != null && (p.prefabObject.GetComponent<LODGroup>() != null || p.useGeneratedBillboard))
|
|
{
|
|
isAnyLOD = true;
|
|
break;
|
|
}
|
|
else if (p.isLODCrossFade)
|
|
{
|
|
p.isLODCrossFade = false;
|
|
hasChanged = true;
|
|
}
|
|
}
|
|
if (isAnyLOD)
|
|
{
|
|
EditorGUILayout.BeginVertical(GPUInstancerEditorConstants.Styles.box);
|
|
GPUInstancerEditorConstants.DrawCustomLabel(GPUInstancerEditorConstants.TEXT_LOD, GPUInstancerEditorConstants.Styles.boldLabel);
|
|
|
|
if (GPUInstancerConstants.gpuiSettings.IsLODCrossFadeSupported())
|
|
{
|
|
hasChanged |= MultiToggle(selectedPrototypeList, GPUInstancerEditorConstants.TEXT_isLODCrossFade, isLODCrossFade, isLODCrossFadeMixed, (p, v) => p.isLODCrossFade = v);
|
|
DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_isLODCrossFade);
|
|
|
|
if (isLODCrossFade && !isLODCrossFadeMixed)
|
|
{
|
|
hasChanged |= MultiToggle(selectedPrototypeList, GPUInstancerEditorConstants.TEXT_isLODCrossFadeAnimate, isLODCrossFadeAnimate, isLODCrossFadeAnimateMixed, (p, v) => p.isLODCrossFadeAnimate = v);
|
|
DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_isLODCrossFadeAnimate);
|
|
|
|
if (!isLODCrossFadeAnimate && !isLODCrossFadeAnimateMixed)
|
|
{
|
|
hasChanged |= MultiSlider(selectedPrototypeList, GPUInstancerEditorConstants.TEXT_lodFadeTransitionWidth, lodFadeTransitionWidth, 0.0f, 1.0f, lodFadeTransitionWidthMixed, (p, v) => p.lodFadeTransitionWidth = v);
|
|
DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_lodFadeTransitionWidth);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
foreach (GPUInstancerPrototype p in selectedPrototypeList)
|
|
{
|
|
if (p.isLODCrossFade)
|
|
{
|
|
p.isLODCrossFade = false;
|
|
hasChanged = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
hasChanged |= MultiFloat(selectedPrototypeList, GPUInstancerEditorConstants.TEXT_lodBiasAdjustment, lodBiasAdjustment, lodBiasAdjustmentMixed, (p, v) => p.lodBiasAdjustment = v);
|
|
DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_lodBiasAdjustment);
|
|
|
|
EditorGUILayout.EndVertical();
|
|
}
|
|
#endregion LOD
|
|
|
|
hasChanged |= DrawGPUInstancerPrototypeInfo(selectedPrototypeList);
|
|
hasChanged |= DrawGPUInstancerPrototypeBillboardSettings(selectedPrototypeList);
|
|
DrawGPUInstancerPrototypeActions();
|
|
DrawGPUInstancerPrototypeAdvancedActions();
|
|
EditorGUI.EndDisabledGroup();
|
|
|
|
if (hasChanged)
|
|
{
|
|
for (int i = 0; i < selectedPrototypeList.Count; i++)
|
|
{
|
|
EditorUtility.SetDirty(selectedPrototypeList[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
EditorGUILayout.EndVertical();
|
|
}
|
|
|
|
public virtual void DrawGPUInstancerPrototypeBox(GPUInstancerPrototype selectedPrototype, bool isFrustumCulling, bool isOcclusionCulling)
|
|
{
|
|
if (selectedPrototype == null)
|
|
return;
|
|
|
|
EditorGUILayout.BeginVertical(GPUInstancerEditorConstants.Styles.box);
|
|
// title
|
|
Rect foldoutRect = GUILayoutUtility.GetRect(0, 20, GUILayout.ExpandWidth(true), GUILayout.ExpandHeight(false));
|
|
foldoutRect.x += 12;
|
|
showPrototypeBox = EditorGUI.Foldout(foldoutRect, showPrototypeBox, selectedPrototype.ToString(), true, GPUInstancerEditorConstants.Styles.foldout);
|
|
|
|
if (!showPrototypeBox)
|
|
{
|
|
EditorGUILayout.EndVertical();
|
|
return;
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(selectedPrototype.warningText))
|
|
{
|
|
EditorGUILayout.HelpBox(selectedPrototype.warningText, MessageType.Error);
|
|
EditorGUILayout.BeginHorizontal();
|
|
if (selectedPrototype.warningText.StartsWith("Can not create instanced version for shader"))
|
|
{
|
|
GPUInstancerEditorConstants.DrawColoredButton(new GUIContent("Go to Unity Archive"),
|
|
GPUInstancerEditorConstants.Colors.dimgray, Color.white, FontStyle.Bold, Rect.zero,
|
|
() =>
|
|
{
|
|
Application.OpenURL("https://unity3d.com/get-unity/download/archive");
|
|
});
|
|
}
|
|
else if (selectedPrototype.warningText.StartsWith("ShaderGraph shader does not contain"))
|
|
{
|
|
GPUInstancerEditorConstants.DrawColoredButton(new GUIContent("Go to Shader Setup Documentation"),
|
|
GPUInstancerEditorConstants.Colors.dimgray, Color.white, FontStyle.Bold, Rect.zero,
|
|
() =>
|
|
{
|
|
Application.OpenURL("https://wiki.gurbu.com/index.php?title=GPU_Instancer:FAQ#ShaderGraph_Setup");
|
|
});
|
|
}
|
|
else if (selectedPrototype.warningText.StartsWith("Better Shaders"))
|
|
{
|
|
GPUInstancerEditorConstants.DrawColoredButton(new GUIContent("Go to Shader Setup Documentation"),
|
|
GPUInstancerEditorConstants.Colors.dimgray, Color.white, FontStyle.Bold, Rect.zero,
|
|
() =>
|
|
{
|
|
Application.OpenURL("https://wiki.gurbu.com/index.php?title=GPU_Instancer:FAQ#Better_Shaders_Setup");
|
|
});
|
|
}
|
|
if (selectedPrototype.warningShader != null)
|
|
{
|
|
GUILayout.Space(10);
|
|
GPUInstancerEditorConstants.DrawColoredButton(new GUIContent("Select Shader"),
|
|
GPUInstancerEditorConstants.Colors.lightBlue, Color.white, FontStyle.Bold, Rect.zero,
|
|
() =>
|
|
{
|
|
Selection.activeObject = selectedPrototype.warningShader;
|
|
});
|
|
}
|
|
EditorGUILayout.EndHorizontal();
|
|
GUILayout.Space(10);
|
|
|
|
}
|
|
|
|
|
|
DrawPrefabField(selectedPrototype);
|
|
EditorGUI.BeginDisabledGroup(true);
|
|
EditorGUILayout.ObjectField(GPUInstancerEditorConstants.TEXT_prototypeSO, selectedPrototype, typeof(GPUInstancerPrototype), false);
|
|
EditorGUI.EndDisabledGroup();
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
|
|
DrawGPUInstancerPrototypeBeginningInfo(selectedPrototype);
|
|
|
|
#region Shadows
|
|
EditorGUILayout.BeginVertical(GPUInstancerEditorConstants.Styles.box);
|
|
GPUInstancerEditorConstants.DrawCustomLabel(GPUInstancerEditorConstants.TEXT_shadows, GPUInstancerEditorConstants.Styles.boldLabel);
|
|
|
|
EditorGUI.BeginDisabledGroup(Application.isPlaying);
|
|
selectedPrototype.isShadowCasting = EditorGUILayout.Toggle(GPUInstancerEditorConstants.TEXT_isShadowCasting, selectedPrototype.isShadowCasting);
|
|
DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_isShadowCasting);
|
|
EditorGUI.EndDisabledGroup();
|
|
if (selectedPrototype.isShadowCasting)
|
|
{
|
|
if (selectedPrototype.shadowLODMap == null || selectedPrototype.shadowLODMap.Length != 16)
|
|
{
|
|
selectedPrototype.shadowLODMap = new float[] {
|
|
0, 4, 0, 0,
|
|
1, 5, 0, 0,
|
|
2, 6, 0, 0,
|
|
3, 7, 0, 0};
|
|
}
|
|
if (selectedPrototype is GPUInstancerPrefabPrototype && GPUInstancerConstants.gpuiSettings.IsStandardRenderPipeline())
|
|
{
|
|
EditorGUI.BeginDisabledGroup(Application.isPlaying);
|
|
selectedPrototype.useOriginalShaderForShadow = EditorGUILayout.Toggle(GPUInstancerEditorConstants.TEXT_useOriginalShaderForShadow, selectedPrototype.useOriginalShaderForShadow);
|
|
DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_useOriginalShaderForShadow);
|
|
EditorGUI.EndDisabledGroup();
|
|
}
|
|
|
|
if (!(selectedPrototype is GPUInstancerDetailPrototype))
|
|
{
|
|
selectedPrototype.useCustomShadowDistance = EditorGUILayout.Toggle(GPUInstancerEditorConstants.TEXT_useCustomShadowDistance, selectedPrototype.useCustomShadowDistance);
|
|
if (selectedPrototype.useCustomShadowDistance)
|
|
{
|
|
selectedPrototype.shadowDistance = EditorGUILayout.Slider(GPUInstancerEditorConstants.TEXT_shadowDistance, selectedPrototype.shadowDistance, 0.0f, GPUInstancerConstants.gpuiSettings.MAX_PREFAB_DISTANCE);
|
|
}
|
|
DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_useCustomShadowDistance);
|
|
if (selectedPrototype.prefabObject != null && selectedPrototype.prefabObject.GetComponent<LODGroup>() != null)
|
|
{
|
|
LODGroup lodGroup = selectedPrototype.prefabObject.GetComponent<LODGroup>();
|
|
List<GUIContent> optionsList = GPUInstancerEditorConstants.Contents.LODs.GetRange(0, lodGroup.lodCount);
|
|
optionsList.Add(GPUInstancerEditorConstants.Contents.LODs[8]);
|
|
GUIContent[] options = optionsList.ToArray();
|
|
int index = 0;
|
|
for (int i = 0; i < lodGroup.lodCount; i++)
|
|
{
|
|
index = i * 4;
|
|
if (i >= 4)
|
|
index = (i - 4) * 4 + 1;
|
|
int lodIndex = (int)selectedPrototype.shadowLODMap[index];
|
|
selectedPrototype.shadowLODMap[index] = EditorGUILayout.Popup(GPUInstancerEditorConstants.Contents.shadowLODs[i],
|
|
lodIndex >= options.Length ? options.Length - 1 : lodIndex, options);
|
|
if (selectedPrototype.shadowLODMap[index] == options.Length - 1)
|
|
selectedPrototype.shadowLODMap[index] = 7;
|
|
}
|
|
}
|
|
|
|
selectedPrototype.cullShadows = EditorGUILayout.Toggle(GPUInstancerEditorConstants.TEXT_cullShadows, selectedPrototype.cullShadows);
|
|
DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_cullShadows);
|
|
}
|
|
}
|
|
|
|
EditorGUILayout.EndVertical();
|
|
#endregion Shadows
|
|
|
|
#region Culling
|
|
EditorGUILayout.BeginVertical(GPUInstancerEditorConstants.Styles.box);
|
|
GPUInstancerEditorConstants.DrawCustomLabel(GPUInstancerEditorConstants.TEXT_culling, GPUInstancerEditorConstants.Styles.boldLabel);
|
|
|
|
EditorGUILayout.MinMaxSlider(GPUInstancerEditorConstants.TEXT_maxDistance, ref selectedPrototype.minDistance, ref selectedPrototype.maxDistance, 0.0f, GetMaxDistance(selectedPrototype));
|
|
EditorGUILayout.BeginHorizontal();
|
|
selectedPrototype.minDistance = EditorGUILayout.FloatField(" ", selectedPrototype.minDistance);
|
|
selectedPrototype.maxDistance = EditorGUILayout.FloatField(selectedPrototype.maxDistance);
|
|
EditorGUILayout.EndHorizontal();
|
|
DrawHelpText(selectedPrototype is GPUInstancerDetailPrototype ? GPUInstancerEditorConstants.HELPTEXT_maxDistanceDetail : GPUInstancerEditorConstants.HELPTEXT_maxDistance);
|
|
|
|
if (isFrustumCulling)
|
|
{
|
|
selectedPrototype.isFrustumCulling = EditorGUILayout.Toggle(GPUInstancerEditorConstants.TEXT_isFrustumCulling, selectedPrototype.isFrustumCulling);
|
|
DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_isFrustumCulling);
|
|
if (selectedPrototype.isFrustumCulling)
|
|
{
|
|
selectedPrototype.frustumOffset = EditorGUILayout.Slider(GPUInstancerEditorConstants.TEXT_frustumOffset, selectedPrototype.frustumOffset, 0.0f, 0.5f);
|
|
DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_frustumOffset);
|
|
}
|
|
}
|
|
|
|
if (isOcclusionCulling)
|
|
{
|
|
selectedPrototype.isOcclusionCulling = EditorGUILayout.Toggle(GPUInstancerEditorConstants.TEXT_isOcclusionCulling, selectedPrototype.isOcclusionCulling);
|
|
DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_isOcclusionCulling);
|
|
if (selectedPrototype.isOcclusionCulling)
|
|
{
|
|
selectedPrototype.occlusionOffset = EditorGUILayout.Slider(GPUInstancerEditorConstants.TEXT_occlusionOffset, selectedPrototype.occlusionOffset, 0.0f, 0.1f);
|
|
DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_occlusionOffset);
|
|
selectedPrototype.occlusionAccuracy = EditorGUILayout.IntSlider(GPUInstancerEditorConstants.TEXT_occlusionAccuracy, selectedPrototype.occlusionAccuracy, 1, 3);
|
|
DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_occlusionAccuracy);
|
|
}
|
|
}
|
|
|
|
if (isFrustumCulling || isOcclusionCulling)
|
|
{
|
|
selectedPrototype.minCullingDistance = EditorGUILayout.Slider(GPUInstancerEditorConstants.TEXT_minCullingDistance, selectedPrototype.minCullingDistance, 0, 100);
|
|
DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_minCullingDistance);
|
|
}
|
|
EditorGUI.BeginDisabledGroup(Application.isPlaying);
|
|
selectedPrototype.boundsOffset = EditorGUILayout.Vector3Field(GPUInstancerEditorConstants.TEXT_boundsOffset, selectedPrototype.boundsOffset);
|
|
EditorGUI.EndDisabledGroup();
|
|
if (selectedPrototype.boundsOffset.x < 0)
|
|
selectedPrototype.boundsOffset.x = 0;
|
|
if (selectedPrototype.boundsOffset.y < 0)
|
|
selectedPrototype.boundsOffset.y = 0;
|
|
if (selectedPrototype.boundsOffset.z < 0)
|
|
selectedPrototype.boundsOffset.z = 0;
|
|
DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_boundsOffset);
|
|
|
|
EditorGUILayout.EndVertical();
|
|
#endregion Culling
|
|
|
|
#region LOD
|
|
if (selectedPrototype.prefabObject != null && (selectedPrototype.prefabObject.GetComponent<LODGroup>() != null || selectedPrototype.useGeneratedBillboard))
|
|
{
|
|
EditorGUILayout.BeginVertical(GPUInstancerEditorConstants.Styles.box);
|
|
GPUInstancerEditorConstants.DrawCustomLabel(GPUInstancerEditorConstants.TEXT_LOD, GPUInstancerEditorConstants.Styles.boldLabel);
|
|
|
|
EditorGUI.BeginDisabledGroup(Application.isPlaying);
|
|
if (GPUInstancerConstants.gpuiSettings.IsLODCrossFadeSupported())
|
|
{
|
|
selectedPrototype.isLODCrossFade = EditorGUILayout.Toggle(GPUInstancerEditorConstants.TEXT_isLODCrossFade, selectedPrototype.isLODCrossFade);
|
|
DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_isLODCrossFade);
|
|
|
|
if (selectedPrototype.isLODCrossFade)
|
|
{
|
|
selectedPrototype.isLODCrossFadeAnimate = EditorGUILayout.Toggle(GPUInstancerEditorConstants.TEXT_isLODCrossFadeAnimate, selectedPrototype.isLODCrossFadeAnimate);
|
|
DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_isLODCrossFadeAnimate);
|
|
|
|
if (!selectedPrototype.isLODCrossFadeAnimate)
|
|
{
|
|
selectedPrototype.lodFadeTransitionWidth = EditorGUILayout.Slider(GPUInstancerEditorConstants.TEXT_lodFadeTransitionWidth, selectedPrototype.lodFadeTransitionWidth, 0.0f, 1.0f);
|
|
DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_lodFadeTransitionWidth);
|
|
}
|
|
|
|
//if (GPUInstancerConstants.gpuiSettings.isURP)
|
|
//{
|
|
// EditorGUILayout.HelpBox("URP shaders require to be compatible with LOD cross-fading by using the LODDitheringTransition method (e.g. SpeedTree8 shader). Custom cross-fading implementations will not work out of the box with GPUI.", MessageType.Warning);
|
|
//}
|
|
}
|
|
}
|
|
else if (selectedPrototype.isLODCrossFade)
|
|
selectedPrototype.isLODCrossFade = false;
|
|
|
|
selectedPrototype.lodBiasAdjustment = EditorGUILayout.FloatField(GPUInstancerEditorConstants.TEXT_lodBiasAdjustment, selectedPrototype.lodBiasAdjustment);
|
|
DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_lodBiasAdjustment);
|
|
EditorGUI.EndDisabledGroup();
|
|
|
|
EditorGUILayout.EndVertical();
|
|
}
|
|
else if (selectedPrototype.isLODCrossFade)
|
|
selectedPrototype.isLODCrossFade = false;
|
|
#endregion LOD
|
|
|
|
EditorGUI.BeginDisabledGroup(Application.isPlaying);
|
|
DrawGPUInstancerPrototypeInfo(selectedPrototype);
|
|
|
|
DrawGPUInstancerPrototypeBillboardSettings(selectedPrototype);
|
|
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
if (selectedPrototype != null)
|
|
EditorUtility.SetDirty(selectedPrototype);
|
|
}
|
|
|
|
DrawGPUInstancerPrototypeActions();
|
|
DrawGPUInstancerPrototypeAdvancedActions();
|
|
|
|
EditorGUI.EndDisabledGroup();
|
|
EditorGUILayout.EndVertical();
|
|
}
|
|
|
|
public virtual void DrawGPUInstancerPrototypeBillboardSettings(GPUInstancerPrototype selectedPrototype)
|
|
{
|
|
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.checkedForBillboardExtensions)
|
|
{
|
|
selectedPrototype.checkedForBillboardExtensions = true;
|
|
if (CheckForBillboardExtensions(selectedPrototype))
|
|
return;
|
|
}
|
|
|
|
EditorGUILayout.BeginVertical(GPUInstancerEditorConstants.Styles.box);
|
|
|
|
GPUInstancerEditorConstants.DrawCustomLabel(GPUInstancerEditorConstants.TEXT_billboardSettings, GPUInstancerEditorConstants.Styles.boldLabel);
|
|
|
|
// This is for the special case of importing a prototype with a billboard generated in the Standard Pipeline into an SRP project.
|
|
if (!GPUInstancerConstants.gpuiSettings.IsBillboardsSupported() && selectedPrototype.useGeneratedBillboard && !selectedPrototype.billboard.useCustomBillboard)
|
|
selectedPrototype.useGeneratedBillboard = false;
|
|
|
|
bool previousUseGeneratedBillboard = selectedPrototype.useGeneratedBillboard;
|
|
selectedPrototype.useGeneratedBillboard = EditorGUILayout.Toggle(GPUInstancerEditorConstants.TEXT_useGeneratedBillboard, selectedPrototype.useGeneratedBillboard);
|
|
DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_useGeneratedBillboard);
|
|
|
|
if (previousUseGeneratedBillboard && !selectedPrototype.useGeneratedBillboard)
|
|
{
|
|
GPUInstancerConstants.gpuiSettings.billboardAtlasBindings.DeleteBillboardTextures(selectedPrototype);
|
|
}
|
|
|
|
if (selectedPrototype.useGeneratedBillboard && selectedPrototype.billboard == null)
|
|
selectedPrototype.billboard = new GPUInstancerBillboard();
|
|
else if (!selectedPrototype.useGeneratedBillboard && selectedPrototype.billboard != null)
|
|
{
|
|
if (selectedPrototype.billboard != null && !selectedPrototype.billboard.useCustomBillboard)
|
|
selectedPrototype.billboard = null;
|
|
}
|
|
|
|
if (selectedPrototype.useGeneratedBillboard)
|
|
{
|
|
if (!GPUInstancerConstants.gpuiSettings.IsBillboardsSupported())
|
|
selectedPrototype.billboard.useCustomBillboard = true;
|
|
|
|
if (selectedPrototype.treeType != GPUInstancerTreeType.SpeedTree && selectedPrototype.treeType != GPUInstancerTreeType.SpeedTree8
|
|
&& selectedPrototype.treeType != GPUInstancerTreeType.TreeCreatorTree && selectedPrototype.treeType != GPUInstancerTreeType.SoftOcclusionTree
|
|
&& !selectedPrototype.billboard.useCustomBillboard)
|
|
EditorGUILayout.HelpBox(GPUInstancerEditorConstants.HELPTEXT_unsupportedBillboardWarning, MessageType.Warning);
|
|
|
|
if (selectedPrototype.treeType == GPUInstancerTreeType.SpeedTree8)
|
|
EditorGUILayout.HelpBox(GPUInstancerEditorConstants.HELPTEXT_speedtree8BillboardReplacementInfo, MessageType.Info);
|
|
|
|
bool previousUseCustomBillboard = selectedPrototype.billboard.useCustomBillboard;
|
|
|
|
if (!GPUInstancerConstants.gpuiSettings.IsBillboardsSupported())
|
|
EditorGUILayout.HelpBox("Generated billboards are not supported in SRP versions prior to 10.x. You can assign a custom billboard material and mesh to use as the final LOD for your prototype below.", MessageType.Warning);
|
|
else
|
|
{
|
|
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)
|
|
GPUInstancerConstants.gpuiSettings.billboardAtlasBindings.DeleteBillboardTextures(selectedPrototype);
|
|
|
|
|
|
if (GPUInstancerConstants.gpuiSettings != null && GPUInstancerConstants.gpuiSettings.shaderBindings != null && selectedPrototype.billboard.customBillboardMaterial != null)
|
|
{
|
|
if (!GPUInstancerConstants.gpuiSettings.shaderBindings.IsShadersInstancedVersionExists(selectedPrototype.billboard.customBillboardMaterial.shader.name))
|
|
{
|
|
Shader instancedShader = GPUInstancerUtility.CreateInstancedShader(selectedPrototype.billboard.customBillboardMaterial.shader);
|
|
if (instancedShader != null)
|
|
GPUInstancerConstants.gpuiSettings.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 != null && selectedPrototype.prefabObject.GetComponent<LODGroup>() != null;
|
|
bool speedTreeBillboard = (selectedPrototype.treeType == GPUInstancerTreeType.SpeedTree || selectedPrototype.treeType == GPUInstancerTreeType.SpeedTree8) && hasLODGroup
|
|
&& (selectedPrototype.treeType == GPUInstancerTreeType.SpeedTree8 || 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 (!GPUInstancerConstants.gpuiSettings.IsStandardRenderPipeline())
|
|
{
|
|
selectedPrototype.billboard.normalStrength = EditorGUILayout.Slider(GPUInstancerEditorConstants.TEXT_billboardNormalStrength, selectedPrototype.billboard.normalStrength, 0.0f, 8.0f);
|
|
DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_billboardNormalStrength);
|
|
}
|
|
|
|
if (selectedPrototype.billboard.albedoAtlasTexture == null)
|
|
GPUInstancerUtility.AssignBillboardBinding(selectedPrototype);
|
|
|
|
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, selectedPrototype.billboard.albedoAtlasTexture != null);
|
|
GUIUtility.ExitGUI();
|
|
});
|
|
}
|
|
|
|
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.prefabObject != null && selectedPrototype.useGeneratedBillboard && selectedPrototype.billboard != null && selectedPrototype.billboard.useCustomBillboard && GPUInstancerDefines.billboardExtensions != null && GPUInstancerDefines.billboardExtensions.Count > 0)
|
|
{
|
|
GUILayout.Space(10);
|
|
|
|
EditorGUILayout.BeginVertical(GPUInstancerEditorConstants.Styles.box);
|
|
|
|
GPUInstancerEditorConstants.DrawCustomLabel("External Billboard Generators", GPUInstancerEditorConstants.Styles.boldLabel);
|
|
|
|
GUILayout.Space(5);
|
|
|
|
foreach (Extension.GPUInstancerBillboardExtension billboardExtension in GPUInstancerDefines.billboardExtensions)
|
|
{
|
|
try
|
|
{
|
|
EditorGUILayout.BeginHorizontal();
|
|
GUILayout.Label(billboardExtension.GetTitle(), GPUInstancerEditorConstants.Styles.label);
|
|
|
|
GPUInstancerEditorConstants.DrawColoredButton(new GUIContent(billboardExtension.GetButtonText()), GPUInstancerEditorConstants.Colors.green, Color.white, FontStyle.Bold, Rect.zero,
|
|
() =>
|
|
{
|
|
_redirectObject = billboardExtension.GenerateBillboard(selectedPrototype.prefabObject);
|
|
selectedPrototype.checkedForBillboardExtensions = 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 virtual bool DrawGPUInstancerPrototypeBillboardSettings(List<GPUInstancerPrototype> selectedPrototypeList)
|
|
{
|
|
foreach (var selectedPrototype in selectedPrototypeList)
|
|
{
|
|
if (selectedPrototype.isBillboardDisabled || (selectedPrototype is GPUInstancerDetailPrototype && !((GPUInstancerDetailPrototype)selectedPrototype).usePrototypeMesh))
|
|
{
|
|
if (selectedPrototype.useGeneratedBillboard)
|
|
selectedPrototype.useGeneratedBillboard = false;
|
|
if (selectedPrototype.billboard != null)
|
|
selectedPrototype.billboard = null;
|
|
|
|
// This is for the special case of importing a prototype with a billboard generated in the Standard Pipeline into an SRP project.
|
|
if (!GPUInstancerConstants.gpuiSettings.IsBillboardsSupported() && selectedPrototype.useGeneratedBillboard && !selectedPrototype.billboard.useCustomBillboard)
|
|
selectedPrototype.useGeneratedBillboard = false;
|
|
}
|
|
|
|
if (Event.current.type == EventType.Repaint && !selectedPrototype.checkedForBillboardExtensions)
|
|
{
|
|
selectedPrototype.checkedForBillboardExtensions = true;
|
|
CheckForBillboardExtensions(selectedPrototype);
|
|
}
|
|
|
|
if (selectedPrototype.useGeneratedBillboard && selectedPrototype.billboard == null)
|
|
selectedPrototype.billboard = new GPUInstancerBillboard();
|
|
else if (!selectedPrototype.useGeneratedBillboard && selectedPrototype.billboard != null)
|
|
{
|
|
if (selectedPrototype.billboard != null && !selectedPrototype.billboard.useCustomBillboard)
|
|
selectedPrototype.billboard = null;
|
|
}
|
|
|
|
if (selectedPrototype.billboard != null)
|
|
{
|
|
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;
|
|
}
|
|
|
|
if (selectedPrototype.billboard.albedoAtlasTexture == null)
|
|
GPUInstancerUtility.AssignBillboardBinding(selectedPrototype);
|
|
}
|
|
}
|
|
|
|
GPUInstancerPrototype prototype0 = selectedPrototypeList[0];
|
|
bool hasChanged = false;
|
|
bool isUseGeneratedBillboardMixed = false;
|
|
bool isUseGeneratedBillboard = prototype0.useGeneratedBillboard;
|
|
for (int i = 1; i < selectedPrototypeList.Count; i++)
|
|
{
|
|
if (!isUseGeneratedBillboardMixed && isUseGeneratedBillboard != selectedPrototypeList[i].useGeneratedBillboard)
|
|
isUseGeneratedBillboardMixed = true;
|
|
}
|
|
|
|
EditorGUILayout.BeginVertical(GPUInstancerEditorConstants.Styles.box);
|
|
|
|
GPUInstancerEditorConstants.DrawCustomLabel(GPUInstancerEditorConstants.TEXT_billboardSettings, GPUInstancerEditorConstants.Styles.boldLabel);
|
|
|
|
hasChanged |= MultiToggle(selectedPrototypeList, GPUInstancerEditorConstants.TEXT_useGeneratedBillboard, isUseGeneratedBillboard, isUseGeneratedBillboardMixed, (p, v) => p.useGeneratedBillboard = v);
|
|
DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_useGeneratedBillboard);
|
|
|
|
if (!isUseGeneratedBillboardMixed && isUseGeneratedBillboard && prototype0.billboard != null)
|
|
{
|
|
bool isUseCustomBillboardMixed = false;
|
|
bool isUseCustomBillboard = prototype0.billboard.useCustomBillboard;
|
|
bool isBillboardQualityMixed = false;
|
|
BillboardQuality billboardQuality = prototype0.billboard.billboardQuality;
|
|
bool isFrameCountMixed = false;
|
|
int frameCount = prototype0.billboard.frameCount;
|
|
bool isBillboardBrightnessMixed = false;
|
|
float billboardBrightness = prototype0.billboard.billboardBrightness;
|
|
bool isReplaceLODCullWithBillboardMixed = false;
|
|
bool replaceLODCullWithBillboard = prototype0.billboard.replaceLODCullWithBillboard;
|
|
bool isBillboardDistanceMixed = false;
|
|
float billboardDistance = prototype0.billboard.billboardDistance;
|
|
bool isBillboardFaceCamPosMixed = false;
|
|
bool billboardFaceCamPos = prototype0.billboard.billboardFaceCamPos;
|
|
bool isNormalStrengthMixed = false;
|
|
float normalStrength = prototype0.billboard.normalStrength;
|
|
for (int i = 1; i < selectedPrototypeList.Count; i++)
|
|
{
|
|
if (!isUseCustomBillboardMixed && isUseCustomBillboard != selectedPrototypeList[i].billboard.useCustomBillboard)
|
|
isUseCustomBillboardMixed = true;
|
|
if (!isBillboardQualityMixed && billboardQuality != selectedPrototypeList[i].billboard.billboardQuality)
|
|
isBillboardQualityMixed = true;
|
|
if (!isFrameCountMixed && frameCount != selectedPrototypeList[i].billboard.frameCount)
|
|
isFrameCountMixed = true;
|
|
if (!isBillboardBrightnessMixed && billboardBrightness != selectedPrototypeList[i].billboard.billboardBrightness)
|
|
isBillboardBrightnessMixed = true;
|
|
if (!isReplaceLODCullWithBillboardMixed && replaceLODCullWithBillboard != selectedPrototypeList[i].billboard.replaceLODCullWithBillboard)
|
|
isReplaceLODCullWithBillboardMixed = true;
|
|
if (!isBillboardDistanceMixed && billboardDistance != selectedPrototypeList[i].billboard.billboardDistance)
|
|
isBillboardDistanceMixed = true;
|
|
if (!isBillboardFaceCamPosMixed && billboardFaceCamPos != selectedPrototypeList[i].billboard.billboardFaceCamPos)
|
|
isBillboardFaceCamPosMixed = true;
|
|
if (!isNormalStrengthMixed && normalStrength != selectedPrototypeList[i].billboard.normalStrength)
|
|
isNormalStrengthMixed = true;
|
|
}
|
|
|
|
hasChanged |= MultiToggle(selectedPrototypeList, GPUInstancerEditorConstants.TEXT_useCustomBillboard, isUseCustomBillboard, isUseCustomBillboardMixed, (p, v) => p.billboard.useCustomBillboard = v);
|
|
DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_useCustomBillboard);
|
|
|
|
if (!isUseCustomBillboardMixed && !isUseCustomBillboard)
|
|
{
|
|
hasChanged |= MultiPopup(selectedPrototypeList, GPUInstancerEditorConstants.TEXT_billboardQuality, (int)billboardQuality, GPUInstancerEditorConstants.TEXT_BillboardQualityOptions, isBillboardQualityMixed, (p, v) => p.billboard.billboardQuality = (BillboardQuality)v);
|
|
DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_billboardQuality);
|
|
|
|
hasChanged |= MultiIntSlider(selectedPrototypeList, GPUInstancerEditorConstants.TEXT_billboardFrameCount, frameCount, 8, 32, isFrameCountMixed, (p, v) => p.billboard.frameCount = Mathf.NextPowerOfTwo(v));
|
|
DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_billboardFrameCount);
|
|
|
|
hasChanged |= MultiSlider(selectedPrototypeList, GPUInstancerEditorConstants.TEXT_billboardBrightness, billboardBrightness, 0.0f, 1.0f, isBillboardBrightnessMixed, (p, v) => p.billboard.billboardBrightness = v);
|
|
DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_billboardBrightness);
|
|
|
|
if (prototype0.prefabObject != null && prototype0.prefabObject.GetComponent<LODGroup>() != null)
|
|
{
|
|
hasChanged |= MultiToggle(selectedPrototypeList, GPUInstancerEditorConstants.TEXT_replaceLODCull, replaceLODCullWithBillboard, isReplaceLODCullWithBillboardMixed, (p, v) => p.billboard.replaceLODCullWithBillboard = v);
|
|
DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_replaceLODCull);
|
|
}
|
|
|
|
hasChanged |= MultiSlider(selectedPrototypeList, GPUInstancerEditorConstants.TEXT_generatedBillboardDistance, billboardDistance, 0.01f, 1f, isBillboardDistanceMixed, (p, v) => p.billboard.billboardDistance = v);
|
|
DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_generatedBillboardDistance);
|
|
|
|
hasChanged |= MultiToggle(selectedPrototypeList, GPUInstancerEditorConstants.TEXT_billboardFaceCamPos, billboardFaceCamPos, isBillboardFaceCamPosMixed, (p, v) => p.billboard.billboardFaceCamPos = v);
|
|
DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_billboardFaceCamPos);
|
|
|
|
if (!GPUInstancerConstants.gpuiSettings.IsStandardRenderPipeline())
|
|
{
|
|
hasChanged |= MultiSlider(selectedPrototypeList, GPUInstancerEditorConstants.TEXT_billboardNormalStrength, normalStrength, 0.0f, 8.0f, isNormalStrengthMixed, (p, v) => p.billboard.normalStrength = v);
|
|
DrawHelpText(GPUInstancerEditorConstants.HELPTEXT_billboardNormalStrength);
|
|
}
|
|
}
|
|
}
|
|
|
|
EditorGUILayout.EndVertical();
|
|
|
|
return hasChanged;
|
|
}
|
|
|
|
public void DrawHelpText(string text, bool forceShow = false)
|
|
{
|
|
if (showHelpText || forceShow)
|
|
{
|
|
EditorGUILayout.HelpBox(text, MessageType.Info);
|
|
}
|
|
}
|
|
|
|
public static void DrawWikiButton(Rect buttonRect, string hash)
|
|
{
|
|
DrawWikiButton(buttonRect, "GPU_Instancer:GettingStarted", hash, "Wiki", GPUInstancerEditorConstants.Colors.lightBlue);
|
|
}
|
|
|
|
public static void DrawWikiButton(Rect buttonRect, string title, string hash, string buttonText, Color buttonColor)
|
|
{
|
|
GPUInstancerEditorConstants.DrawColoredButton(new GUIContent(buttonText),
|
|
buttonColor, Color.white, FontStyle.Bold, buttonRect,
|
|
() => { Application.OpenURL("https://wiki.gurbu.com/index.php?title=" + title + hash); }
|
|
);
|
|
}
|
|
|
|
public void DrawHelpButton(Rect buttonRect, bool showingHelp)
|
|
{
|
|
if (GUI.Button(buttonRect, new GUIContent(showHelpText ? helpIconActive : helpIcon,
|
|
showHelpText ? GPUInstancerEditorConstants.TEXT_hideHelpTooltip : GPUInstancerEditorConstants.TEXT_showHelpTooltip), showHelpText ? GPUInstancerEditorConstants.Styles.helpButtonSelected : GPUInstancerEditorConstants.Styles.helpButton))
|
|
{
|
|
showHelpText = !showHelpText;
|
|
}
|
|
}
|
|
|
|
public abstract bool DrawGPUInstancerPrototypeInfo(List<GPUInstancerPrototype> selectedPrototypeList);
|
|
public abstract void DrawGPUInstancerPrototypeInfo(GPUInstancerPrototype selectedPrototype);
|
|
public virtual bool DrawGPUInstancerPrototypeBeginningInfo(List<GPUInstancerPrototype> selectedPrototypeList) { return false; }
|
|
public virtual void DrawGPUInstancerPrototypeBeginningInfo(GPUInstancerPrototype selectedPrototype) { }
|
|
public abstract void DrawGPUInstancerPrototypeActions();
|
|
public virtual void DrawGPUInstancerPrototypeAdvancedActions() { }
|
|
public abstract float GetMaxDistance(GPUInstancerPrototype selectedPrototype);
|
|
|
|
public static bool CheckForBillboardExtensions(GPUInstancerPrototype selectedPrototype)
|
|
{
|
|
bool hasExtensionBillboard = false;
|
|
if (GPUInstancerDefines.billboardExtensions != null && GPUInstancerDefines.billboardExtensions.Count > 0)
|
|
{
|
|
foreach (Extension.GPUInstancerBillboardExtension billboardExtension in GPUInstancerDefines.billboardExtensions)
|
|
{
|
|
try
|
|
{
|
|
if (billboardExtension.IsBillboardAdded(selectedPrototype.prefabObject))
|
|
{
|
|
Mesh generatedMesh = billboardExtension.GetBillboardMesh(selectedPrototype.prefabObject);
|
|
Material generatedMaterial = billboardExtension.GetBillboardMaterial(selectedPrototype.prefabObject);
|
|
bool isInLODGroup = billboardExtension.IsInLODGroup(selectedPrototype.prefabObject);
|
|
if (generatedMesh != null && generatedMaterial != null)
|
|
{
|
|
if (selectedPrototype.billboard == null)
|
|
selectedPrototype.billboard = new GPUInstancerBillboard();
|
|
|
|
selectedPrototype.useGeneratedBillboard = true;
|
|
selectedPrototype.billboard.useCustomBillboard = true;
|
|
selectedPrototype.billboard.customBillboardInLODGroup = isInLODGroup;
|
|
selectedPrototype.billboard.customBillboardMesh = generatedMesh;
|
|
selectedPrototype.billboard.customBillboardMaterial = generatedMaterial;
|
|
|
|
hasExtensionBillboard = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
catch (System.Exception e)
|
|
{
|
|
EditorUtility.ClearProgressBar();
|
|
Debug.LogError("Error generating billboard: " + e.Message + " StackTrace:" + e.StackTrace);
|
|
}
|
|
}
|
|
}
|
|
return hasExtensionBillboard;
|
|
}
|
|
|
|
public virtual void DrawPrefabField(GPUInstancerPrototype selectedPrototype)
|
|
{
|
|
EditorGUI.BeginDisabledGroup(true);
|
|
EditorGUILayout.ObjectField(GPUInstancerEditorConstants.TEXT_prefabObject, selectedPrototype.prefabObject, typeof(GameObject), false);
|
|
EditorGUI.EndDisabledGroup();
|
|
}
|
|
|
|
public static bool MultiToggle(List<GPUInstancerPrototype> selectedPrototypeList, string text, bool value, bool isMixed, UnityAction<GPUInstancerPrototype, bool> prototypeAction)
|
|
{
|
|
bool hasChanged = false;
|
|
EditorGUI.showMixedValue = isMixed;
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
value = EditorGUILayout.Toggle(text, value);
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
for (int i = 0; i < selectedPrototypeList.Count; i++)
|
|
{
|
|
prototypeAction(selectedPrototypeList[i], value);
|
|
}
|
|
hasChanged = true;
|
|
}
|
|
EditorGUI.showMixedValue = false;
|
|
|
|
return hasChanged;
|
|
}
|
|
|
|
public static bool MultiSlider(List<GPUInstancerPrototype> selectedPrototypeList, string text, float value, float leftValue, float rightValue, bool isMixed, UnityAction<GPUInstancerPrototype, float> prototypeAction)
|
|
{
|
|
bool hasChanged = false;
|
|
EditorGUI.showMixedValue = isMixed;
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
value = EditorGUILayout.Slider(text, value, leftValue, rightValue);
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
for (int i = 0; i < selectedPrototypeList.Count; i++)
|
|
{
|
|
prototypeAction(selectedPrototypeList[i], value);
|
|
}
|
|
hasChanged = true;
|
|
}
|
|
EditorGUI.showMixedValue = false;
|
|
|
|
return hasChanged;
|
|
}
|
|
|
|
public static bool MultiMinMaxSlider(List<GPUInstancerPrototype> selectedPrototypeList, string text, float minValue, float maxValue, float minLimit, float maxLimit, bool isMixed, UnityAction<GPUInstancerPrototype, float, float> prototypeAction)
|
|
{
|
|
bool hasChanged = false;
|
|
EditorGUI.showMixedValue = isMixed;
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
EditorGUILayout.MinMaxSlider(text, ref minValue, ref maxValue, minLimit, maxLimit);
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
for (int i = 0; i < selectedPrototypeList.Count; i++)
|
|
{
|
|
prototypeAction(selectedPrototypeList[i], minValue, maxValue);
|
|
}
|
|
hasChanged = true;
|
|
}
|
|
EditorGUI.showMixedValue = false;
|
|
|
|
return hasChanged;
|
|
}
|
|
|
|
public static bool MultiIntSlider(List<GPUInstancerPrototype> selectedPrototypeList, string text, int value, int leftValue, int rightValue, bool isMixed, UnityAction<GPUInstancerPrototype, int> prototypeAction)
|
|
{
|
|
bool hasChanged = false;
|
|
EditorGUI.showMixedValue = isMixed;
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
value = EditorGUILayout.IntSlider(text, value, leftValue, rightValue);
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
for (int i = 0; i < selectedPrototypeList.Count; i++)
|
|
{
|
|
prototypeAction(selectedPrototypeList[i], value);
|
|
}
|
|
hasChanged = true;
|
|
}
|
|
EditorGUI.showMixedValue = false;
|
|
|
|
return hasChanged;
|
|
}
|
|
|
|
public static bool MultiVector4(List<GPUInstancerPrototype> selectedPrototypeList, string text, Vector4 value, bool isMixed, UnityAction<GPUInstancerPrototype, Vector4> prototypeAction)
|
|
{
|
|
bool hasChanged = false;
|
|
EditorGUI.showMixedValue = isMixed;
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
value = EditorGUILayout.Vector4Field(text, value);
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
for (int i = 0; i < selectedPrototypeList.Count; i++)
|
|
{
|
|
prototypeAction(selectedPrototypeList[i], value);
|
|
}
|
|
hasChanged = true;
|
|
}
|
|
EditorGUI.showMixedValue = false;
|
|
|
|
return hasChanged;
|
|
}
|
|
|
|
public static bool MultiFloat(List<GPUInstancerPrototype> selectedPrototypeList, string text, float value, bool isMixed, UnityAction<GPUInstancerPrototype, float> prototypeAction)
|
|
{
|
|
bool hasChanged = false;
|
|
EditorGUI.showMixedValue = isMixed;
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
if (text == null)
|
|
value = EditorGUILayout.FloatField(value);
|
|
else
|
|
value = EditorGUILayout.FloatField(text, value);
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
for (int i = 0; i < selectedPrototypeList.Count; i++)
|
|
{
|
|
prototypeAction(selectedPrototypeList[i], value);
|
|
}
|
|
hasChanged = true;
|
|
}
|
|
EditorGUI.showMixedValue = false;
|
|
|
|
return hasChanged;
|
|
}
|
|
|
|
public static bool MultiColor(List<GPUInstancerPrototype> selectedPrototypeList, string text, Color value, bool isMixed, UnityAction<GPUInstancerPrototype, Color> prototypeAction)
|
|
{
|
|
bool hasChanged = false;
|
|
EditorGUI.showMixedValue = isMixed;
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
value = EditorGUILayout.ColorField(text, value);
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
for (int i = 0; i < selectedPrototypeList.Count; i++)
|
|
{
|
|
prototypeAction(selectedPrototypeList[i], value);
|
|
}
|
|
hasChanged = true;
|
|
}
|
|
EditorGUI.showMixedValue = false;
|
|
|
|
return hasChanged;
|
|
}
|
|
|
|
public static bool MultiVector3(List<GPUInstancerPrototype> selectedPrototypeList, string text, Vector3 value, bool isMixed, bool acceptNegative, UnityAction<GPUInstancerPrototype, Vector3> prototypeAction)
|
|
{
|
|
bool hasChanged = false;
|
|
EditorGUI.showMixedValue = isMixed;
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
value = EditorGUILayout.Vector3Field(text, value);
|
|
if (!acceptNegative)
|
|
{
|
|
if (value.x < 0)
|
|
value.x = 0;
|
|
if (value.y < 0)
|
|
value.y = 0;
|
|
if (value.z < 0)
|
|
value.z = 0;
|
|
}
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
for (int i = 0; i < selectedPrototypeList.Count; i++)
|
|
{
|
|
prototypeAction(selectedPrototypeList[i], value);
|
|
}
|
|
hasChanged = true;
|
|
}
|
|
EditorGUI.showMixedValue = false;
|
|
|
|
return hasChanged;
|
|
}
|
|
|
|
public static bool MultiPopup(List<GPUInstancerPrototype> selectedPrototypeList, string text, int value, string[] options, bool isMixed, UnityAction<GPUInstancerPrototype, int> prototypeAction)
|
|
{
|
|
bool hasChanged = false;
|
|
EditorGUI.showMixedValue = isMixed;
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
value = EditorGUILayout.Popup(text, value, options);
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
for (int i = 0; i < selectedPrototypeList.Count; i++)
|
|
{
|
|
prototypeAction(selectedPrototypeList[i], value);
|
|
}
|
|
hasChanged = true;
|
|
}
|
|
EditorGUI.showMixedValue = false;
|
|
|
|
return hasChanged;
|
|
}
|
|
}
|
|
}
|