ArabDesert/Assets/Editor/x64/Bakery/scripts/ftSkyLightInspector.cs

366 lines
17 KiB
C#
Raw Normal View History

2024-05-25 09:10:35 +03:00
using UnityEditor;
using UnityEngine;
using System;
using System.IO;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEditor.SceneManagement;
using UnityEngine.SceneManagement;
[CustomEditor(typeof(BakerySkyLight))]
[CanEditMultipleObjects]
public class ftSkyLightInspector : UnityEditor.Editor
{
public static Quaternion QuaternionFromMatrix(Matrix4x4 m) {
Quaternion q = new Quaternion();
q.w = Mathf.Sqrt( Mathf.Max( 0, 1 + m[0,0] + m[1,1] + m[2,2] ) ) / 2;
q.x = Mathf.Sqrt( Mathf.Max( 0, 1 + m[0,0] - m[1,1] - m[2,2] ) ) / 2;
q.y = Mathf.Sqrt( Mathf.Max( 0, 1 - m[0,0] + m[1,1] - m[2,2] ) ) / 2;
q.z = Mathf.Sqrt( Mathf.Max( 0, 1 - m[0,0] - m[1,1] + m[2,2] ) ) / 2;
q.x *= Mathf.Sign( q.x * ( m[2,1] - m[1,2] ) );
q.y *= Mathf.Sign( q.y * ( m[0,2] - m[2,0] ) );
q.z *= Mathf.Sign( q.z * ( m[1,0] - m[0,1] ) );
return q;
}
SerializedProperty ftraceLightColor;
SerializedProperty ftraceLightIntensity;
SerializedProperty ftraceLightTexture;
SerializedProperty ftraceLightSamples;
SerializedProperty ftraceLightHemi;
SerializedProperty ftraceLightCorrectRot;
SerializedProperty ftraceLightBitmask;
SerializedProperty ftraceLightBakeToIndirect;
SerializedProperty ftraceLightIndirectIntensity;
SerializedProperty ftraceTangentSH;
int texCached = -1;
void TestPreviewRefreshProperty(ref int cached, int newVal)
{
if (cached >= 0)
{
if (cached != newVal)
{
BakerySkyLight.lightsChanged = 2;
}
}
cached = newVal;
}
void TestPreviewRefreshProperty(ref int cached, UnityEngine.Object newVal)
{
if (newVal == null)
{
TestPreviewRefreshProperty(ref cached, 0);
return;
}
TestPreviewRefreshProperty(ref cached, newVal.GetInstanceID());
}
static string ftSkyboxShaderName = "Bakery/Skybox";
ftLightmapsStorage storage;
static string[] selStrings = new string[] {"0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16",
"17","18","19","20","21","22","23","24","25","26","27","28","29","30"};//,"31"};
static public string[] directContributionOptions = new string[] {"Direct And Indirect (recommended)", "Indirect only"};
bool showExperimental = false;
void OnEnable()
{
ftraceLightColor = serializedObject.FindProperty("color");
ftraceLightIntensity = serializedObject.FindProperty("intensity");
ftraceLightIndirectIntensity = serializedObject.FindProperty("indirectIntensity");
ftraceLightTexture = serializedObject.FindProperty("cubemap");
ftraceLightSamples = serializedObject.FindProperty("samples");
ftraceLightHemi = serializedObject.FindProperty("hemispherical");
ftraceLightCorrectRot = serializedObject.FindProperty("correctRotation");
ftraceLightBitmask = serializedObject.FindProperty("bitmask");
ftraceLightBakeToIndirect = serializedObject.FindProperty("bakeToIndirect");
ftraceTangentSH = serializedObject.FindProperty("tangentSH");
}
public override void OnInspectorGUI() {
{
serializedObject.Update();
TestPreviewRefreshProperty(ref texCached, ftraceLightTexture.objectReferenceValue);
EditorGUILayout.PropertyField(ftraceLightColor, new GUIContent("Color", "Sky color. Multiplies texture color."));
EditorGUILayout.PropertyField(ftraceLightIntensity, new GUIContent("Intensity", "Color multiplier"));
EditorGUILayout.PropertyField(ftraceLightTexture, new GUIContent("Sky texture", "Cubemap"));
if (ftraceLightTexture.objectReferenceValue != null)
{
EditorGUILayout.PropertyField(ftraceLightCorrectRot, new GUIContent("Correct rotation", "Enable to have a proper match between GameObject rotation and HDRI rotation. Disabled by default for backwards compatibility."));
var angles = (target as BakerySkyLight).transform.eulerAngles;
EditorGUILayout.LabelField("Cubemap angles: " + angles.x + ", " + angles.y + ", " + angles.z);
EditorGUILayout.LabelField("Rotate this GameObject to change cubemap angles.");
EditorGUILayout.Space();
}
EditorGUILayout.PropertyField(ftraceLightSamples, new GUIContent("Samples", "The amount of rays tested for this light. Rays are emitted hemispherically."));
EditorGUILayout.PropertyField(ftraceLightHemi, new GUIContent("Hemispherical", "Only emit light from upper hemisphere"));
//ftraceLightBitmask.intValue = EditorGUILayout.MaskField(new GUIContent("Bitmask", "Lights only affect renderers with overlapping bits"), ftraceLightBitmask.intValue, selStrings);
int prevVal = ftraceLightBitmask.intValue;
int newVal = EditorGUILayout.MaskField(new GUIContent("Bitmask", "Lights only affect renderers with overlapping bits"), ftraceLightBitmask.intValue, selStrings);
if (prevVal != newVal) ftraceLightBitmask.intValue = newVal;
//EditorGUILayout.PropertyField(ftraceLightBakeToIndirect, new GUIContent("Bake to indirect", "Add direct contribution from this light to indirect-only lightmaps"));
if (storage == null) storage = ftRenderLightmap.FindRenderSettingsStorage();
var rmode = storage.renderSettingsUserRenderMode;
if (rmode != (int)ftRenderLightmap.RenderMode.FullLighting)
{
ftDirectLightInspector.BakeWhat contrib;
if (ftraceLightBakeToIndirect.boolValue)
{
contrib = ftDirectLightInspector.BakeWhat.DirectAndIndirect;
}
else
{
contrib = ftDirectLightInspector.BakeWhat.IndirectOnly;
}
var prevContrib = contrib;
contrib = (ftDirectLightInspector.BakeWhat)EditorGUILayout.Popup("Baked contribution", (int)contrib, directContributionOptions);
if (prevContrib != contrib)
{
if (contrib == ftDirectLightInspector.BakeWhat.IndirectOnly)
{
ftraceLightBakeToIndirect.boolValue = false;
}
else
{
ftraceLightBakeToIndirect.boolValue = true;
}
}
}
EditorGUILayout.PropertyField(ftraceLightIndirectIntensity, new GUIContent("Indirect intensity", "Non-physical GI multiplier for this light"));
showExperimental = EditorGUILayout.Foldout(showExperimental, "Experimental", EditorStyles.foldout);
if (showExperimental)
{
EditorGUILayout.PropertyField(ftraceTangentSH, new GUIContent("Tangent-space SH", "Only affects single-color skylights. When baking in SH mode, harmonics will be in tangent space. Can be useful for implementing skinned model specular occlusion in custom shaders."));
}
serializedObject.ApplyModifiedProperties();
}
var skyMat = RenderSettings.skybox;
bool match = false;
bool skyboxValid = true;
string why = "";
if (skyMat != null)
{
if (skyMat.HasProperty("_Tex") && skyMat.HasProperty("_Exposure") && skyMat.HasProperty("_Tint"))
{
if (skyMat.GetTexture("_Tex") == ftraceLightTexture.objectReferenceValue)
{
float exposure = skyMat.GetFloat("_Exposure");
bool exposureSRGB = skyMat.shader.name == "Skybox/Cubemap";
if (exposureSRGB)
{
exposure = Mathf.Pow(exposure, 2.2f); // can't detect [Gamma] keyword...
exposure *= PlayerSettings.colorSpace == ColorSpace.Linear ? 4.59f : 2; // weird unity constant
}
if (Mathf.Abs(exposure - ftraceLightIntensity.floatValue) < 0.0001f)
{
if (skyMat.GetColor("_Tint") == ftraceLightColor.colorValue)
{
bool anglesMatch = true;
var angles = (target as BakerySkyLight).transform.eulerAngles;
Vector3 matMatrixX = Vector3.right;
Vector3 matMatrixY = Vector3.up;
Vector3 matMatrixZ = Vector3.forward;
float matAngleY = 0;
bool hasYAngle = skyMat.HasProperty("_Rotation");
bool hasXZAngles = skyMat.HasProperty("_MatrixRight");
if (hasYAngle) matAngleY = skyMat.GetFloat("_Rotation");
if (hasXZAngles)
{
matMatrixX = skyMat.GetVector("_MatrixRight");
matMatrixY = skyMat.GetVector("_MatrixUp");
matMatrixZ = skyMat.GetVector("_MatrixForward");
}
if (angles.y != 0 && !hasYAngle)
{
anglesMatch = false;
why = "no _Rotation property, but light is rotated";
}
else if ((angles.x != 0 || angles.z != 0) && !hasXZAngles)
{
anglesMatch = false;
why = "shader doesn't allow XZ rotation";
}
else
{
var lightQuat = (target as BakerySkyLight).transform.rotation;
Quaternion matQuat;
if (hasXZAngles)
{
var mtx = new Matrix4x4();
mtx.SetColumn(0, new Vector4(matMatrixX.x, matMatrixX.y, matMatrixX.z, 0));
mtx.SetColumn(1, new Vector4(matMatrixY.x, matMatrixY.y, matMatrixY.z, 0));
mtx.SetColumn(2, new Vector4(matMatrixZ.x, matMatrixZ.y, matMatrixZ.z, 0));
matQuat = QuaternionFromMatrix(mtx);
}
else
{
matQuat = Quaternion.Euler(0, matAngleY, 0);
}
float diff = Quaternion.Angle(matQuat, lightQuat);
//Debug.Log("d " + diff);
if (Mathf.Abs(diff) > 0.01f)
{
anglesMatch = false;
why = "angles don't match";
}
}
if (anglesMatch) match = true;
}
else
{
why = "color doesn't match";
}
}
else
{
why = "exposure doesn't match";
}
}
else
{
why = "texture doesn't match";
}
}
else
{
if (!skyMat.HasProperty("_Tex")) why += "_Tex ";
if (!skyMat.HasProperty("_Exposure")) why += "_Exposure ";
if (!skyMat.HasProperty("_Tint")) why += "_Tint ";
why += "not defined";
skyboxValid = false;
}
}
else
{
why = "no skybox set";
skyboxValid = false;
}
if (!match)
{
EditorGUILayout.Space();
EditorGUILayout.LabelField("Skylight doesn't match skybox: " + why);
EditorGUILayout.Space();
if (skyboxValid)
{
if (GUILayout.Button("Match this light to scene skybox"))
{
ftraceLightTexture.objectReferenceValue = skyMat.GetTexture("_Tex");
float exposure = skyMat.GetFloat("_Exposure");
bool exposureSRGB = skyMat.shader.name == "Skybox/Cubemap";
if (exposureSRGB)
{
exposure = Mathf.Pow(exposure, 2.2f); // can't detect [Gamma] keyword...
exposure *= PlayerSettings.colorSpace == ColorSpace.Linear ? 4.59f : 2; // weird unity constant
}
ftraceLightIntensity.floatValue = exposure;
ftraceLightColor.colorValue = skyMat.GetColor("_Tint");
float matAngle = 0;
if (skyMat.HasProperty("_Rotation")) matAngle = skyMat.GetFloat("_Rotation");
var matQuat = Quaternion.Euler(0, matAngle, 0);
Undo.RecordObject((target as BakerySkyLight).transform, "Rotate skylight");
(target as BakerySkyLight).transform.rotation = matQuat;
serializedObject.ApplyModifiedProperties();
}
}
if (GUILayout.Button("Match scene skybox to this light"))
{
if (skyMat != null)
{
Undo.RecordObject(skyMat, "Change skybox");
}
var tform = (target as BakerySkyLight).transform;
var angles = tform.eulerAngles;
if (angles.x !=0 || angles.z !=0)
{
if (skyboxValid && !skyMat.HasProperty("_MatrixRight")) skyboxValid = false; // only ftrace skybox can handle xz rotation for now
}
if (angles.y != 0 && skyboxValid && !skyMat.HasProperty("_Rotation")) skyboxValid = false; // needs _Rotation for Y angle
if (!skyboxValid)
{
var outputPath = ftRenderLightmap.outputPath;
skyMat = new Material(Shader.Find(ftSkyboxShaderName));
if (!Directory.Exists("Assets/" + outputPath))
{
Directory.CreateDirectory("Assets/" + outputPath);
}
AssetDatabase.CreateAsset(skyMat, "Assets/" + outputPath + "/" + SceneManager.GetActiveScene().name + "_skybox.asset");
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
skyMat.SetTexture("_Tex", ftraceLightTexture.objectReferenceValue as Cubemap);
skyMat.SetFloat("_NoTexture", ftraceLightTexture.objectReferenceValue == null ? 1 : 0);
float exposure = ftraceLightIntensity.floatValue;
bool exposureSRGB = skyMat.shader.name == "Skybox/Cubemap";
if (exposureSRGB)
{
exposure /= PlayerSettings.colorSpace == ColorSpace.Linear ? 4.59f : 2; // weird unity constant
exposure = Mathf.Pow(exposure, 1.0f / 2.2f); // can't detect [Gamma] keyword...
}
skyMat.SetFloat("_Exposure", exposure);
skyMat.SetColor("_Tint", ftraceLightColor.colorValue);
if (skyMat.HasProperty("_Rotation")) skyMat.SetFloat("_Rotation", angles.y);
if ((target as BakerySkyLight).correctRotation)
{
// transpose
var r = tform.right;
var u = tform.up;
var f = tform.forward;
if (skyMat.HasProperty("_MatrixRight")) skyMat.SetVector("_MatrixRight", new Vector3(r.x, u.x, f.x));
if (skyMat.HasProperty("_MatrixUp")) skyMat.SetVector("_MatrixUp", new Vector3(r.y, u.y, f.y));
if (skyMat.HasProperty("_MatrixForward")) skyMat.SetVector("_MatrixForward", new Vector3(r.z, u.z, f.z));
}
else
{
if (skyMat.HasProperty("_MatrixRight")) skyMat.SetVector("_MatrixRight", tform.right);
if (skyMat.HasProperty("_MatrixUp")) skyMat.SetVector("_MatrixUp", tform.up);
if (skyMat.HasProperty("_MatrixForward")) skyMat.SetVector("_MatrixForward", tform.forward);
}
RenderSettings.skybox = skyMat;
EditorUtility.SetDirty(skyMat);
EditorSceneManager.MarkAllScenesDirty();
}
EditorGUILayout.Space();
EditorGUILayout.Space();
}
}
}