chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,577 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using MCPForUnity.Editor.Helpers;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
using MCPForUnity.Runtime.Helpers;
|
||||
|
||||
namespace MCPForUnity.Editor.Tools.Graphics
|
||||
{
|
||||
internal static class RendererFeatureOps
|
||||
{
|
||||
// Cached URP types (resolved via reflection to avoid hard dependency)
|
||||
private static Type _scriptableRendererDataType;
|
||||
private static Type _scriptableRendererFeatureType;
|
||||
private static Type _universalRenderPipelineAssetType;
|
||||
private static bool _typesResolved;
|
||||
|
||||
private static void EnsureTypes()
|
||||
{
|
||||
if (_typesResolved) return;
|
||||
_typesResolved = true;
|
||||
|
||||
_scriptableRendererDataType = Type.GetType(
|
||||
"UnityEngine.Rendering.Universal.ScriptableRendererData, Unity.RenderPipelines.Universal.Runtime");
|
||||
_scriptableRendererFeatureType = Type.GetType(
|
||||
"UnityEngine.Rendering.Universal.ScriptableRendererFeature, Unity.RenderPipelines.Universal.Runtime");
|
||||
_universalRenderPipelineAssetType = Type.GetType(
|
||||
"UnityEngine.Rendering.Universal.UniversalRenderPipelineAsset, Unity.RenderPipelines.Universal.Runtime");
|
||||
}
|
||||
|
||||
// === feature_list ===
|
||||
internal static object ListFeatures(JObject @params)
|
||||
{
|
||||
var rendererData = GetRendererData(@params);
|
||||
if (rendererData == null)
|
||||
return new ErrorResponse("Could not find URP ScriptableRendererData. Ensure URP is active.");
|
||||
|
||||
var featuresProp = rendererData.GetType().GetProperty("rendererFeatures",
|
||||
BindingFlags.Public | BindingFlags.Instance);
|
||||
if (featuresProp == null)
|
||||
return new ErrorResponse("rendererFeatures property not found on renderer data.");
|
||||
|
||||
var featuresList = featuresProp.GetValue(rendererData) as System.Collections.IList;
|
||||
if (featuresList == null)
|
||||
return new { success = true, message = "No renderer features.", data = new { features = new object[0] } };
|
||||
|
||||
var features = new List<object>();
|
||||
for (int i = 0; i < featuresList.Count; i++)
|
||||
{
|
||||
var feature = featuresList[i] as ScriptableObject;
|
||||
if (feature == null) continue;
|
||||
|
||||
var isActiveProp = feature.GetType().GetProperty("isActive",
|
||||
BindingFlags.Public | BindingFlags.Instance);
|
||||
|
||||
features.Add(new
|
||||
{
|
||||
index = i,
|
||||
name = feature.name,
|
||||
type = feature.GetType().Name,
|
||||
isActive = isActiveProp != null ? (bool)isActiveProp.GetValue(feature) : true,
|
||||
properties = GetFeatureProperties(feature)
|
||||
});
|
||||
}
|
||||
|
||||
return new
|
||||
{
|
||||
success = true,
|
||||
message = $"Found {features.Count} renderer feature(s).",
|
||||
data = new
|
||||
{
|
||||
rendererDataName = (rendererData as ScriptableObject)?.name,
|
||||
features
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// === feature_add ===
|
||||
internal static object AddFeature(JObject @params)
|
||||
{
|
||||
var p = new ToolParams(@params);
|
||||
string typeName = p.Get("type");
|
||||
if (string.IsNullOrEmpty(typeName))
|
||||
return new ErrorResponse("'type' parameter required (e.g., 'FullScreenPassRendererFeature', 'RenderObjects').");
|
||||
|
||||
var rendererData = GetRendererData(@params);
|
||||
if (rendererData == null)
|
||||
return new ErrorResponse("Could not find URP ScriptableRendererData.");
|
||||
|
||||
EnsureTypes();
|
||||
if (_scriptableRendererFeatureType == null)
|
||||
return new ErrorResponse("ScriptableRendererFeature type not found. Is URP installed?");
|
||||
|
||||
// Resolve the feature type
|
||||
var featureType = ResolveFeatureType(typeName);
|
||||
if (featureType == null)
|
||||
{
|
||||
var available = GetAvailableFeatureTypes();
|
||||
return new ErrorResponse(
|
||||
$"Feature type '{typeName}' not found. Available: {string.Join(", ", available.Select(t => t.Name))}");
|
||||
}
|
||||
|
||||
// Create the feature instance
|
||||
var feature = ScriptableObject.CreateInstance(featureType);
|
||||
if (feature == null)
|
||||
return new ErrorResponse($"Failed to create instance of '{featureType.Name}'.");
|
||||
|
||||
string displayName = p.Get("name") ?? featureType.Name;
|
||||
feature.name = displayName;
|
||||
|
||||
// Add to the renderer data asset
|
||||
Undo.RecordObject(rendererData as UnityEngine.Object, "Add Renderer Feature");
|
||||
AssetDatabase.AddObjectToAsset(feature, rendererData as UnityEngine.Object);
|
||||
|
||||
// Add to the features list via SerializedObject
|
||||
using (var so = new SerializedObject(rendererData as UnityEngine.Object))
|
||||
{
|
||||
var rendererFeaturesProp = so.FindProperty("m_RendererFeatures");
|
||||
if (rendererFeaturesProp != null)
|
||||
{
|
||||
rendererFeaturesProp.arraySize++;
|
||||
var element = rendererFeaturesProp.GetArrayElementAtIndex(rendererFeaturesProp.arraySize - 1);
|
||||
element.objectReferenceValue = feature;
|
||||
so.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
// Also update the map (m_RendererFeatureMap) if it exists
|
||||
// Map stores persistent local file IDs, not transient instance IDs
|
||||
var mapProp = so.FindProperty("m_RendererFeatureMap");
|
||||
if (mapProp != null)
|
||||
{
|
||||
long localId = 0;
|
||||
AssetDatabase.TryGetGUIDAndLocalFileIdentifier(feature, out _, out localId);
|
||||
mapProp.arraySize++;
|
||||
var mapElement = mapProp.GetArrayElementAtIndex(mapProp.arraySize - 1);
|
||||
mapElement.longValue = localId;
|
||||
so.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
|
||||
// Configure initial properties if provided
|
||||
var propertiesToken = p.GetRaw("properties") as JObject;
|
||||
if (propertiesToken != null)
|
||||
ApplyFeatureProperties(feature, propertiesToken);
|
||||
|
||||
// Set material if provided (common for FullScreenPass)
|
||||
string materialPath = p.Get("material");
|
||||
if (!string.IsNullOrEmpty(materialPath))
|
||||
TrySetMaterial(feature, materialPath);
|
||||
|
||||
EditorUtility.SetDirty(rendererData as UnityEngine.Object);
|
||||
AssetDatabase.SaveAssets();
|
||||
|
||||
return new
|
||||
{
|
||||
success = true,
|
||||
message = $"Added renderer feature '{displayName}' ({featureType.Name}).",
|
||||
data = new
|
||||
{
|
||||
name = displayName,
|
||||
type = featureType.Name,
|
||||
instanceId = feature.GetInstanceIDCompat()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// === feature_remove ===
|
||||
internal static object RemoveFeature(JObject @params)
|
||||
{
|
||||
var p = new ToolParams(@params);
|
||||
int? index = p.GetInt("index");
|
||||
string name = p.Get("name");
|
||||
|
||||
var rendererData = GetRendererData(@params);
|
||||
if (rendererData == null)
|
||||
return new ErrorResponse("Could not find URP ScriptableRendererData.");
|
||||
|
||||
var featuresProp = rendererData.GetType().GetProperty("rendererFeatures",
|
||||
BindingFlags.Public | BindingFlags.Instance);
|
||||
if (featuresProp == null)
|
||||
return new ErrorResponse("rendererFeatures property not found.");
|
||||
|
||||
var featuresList = featuresProp.GetValue(rendererData) as System.Collections.IList;
|
||||
if (featuresList == null || featuresList.Count == 0)
|
||||
return new ErrorResponse("No renderer features to remove.");
|
||||
|
||||
int targetIndex = ResolveFeatureIndex(featuresList, index, name);
|
||||
if (targetIndex < 0)
|
||||
return new ErrorResponse($"Feature not found. Specify 'index' (0-{featuresList.Count - 1}) or 'name'.");
|
||||
|
||||
var feature = featuresList[targetIndex] as ScriptableObject;
|
||||
string featureName = feature?.name ?? "Unknown";
|
||||
|
||||
Undo.RecordObject(rendererData as UnityEngine.Object, "Remove Renderer Feature");
|
||||
|
||||
// Remove from the list via SerializedObject
|
||||
using (var so = new SerializedObject(rendererData as UnityEngine.Object))
|
||||
{
|
||||
var rendererFeaturesPropSo = so.FindProperty("m_RendererFeatures");
|
||||
if (rendererFeaturesPropSo != null)
|
||||
{
|
||||
rendererFeaturesPropSo.DeleteArrayElementAtIndex(targetIndex);
|
||||
// SerializedProperty.DeleteArrayElementAtIndex sets to null first for ObjectReference
|
||||
if (rendererFeaturesPropSo.arraySize > targetIndex)
|
||||
{
|
||||
var element = rendererFeaturesPropSo.GetArrayElementAtIndex(targetIndex);
|
||||
if (element.objectReferenceValue == null)
|
||||
rendererFeaturesPropSo.DeleteArrayElementAtIndex(targetIndex);
|
||||
}
|
||||
so.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
// Clean up the map
|
||||
var mapProp = so.FindProperty("m_RendererFeatureMap");
|
||||
if (mapProp != null && targetIndex < mapProp.arraySize)
|
||||
{
|
||||
mapProp.DeleteArrayElementAtIndex(targetIndex);
|
||||
so.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the sub-asset
|
||||
if (feature != null)
|
||||
AssetDatabase.RemoveObjectFromAsset(feature);
|
||||
|
||||
EditorUtility.SetDirty(rendererData as UnityEngine.Object);
|
||||
AssetDatabase.SaveAssets();
|
||||
|
||||
return new
|
||||
{
|
||||
success = true,
|
||||
message = $"Removed renderer feature '{featureName}' at index {targetIndex}."
|
||||
};
|
||||
}
|
||||
|
||||
// === feature_configure ===
|
||||
internal static object ConfigureFeature(JObject @params)
|
||||
{
|
||||
var p = new ToolParams(@params);
|
||||
int? index = p.GetInt("index");
|
||||
string name = p.Get("name");
|
||||
var propertiesToken = (p.GetRaw("properties") ?? p.GetRaw("settings")) as JObject;
|
||||
|
||||
if (propertiesToken == null)
|
||||
return new ErrorResponse("'properties' (or 'settings') dict is required.");
|
||||
|
||||
var rendererData = GetRendererData(@params);
|
||||
if (rendererData == null)
|
||||
return new ErrorResponse("Could not find URP ScriptableRendererData.");
|
||||
|
||||
var featuresProp = rendererData.GetType().GetProperty("rendererFeatures",
|
||||
BindingFlags.Public | BindingFlags.Instance);
|
||||
var featuresList = featuresProp?.GetValue(rendererData) as System.Collections.IList;
|
||||
if (featuresList == null || featuresList.Count == 0)
|
||||
return new ErrorResponse("No renderer features to configure.");
|
||||
|
||||
int targetIndex = ResolveFeatureIndex(featuresList, index, name);
|
||||
if (targetIndex < 0)
|
||||
return new ErrorResponse($"Feature not found. Specify 'index' (0-{featuresList.Count - 1}) or 'name'.");
|
||||
|
||||
var feature = featuresList[targetIndex] as ScriptableObject;
|
||||
if (feature == null)
|
||||
return new ErrorResponse($"Feature at index {targetIndex} is null.");
|
||||
|
||||
Undo.RecordObject(feature, "Configure Renderer Feature");
|
||||
var result = ApplyFeatureProperties(feature, propertiesToken);
|
||||
EditorUtility.SetDirty(feature);
|
||||
EditorUtility.SetDirty(rendererData as UnityEngine.Object);
|
||||
AssetDatabase.SaveAssets();
|
||||
|
||||
return new
|
||||
{
|
||||
success = true,
|
||||
message = $"Configured '{feature.name}': {result.changed.Count} set, {result.failed.Count} failed.",
|
||||
data = new { result.changed, result.failed }
|
||||
};
|
||||
}
|
||||
|
||||
// === feature_toggle ===
|
||||
internal static object ToggleFeature(JObject @params)
|
||||
{
|
||||
var p = new ToolParams(@params);
|
||||
int? index = p.GetInt("index");
|
||||
string name = p.Get("name");
|
||||
bool? active = p.GetBool("active");
|
||||
|
||||
var rendererData = GetRendererData(@params);
|
||||
if (rendererData == null)
|
||||
return new ErrorResponse("Could not find URP ScriptableRendererData.");
|
||||
|
||||
var featuresProp = rendererData.GetType().GetProperty("rendererFeatures",
|
||||
BindingFlags.Public | BindingFlags.Instance);
|
||||
var featuresList = featuresProp?.GetValue(rendererData) as System.Collections.IList;
|
||||
if (featuresList == null || featuresList.Count == 0)
|
||||
return new ErrorResponse("No renderer features.");
|
||||
|
||||
int targetIndex = ResolveFeatureIndex(featuresList, index, name);
|
||||
if (targetIndex < 0)
|
||||
return new ErrorResponse($"Feature not found. Specify 'index' or 'name'.");
|
||||
|
||||
var feature = featuresList[targetIndex] as ScriptableObject;
|
||||
if (feature == null)
|
||||
return new ErrorResponse($"Feature at index {targetIndex} is null.");
|
||||
|
||||
// ScriptableRendererFeature.SetActive(bool) is public
|
||||
var setActiveMethod = feature.GetType().GetMethod("SetActive",
|
||||
BindingFlags.Public | BindingFlags.Instance);
|
||||
if (setActiveMethod == null)
|
||||
return new ErrorResponse("SetActive method not found on feature.");
|
||||
|
||||
bool newState = active ?? true;
|
||||
Undo.RecordObject(feature, "Toggle Renderer Feature");
|
||||
setActiveMethod.Invoke(feature, new object[] { newState });
|
||||
EditorUtility.SetDirty(feature);
|
||||
EditorUtility.SetDirty(rendererData as UnityEngine.Object);
|
||||
AssetDatabase.SaveAssets();
|
||||
|
||||
return new
|
||||
{
|
||||
success = true,
|
||||
message = $"Feature '{feature.name}' {(newState ? "enabled" : "disabled")}."
|
||||
};
|
||||
}
|
||||
|
||||
// === feature_reorder ===
|
||||
internal static object ReorderFeatures(JObject @params)
|
||||
{
|
||||
var p = new ToolParams(@params);
|
||||
var orderToken = p.GetRaw("order") as JArray;
|
||||
if (orderToken == null)
|
||||
return new ErrorResponse("'order' parameter required (array of indices, e.g. [2, 0, 1]).");
|
||||
|
||||
var rendererData = GetRendererData(@params);
|
||||
if (rendererData == null)
|
||||
return new ErrorResponse("Could not find URP ScriptableRendererData.");
|
||||
|
||||
var featuresProp = rendererData.GetType().GetProperty("rendererFeatures",
|
||||
BindingFlags.Public | BindingFlags.Instance);
|
||||
var featuresList = featuresProp?.GetValue(rendererData) as System.Collections.IList;
|
||||
if (featuresList == null || featuresList.Count == 0)
|
||||
return new ErrorResponse("No renderer features to reorder.");
|
||||
|
||||
var newOrder = orderToken.Select(t => (int)t).ToList();
|
||||
if (newOrder.Count != featuresList.Count)
|
||||
return new ErrorResponse(
|
||||
$"Order array length ({newOrder.Count}) must match feature count ({featuresList.Count}).");
|
||||
|
||||
// Validate all indices are present
|
||||
var sorted = newOrder.OrderBy(x => x).ToList();
|
||||
for (int i = 0; i < sorted.Count; i++)
|
||||
{
|
||||
if (sorted[i] != i)
|
||||
return new ErrorResponse("Order array must contain each index exactly once (0 to N-1).");
|
||||
}
|
||||
|
||||
Undo.RecordObject(rendererData as UnityEngine.Object, "Reorder Renderer Features");
|
||||
|
||||
using (var so = new SerializedObject(rendererData as UnityEngine.Object))
|
||||
{
|
||||
var rendererFeaturesPropSo = so.FindProperty("m_RendererFeatures");
|
||||
if (rendererFeaturesPropSo == null)
|
||||
return new ErrorResponse("m_RendererFeatures property not found.");
|
||||
|
||||
// Read current features
|
||||
var current = new UnityEngine.Object[featuresList.Count];
|
||||
for (int i = 0; i < featuresList.Count; i++)
|
||||
current[i] = rendererFeaturesPropSo.GetArrayElementAtIndex(i).objectReferenceValue;
|
||||
|
||||
// Apply new order
|
||||
for (int i = 0; i < newOrder.Count; i++)
|
||||
rendererFeaturesPropSo.GetArrayElementAtIndex(i).objectReferenceValue = current[newOrder[i]];
|
||||
|
||||
// Also reorder the feature map to keep it in sync
|
||||
var mapProp = so.FindProperty("m_RendererFeatureMap");
|
||||
if (mapProp != null && mapProp.arraySize == featuresList.Count)
|
||||
{
|
||||
var currentMap = new long[featuresList.Count];
|
||||
for (int i = 0; i < featuresList.Count; i++)
|
||||
currentMap[i] = mapProp.GetArrayElementAtIndex(i).longValue;
|
||||
for (int i = 0; i < newOrder.Count; i++)
|
||||
mapProp.GetArrayElementAtIndex(i).longValue = currentMap[newOrder[i]];
|
||||
}
|
||||
|
||||
so.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
EditorUtility.SetDirty(rendererData as UnityEngine.Object);
|
||||
AssetDatabase.SaveAssets();
|
||||
|
||||
return new
|
||||
{
|
||||
success = true,
|
||||
message = $"Reordered {featuresList.Count} renderer features."
|
||||
};
|
||||
}
|
||||
|
||||
// ==================== Helpers ====================
|
||||
|
||||
private static object GetRendererData(JObject @params)
|
||||
{
|
||||
EnsureTypes();
|
||||
if (_universalRenderPipelineAssetType == null || _scriptableRendererDataType == null)
|
||||
return null;
|
||||
|
||||
var pipelineAsset = GraphicsSettings.currentRenderPipeline;
|
||||
if (pipelineAsset == null || !_universalRenderPipelineAssetType.IsInstanceOfType(pipelineAsset))
|
||||
return null;
|
||||
|
||||
var p = new ToolParams(@params);
|
||||
int rendererIndex = p.GetInt("renderer_index") ?? -1;
|
||||
|
||||
// Get renderer data from the URP asset
|
||||
// Try scriptableRendererData property or GetRenderer method
|
||||
if (rendererIndex >= 0)
|
||||
{
|
||||
// Use SerializedObject to get specific renderer
|
||||
using (var so = new SerializedObject(pipelineAsset))
|
||||
{
|
||||
var renderersProp = so.FindProperty("m_RendererDataList");
|
||||
if (renderersProp == null || rendererIndex >= renderersProp.arraySize)
|
||||
return null;
|
||||
|
||||
var element = renderersProp.GetArrayElementAtIndex(rendererIndex);
|
||||
return element.objectReferenceValue;
|
||||
}
|
||||
}
|
||||
|
||||
// Default: get the active renderer (index from m_DefaultRendererIndex)
|
||||
using (var so = new SerializedObject(pipelineAsset))
|
||||
{
|
||||
var defaultIndex = so.FindProperty("m_DefaultRendererIndex");
|
||||
int idx = defaultIndex != null ? defaultIndex.intValue : 0;
|
||||
|
||||
var renderersProp = so.FindProperty("m_RendererDataList");
|
||||
if (renderersProp != null && idx < renderersProp.arraySize)
|
||||
{
|
||||
var element = renderersProp.GetArrayElementAtIndex(idx);
|
||||
return element.objectReferenceValue;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Type ResolveFeatureType(string typeName)
|
||||
{
|
||||
EnsureTypes();
|
||||
if (_scriptableRendererFeatureType == null) return null;
|
||||
|
||||
var derivedTypes = TypeCache.GetTypesDerivedFrom(_scriptableRendererFeatureType);
|
||||
foreach (var t in derivedTypes)
|
||||
{
|
||||
if (t.IsAbstract) continue;
|
||||
if (string.Equals(t.Name, typeName, StringComparison.OrdinalIgnoreCase))
|
||||
return t;
|
||||
}
|
||||
|
||||
// Try partial match (e.g., "FullScreenPass" matches "FullScreenPassRendererFeature")
|
||||
foreach (var t in derivedTypes)
|
||||
{
|
||||
if (t.IsAbstract) continue;
|
||||
if (t.Name.StartsWith(typeName, StringComparison.OrdinalIgnoreCase))
|
||||
return t;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static List<Type> GetAvailableFeatureTypes()
|
||||
{
|
||||
EnsureTypes();
|
||||
if (_scriptableRendererFeatureType == null) return new List<Type>();
|
||||
|
||||
return TypeCache.GetTypesDerivedFrom(_scriptableRendererFeatureType)
|
||||
.Where(t => !t.IsAbstract && !t.IsGenericType)
|
||||
.OrderBy(t => t.Name)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
private static int ResolveFeatureIndex(System.Collections.IList featuresList, int? index, string name)
|
||||
{
|
||||
if (index.HasValue && index.Value >= 0 && index.Value < featuresList.Count)
|
||||
return index.Value;
|
||||
|
||||
if (!string.IsNullOrEmpty(name))
|
||||
{
|
||||
for (int i = 0; i < featuresList.Count; i++)
|
||||
{
|
||||
var feature = featuresList[i] as ScriptableObject;
|
||||
if (feature == null) continue;
|
||||
if (string.Equals(feature.name, name, StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(feature.GetType().Name, name, StringComparison.OrdinalIgnoreCase))
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static Dictionary<string, object> GetFeatureProperties(ScriptableObject feature)
|
||||
{
|
||||
var props = new Dictionary<string, object>();
|
||||
using (var so = new SerializedObject(feature))
|
||||
{
|
||||
var iterator = so.GetIterator();
|
||||
if (iterator.NextVisible(true)) // Enter children
|
||||
{
|
||||
do
|
||||
{
|
||||
// Skip Unity internal properties
|
||||
if (iterator.name == "m_Script" || iterator.name == "m_ObjectHideFlags" || iterator.name == "m_Name")
|
||||
continue;
|
||||
|
||||
props[iterator.name] = GraphicsHelpers.ReadSerializedValue(iterator);
|
||||
} while (iterator.NextVisible(false));
|
||||
}
|
||||
}
|
||||
return props;
|
||||
}
|
||||
|
||||
private static (List<string> changed, List<string> failed) ApplyFeatureProperties(
|
||||
ScriptableObject feature, JObject propertiesToken)
|
||||
{
|
||||
var changed = new List<string>();
|
||||
var failed = new List<string>();
|
||||
|
||||
using (var so = new SerializedObject(feature))
|
||||
{
|
||||
foreach (var prop in propertiesToken.Properties())
|
||||
{
|
||||
var sProp = so.FindProperty(prop.Name);
|
||||
if (sProp != null)
|
||||
{
|
||||
if (GraphicsHelpers.SetSerializedValue(sProp, prop.Value))
|
||||
changed.Add(prop.Name);
|
||||
else
|
||||
failed.Add(prop.Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Try nested: "settings.fieldName"
|
||||
string nested = $"settings.{prop.Name}";
|
||||
sProp = so.FindProperty(nested);
|
||||
if (sProp != null && GraphicsHelpers.SetSerializedValue(sProp, prop.Value))
|
||||
changed.Add(prop.Name);
|
||||
else
|
||||
failed.Add(prop.Name);
|
||||
}
|
||||
}
|
||||
so.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
return (changed, failed);
|
||||
}
|
||||
|
||||
private static void TrySetMaterial(ScriptableObject feature, string materialPath)
|
||||
{
|
||||
var mat = AssetDatabase.LoadAssetAtPath<Material>(materialPath);
|
||||
if (mat == null) return;
|
||||
|
||||
using (var so = new SerializedObject(feature))
|
||||
{
|
||||
// FullScreenPassRendererFeature uses "m_PassMaterial" or "passMaterial"
|
||||
var matProp = so.FindProperty("m_PassMaterial") ?? so.FindProperty("passMaterial");
|
||||
if (matProp != null && matProp.propertyType == SerializedPropertyType.ObjectReference)
|
||||
{
|
||||
matProp.objectReferenceValue = mat;
|
||||
so.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user