498 lines
20 KiB
C#
498 lines
20 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using Newtonsoft.Json.Linq;
|
|
using MCPForUnity.Editor.Helpers;
|
|
using UnityEditor;
|
|
using UnityEngine;
|
|
using UnityEngine.Rendering;
|
|
using MCPForUnity.Runtime.Helpers;
|
|
|
|
namespace MCPForUnity.Editor.Tools.Graphics
|
|
{
|
|
internal static class SkyboxOps
|
|
{
|
|
static Texture CustomReflectionTexture
|
|
{
|
|
get =>
|
|
#if UNITY_2022_1_OR_NEWER
|
|
RenderSettings.customReflectionTexture;
|
|
#else
|
|
RenderSettings.customReflection;
|
|
#endif
|
|
set {
|
|
#if UNITY_2022_1_OR_NEWER
|
|
RenderSettings.customReflectionTexture = value;
|
|
#else
|
|
RenderSettings.customReflection = value;
|
|
#endif
|
|
}
|
|
}
|
|
// ---------------------------------------------------------------
|
|
// skybox_get — read all environment settings
|
|
// ---------------------------------------------------------------
|
|
public static object GetEnvironment(JObject @params)
|
|
{
|
|
var skyMat = RenderSettings.skybox;
|
|
var sun = RenderSettings.sun;
|
|
|
|
object matInfo = null;
|
|
if (skyMat != null)
|
|
{
|
|
var props = new List<object>();
|
|
int count = skyMat.shader.GetPropertyCount();
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
string propName = skyMat.shader.GetPropertyName(i);
|
|
var propType = skyMat.shader.GetPropertyType(i);
|
|
object val = ReadMaterialProperty(skyMat, propName, propType);
|
|
props.Add(new { name = propName, type = propType.ToString(), value = val });
|
|
}
|
|
matInfo = new
|
|
{
|
|
name = skyMat.name,
|
|
shader = skyMat.shader.name,
|
|
path = AssetDatabase.GetAssetPath(skyMat),
|
|
properties = props
|
|
};
|
|
}
|
|
|
|
return new
|
|
{
|
|
success = true,
|
|
message = "Environment settings retrieved.",
|
|
data = new
|
|
{
|
|
skybox = matInfo,
|
|
ambient = new
|
|
{
|
|
mode = RenderSettings.ambientMode.ToString(),
|
|
skyColor = ColorToArray(RenderSettings.ambientSkyColor),
|
|
equatorColor = ColorToArray(RenderSettings.ambientEquatorColor),
|
|
groundColor = ColorToArray(RenderSettings.ambientGroundColor),
|
|
ambientLight = ColorToArray(RenderSettings.ambientLight),
|
|
intensity = RenderSettings.ambientIntensity
|
|
},
|
|
fog = new
|
|
{
|
|
enabled = RenderSettings.fog,
|
|
mode = RenderSettings.fogMode.ToString(),
|
|
color = ColorToArray(RenderSettings.fogColor),
|
|
density = RenderSettings.fogDensity,
|
|
startDistance = RenderSettings.fogStartDistance,
|
|
endDistance = RenderSettings.fogEndDistance
|
|
},
|
|
reflection = new
|
|
{
|
|
intensity = RenderSettings.reflectionIntensity,
|
|
bounces = RenderSettings.reflectionBounces,
|
|
mode = RenderSettings.defaultReflectionMode.ToString(),
|
|
resolution = RenderSettings.defaultReflectionResolution,
|
|
customCubemap = CustomReflectionTexture != null
|
|
? AssetDatabase.GetAssetPath(CustomReflectionTexture)
|
|
: null
|
|
},
|
|
sun = sun != null
|
|
? (object)new { name = sun.gameObject.name, instanceID = sun.gameObject.GetInstanceIDCompat() }
|
|
: null,
|
|
subtractiveShadowColor = ColorToArray(RenderSettings.subtractiveShadowColor)
|
|
}
|
|
};
|
|
}
|
|
|
|
// ---------------------------------------------------------------
|
|
// skybox_set_material — assign a skybox material
|
|
// ---------------------------------------------------------------
|
|
public static object SetMaterial(JObject @params)
|
|
{
|
|
var p = new ToolParams(@params);
|
|
string materialPath = p.Get("material") ?? p.Get("path") ?? p.Get("material_path");
|
|
if (string.IsNullOrEmpty(materialPath))
|
|
return new ErrorResponse("'material' (asset path) is required.");
|
|
|
|
var mat = AssetDatabase.LoadAssetAtPath<Material>(materialPath);
|
|
if (mat == null)
|
|
return new ErrorResponse($"Material not found at '{materialPath}'.");
|
|
|
|
RenderSettings.skybox = mat;
|
|
MarkSceneDirty();
|
|
|
|
return new
|
|
{
|
|
success = true,
|
|
message = $"Skybox set to '{mat.name}' (shader: {mat.shader.name}).",
|
|
data = new
|
|
{
|
|
material = mat.name,
|
|
shader = mat.shader.name,
|
|
path = materialPath
|
|
}
|
|
};
|
|
}
|
|
|
|
// ---------------------------------------------------------------
|
|
// skybox_set_properties — modify properties on the current skybox material
|
|
// ---------------------------------------------------------------
|
|
public static object SetMaterialProperties(JObject @params)
|
|
{
|
|
var p = new ToolParams(@params);
|
|
var skyMat = RenderSettings.skybox;
|
|
if (skyMat == null)
|
|
return new ErrorResponse("No skybox material is set.");
|
|
|
|
var propsRaw = p.GetRaw("properties") ?? p.GetRaw("parameters");
|
|
if (propsRaw == null || propsRaw.Type != JTokenType.Object)
|
|
return new ErrorResponse("'properties' dict is required.");
|
|
|
|
var set = new List<string>();
|
|
var failed = new List<string>();
|
|
|
|
foreach (var kvp in (JObject)propsRaw)
|
|
{
|
|
string propName = kvp.Key;
|
|
if (!skyMat.HasProperty(propName))
|
|
{
|
|
string altName = "_" + propName;
|
|
if (skyMat.HasProperty(altName))
|
|
propName = altName;
|
|
else
|
|
{
|
|
failed.Add(kvp.Key);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (SetMaterialProperty(skyMat, propName, kvp.Value))
|
|
set.Add(kvp.Key);
|
|
else
|
|
failed.Add(kvp.Key);
|
|
}
|
|
|
|
EditorUtility.SetDirty(skyMat);
|
|
AssetDatabase.SaveAssets();
|
|
MarkSceneDirty();
|
|
|
|
return new
|
|
{
|
|
success = true,
|
|
message = $"Set {set.Count} property(ies) on skybox material '{skyMat.name}'.",
|
|
data = new { material = skyMat.name, set, failed }
|
|
};
|
|
}
|
|
|
|
// ---------------------------------------------------------------
|
|
// skybox_set_ambient — set ambient lighting mode and colors
|
|
// ---------------------------------------------------------------
|
|
public static object SetAmbient(JObject @params)
|
|
{
|
|
var p = new ToolParams(@params);
|
|
|
|
string modeStr = p.Get("ambient_mode") ?? p.Get("mode");
|
|
if (!string.IsNullOrEmpty(modeStr))
|
|
{
|
|
if (Enum.TryParse<AmbientMode>(modeStr, true, out var mode))
|
|
RenderSettings.ambientMode = mode;
|
|
else
|
|
return new ErrorResponse(
|
|
$"Invalid ambient mode '{modeStr}'. Valid: Skybox, Trilight, Flat, Custom.");
|
|
}
|
|
|
|
var skyColor = ParseColorToken(p.GetRaw("color") ?? p.GetRaw("sky_color"));
|
|
if (skyColor.HasValue)
|
|
RenderSettings.ambientSkyColor = skyColor.Value;
|
|
|
|
var equatorColor = ParseColorToken(p.GetRaw("equator_color"));
|
|
if (equatorColor.HasValue)
|
|
RenderSettings.ambientEquatorColor = equatorColor.Value;
|
|
|
|
var groundColor = ParseColorToken(p.GetRaw("ground_color"));
|
|
if (groundColor.HasValue)
|
|
RenderSettings.ambientGroundColor = groundColor.Value;
|
|
|
|
var intensity = p.GetFloat("intensity");
|
|
if (intensity.HasValue)
|
|
RenderSettings.ambientIntensity = intensity.Value;
|
|
|
|
MarkSceneDirty();
|
|
|
|
return new
|
|
{
|
|
success = true,
|
|
message = $"Ambient lighting updated (mode: {RenderSettings.ambientMode}).",
|
|
data = new
|
|
{
|
|
mode = RenderSettings.ambientMode.ToString(),
|
|
skyColor = ColorToArray(RenderSettings.ambientSkyColor),
|
|
equatorColor = ColorToArray(RenderSettings.ambientEquatorColor),
|
|
groundColor = ColorToArray(RenderSettings.ambientGroundColor),
|
|
intensity = RenderSettings.ambientIntensity
|
|
}
|
|
};
|
|
}
|
|
|
|
// ---------------------------------------------------------------
|
|
// skybox_set_fog — enable/configure fog
|
|
// ---------------------------------------------------------------
|
|
public static object SetFog(JObject @params)
|
|
{
|
|
var p = new ToolParams(@params);
|
|
|
|
var enabledToken = p.GetRaw("fog_enabled") ?? p.GetRaw("enabled");
|
|
if (enabledToken != null && enabledToken.Type != JTokenType.Null)
|
|
RenderSettings.fog = ParamCoercion.CoerceBool(enabledToken, RenderSettings.fog);
|
|
|
|
string modeStr = p.Get("fog_mode") ?? p.Get("mode");
|
|
if (!string.IsNullOrEmpty(modeStr))
|
|
{
|
|
if (Enum.TryParse<FogMode>(modeStr, true, out var fogMode))
|
|
RenderSettings.fogMode = fogMode;
|
|
else
|
|
return new ErrorResponse(
|
|
$"Invalid fog mode '{modeStr}'. Valid: Linear, Exponential, ExponentialSquared.");
|
|
}
|
|
|
|
var fogColor = ParseColorToken(p.GetRaw("fog_color") ?? p.GetRaw("color"));
|
|
if (fogColor.HasValue)
|
|
RenderSettings.fogColor = fogColor.Value;
|
|
|
|
var density = p.GetFloat("fog_density") ?? p.GetFloat("density");
|
|
if (density.HasValue)
|
|
RenderSettings.fogDensity = density.Value;
|
|
|
|
var start = p.GetFloat("fog_start") ?? p.GetFloat("start");
|
|
if (start.HasValue)
|
|
RenderSettings.fogStartDistance = start.Value;
|
|
|
|
var end = p.GetFloat("fog_end") ?? p.GetFloat("end");
|
|
if (end.HasValue)
|
|
RenderSettings.fogEndDistance = end.Value;
|
|
|
|
MarkSceneDirty();
|
|
|
|
return new
|
|
{
|
|
success = true,
|
|
message = $"Fog settings updated (enabled: {RenderSettings.fog}, mode: {RenderSettings.fogMode}).",
|
|
data = new
|
|
{
|
|
enabled = RenderSettings.fog,
|
|
mode = RenderSettings.fogMode.ToString(),
|
|
color = ColorToArray(RenderSettings.fogColor),
|
|
density = RenderSettings.fogDensity,
|
|
startDistance = RenderSettings.fogStartDistance,
|
|
endDistance = RenderSettings.fogEndDistance
|
|
}
|
|
};
|
|
}
|
|
|
|
// ---------------------------------------------------------------
|
|
// skybox_set_reflection — configure environment reflections
|
|
// ---------------------------------------------------------------
|
|
public static object SetReflection(JObject @params)
|
|
{
|
|
var p = new ToolParams(@params);
|
|
|
|
var intensity = p.GetFloat("intensity");
|
|
if (intensity.HasValue)
|
|
RenderSettings.reflectionIntensity = intensity.Value;
|
|
|
|
var bounces = p.GetInt("bounces");
|
|
if (bounces.HasValue)
|
|
RenderSettings.reflectionBounces = bounces.Value;
|
|
|
|
string modeStr = p.Get("reflection_mode") ?? p.Get("mode");
|
|
if (!string.IsNullOrEmpty(modeStr))
|
|
{
|
|
if (Enum.TryParse<DefaultReflectionMode>(modeStr, true, out var mode))
|
|
RenderSettings.defaultReflectionMode = mode;
|
|
else
|
|
return new ErrorResponse(
|
|
$"Invalid reflection mode '{modeStr}'. Valid: Skybox, Custom.");
|
|
}
|
|
|
|
var resolution = p.GetInt("resolution");
|
|
if (resolution.HasValue)
|
|
RenderSettings.defaultReflectionResolution = resolution.Value;
|
|
|
|
string cubemapPath = p.Get("path") ?? p.Get("cubemap_path");
|
|
if (!string.IsNullOrEmpty(cubemapPath))
|
|
{
|
|
var cubemap = AssetDatabase.LoadAssetAtPath<Texture>(cubemapPath);
|
|
if (cubemap != null)
|
|
CustomReflectionTexture = cubemap;
|
|
else
|
|
return new ErrorResponse($"Cubemap not found at '{cubemapPath}'.");
|
|
}
|
|
|
|
MarkSceneDirty();
|
|
|
|
return new
|
|
{
|
|
success = true,
|
|
message = $"Reflection settings updated (intensity: {RenderSettings.reflectionIntensity}, bounces: {RenderSettings.reflectionBounces}).",
|
|
data = new
|
|
{
|
|
intensity = RenderSettings.reflectionIntensity,
|
|
bounces = RenderSettings.reflectionBounces,
|
|
mode = RenderSettings.defaultReflectionMode.ToString(),
|
|
resolution = RenderSettings.defaultReflectionResolution,
|
|
customCubemap = CustomReflectionTexture != null
|
|
? AssetDatabase.GetAssetPath(CustomReflectionTexture)
|
|
: null
|
|
}
|
|
};
|
|
}
|
|
|
|
// ---------------------------------------------------------------
|
|
// skybox_set_sun — set the sun source light
|
|
// ---------------------------------------------------------------
|
|
public static object SetSun(JObject @params)
|
|
{
|
|
var p = new ToolParams(@params);
|
|
string target = p.Get("target") ?? p.Get("name");
|
|
if (string.IsNullOrEmpty(target))
|
|
return new ErrorResponse("'target' (light GameObject name or instance ID) is required.");
|
|
|
|
GameObject go = null;
|
|
if (int.TryParse(target, out int instanceId))
|
|
go = GameObjectLookup.ResolveInstanceID(instanceId) as GameObject;
|
|
if (go == null)
|
|
go = GameObject.Find(target);
|
|
if (go == null)
|
|
return new ErrorResponse($"GameObject '{target}' not found.");
|
|
|
|
var light = go.GetComponent<Light>();
|
|
if (light == null)
|
|
return new ErrorResponse($"'{go.name}' does not have a Light component.");
|
|
|
|
RenderSettings.sun = light;
|
|
MarkSceneDirty();
|
|
|
|
return new
|
|
{
|
|
success = true,
|
|
message = $"Sun source set to '{go.name}'.",
|
|
data = new
|
|
{
|
|
name = go.name,
|
|
instanceID = go.GetInstanceIDCompat(),
|
|
lightType = light.type.ToString()
|
|
}
|
|
};
|
|
}
|
|
|
|
// ---------------------------------------------------------------
|
|
// Helpers
|
|
// ---------------------------------------------------------------
|
|
|
|
private static float[] ColorToArray(Color c)
|
|
{
|
|
return new[] { c.r, c.g, c.b, c.a };
|
|
}
|
|
|
|
private static Color ArrayToColor(float[] arr)
|
|
{
|
|
return new Color(
|
|
arr[0], arr[1], arr[2],
|
|
arr.Length >= 4 ? arr[3] : 1f);
|
|
}
|
|
|
|
private static Color? ParseColorToken(JToken token)
|
|
{
|
|
if (token == null || token.Type == JTokenType.Null) return null;
|
|
if (token is JArray arr && arr.Count >= 3)
|
|
{
|
|
return new Color(
|
|
(float)arr[0], (float)arr[1], (float)arr[2],
|
|
arr.Count >= 4 ? (float)arr[3] : 1f);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private static object ReadMaterialProperty(Material mat, string propName, ShaderPropertyType propType)
|
|
{
|
|
switch (propType)
|
|
{
|
|
case ShaderPropertyType.Color:
|
|
return ColorToArray(mat.GetColor(propName));
|
|
case ShaderPropertyType.Float:
|
|
case ShaderPropertyType.Range:
|
|
return mat.GetFloat(propName);
|
|
case ShaderPropertyType.Int:
|
|
return mat.GetInt(propName);
|
|
case ShaderPropertyType.Vector:
|
|
var v = mat.GetVector(propName);
|
|
return new[] { v.x, v.y, v.z, v.w };
|
|
case ShaderPropertyType.Texture:
|
|
var tex = mat.GetTexture(propName);
|
|
return tex != null ? AssetDatabase.GetAssetPath(tex) : null;
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
|
|
private static bool SetMaterialProperty(Material mat, string propName, JToken value)
|
|
{
|
|
int propIdx = mat.shader.FindPropertyIndex(propName);
|
|
if (propIdx < 0) return false;
|
|
|
|
var propType = mat.shader.GetPropertyType(propIdx);
|
|
try
|
|
{
|
|
switch (propType)
|
|
{
|
|
case ShaderPropertyType.Color:
|
|
if (value is JArray colorArr && colorArr.Count >= 3)
|
|
{
|
|
mat.SetColor(propName, new Color(
|
|
(float)colorArr[0], (float)colorArr[1], (float)colorArr[2],
|
|
colorArr.Count >= 4 ? (float)colorArr[3] : 1f));
|
|
return true;
|
|
}
|
|
return false;
|
|
case ShaderPropertyType.Float:
|
|
case ShaderPropertyType.Range:
|
|
mat.SetFloat(propName, (float)value);
|
|
return true;
|
|
case ShaderPropertyType.Int:
|
|
mat.SetInt(propName, (int)value);
|
|
return true;
|
|
case ShaderPropertyType.Vector:
|
|
if (value is JArray vecArr && vecArr.Count >= 2)
|
|
{
|
|
mat.SetVector(propName, new Vector4(
|
|
(float)vecArr[0], (float)vecArr[1],
|
|
vecArr.Count >= 3 ? (float)vecArr[2] : 0f,
|
|
vecArr.Count >= 4 ? (float)vecArr[3] : 0f));
|
|
return true;
|
|
}
|
|
return false;
|
|
case ShaderPropertyType.Texture:
|
|
if (value.Type == JTokenType.String)
|
|
{
|
|
var tex = AssetDatabase.LoadAssetAtPath<Texture>(value.ToString());
|
|
if (tex != null) { mat.SetTexture(propName, tex); return true; }
|
|
}
|
|
else if (value.Type == JTokenType.Null)
|
|
{
|
|
mat.SetTexture(propName, null);
|
|
return true;
|
|
}
|
|
return false;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private static void MarkSceneDirty()
|
|
{
|
|
UnityEditor.SceneManagement.EditorSceneManager.MarkSceneDirty(
|
|
UnityEditor.SceneManagement.EditorSceneManager.GetActiveScene());
|
|
}
|
|
}
|
|
}
|