CapsuleAO point light

This commit is contained in:
StarBeats 2025-09-28 19:40:35 +08:00
parent 4a9d7cc4ab
commit 45c479df00
6 changed files with 126 additions and 41 deletions

View File

@ -1,6 +1,7 @@
using System.Linq; using System.Linq;
using Unity.Mathematics; using Unity.Mathematics;
using UnityEditor; using UnityEditor;
using UnityEditor.EditorTools;
using UnityEditor.IMGUI.Controls; using UnityEditor.IMGUI.Controls;
using UnityEditorInternal; using UnityEditorInternal;
using UnityEngine; using UnityEngine;
@ -18,17 +19,18 @@ namespace X.Rendering.Scene
SerializedProperty boundsProperty; SerializedProperty boundsProperty;
private BoxBoundsHandle boundsHandle = new(); private BoxBoundsHandle boundsHandle = new();
LightData[] lightDatas = null;
public override VisualElement CreateInspectorGUI() public override VisualElement CreateInspectorGUI()
{ {
transform = (target as MonoBehaviour).transform; transform = (target as MonoBehaviour).transform;
var mainLight = GameObject.FindGameObjectWithTag("MainLight")?.GetComponent<Light>(); var mainLight = GameObject.FindGameObjectWithTag("MainLight")?.GetComponent<Light>();
if (mainLight == null ) if (mainLight == null)
{ {
mainLight = GameObject.FindObjectsOfType<Light>().Where(l => l.type == LightType.Directional).First(); mainLight = GameObject.FindObjectsOfType<Light>().Where(l => l.type == LightType.Directional).First();
} }
if(mainLight != null ) if (mainLight != null)
{ {
mainLightDir = (mainLight.transform.rotation * Vector3.forward).normalized; mainLightDir = (mainLight.transform.rotation * Vector3.forward).normalized;
mainLightDir.w = 1; mainLightDir.w = 1;
@ -40,6 +42,8 @@ namespace X.Rendering.Scene
Debug.Log($"{lightList.index}"); Debug.Log($"{lightList.index}");
selectIndex = lightList.index; selectIndex = lightList.index;
}; };
var t = serializedObject.targetObject.GetType().GetField("capsuleLights", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
lightDatas = t.GetValue(serializedObject.targetObject) as LightData[];
lightList.onAddCallback += (_) => lightList.onAddCallback += (_) =>
{ {
@ -48,8 +52,20 @@ namespace X.Rendering.Scene
lightList.index = 0; lightList.index = 0;
} }
lightList.serializedProperty.InsertArrayElementAtIndex(lightList.index); lightList.serializedProperty.InsertArrayElementAtIndex(lightList.index);
lightList.serializedProperty.GetArrayElementAtIndex(lightList.index).vector4Value = mainLightDir; serializedObject.ApplyModifiedProperties();
lightList.Select(lightList.index);
var light = new LightData()
{
isPointLight = true,
lightIntensity = 1,
lightPosition = transform.position + Vector3.up
};
if (lightDatas != null)
{
lightDatas[lightList.index] = light;
lightList.Select(lightList.index);
}
}; };
lightList.drawHeaderCallback = DrawHeader; lightList.drawHeaderCallback = DrawHeader;
@ -63,8 +79,26 @@ namespace X.Rendering.Scene
private void DrawListItems(Rect rect, int index, bool isActive, bool isFocused) private void DrawListItems(Rect rect, int index, bool isActive, bool isFocused)
{ {
SerializedProperty element = lightList.serializedProperty.GetArrayElementAtIndex(index); if(index < 0 )
EditorGUI.LabelField(new Rect(rect.x, rect.y, 200, EditorGUIUtility.singleLineHeight), $"{element.vector4Value}"); {
return;
}
EditorGUI.BeginChangeCheck();
var light = lightDatas[index];
float x = rect.x;
//EditorGUI.LabelField(new Rect(x, rect.y, 50, EditorGUIUtility.singleLineHeight), "点光");
//x += 50;
EditorGUI.LabelField(new Rect(x, rect.y, 150, EditorGUIUtility.singleLineHeight), $"{light.lightPosition}");
x += 140;
light.lightIntensity = EditorGUI.Slider(new Rect(x, rect.y, 200, EditorGUIUtility.singleLineHeight), light.lightIntensity, 0.2f, 2);
x += 210;
light.isPointLight = EditorGUI.ToggleLeft(new Rect(x, rect.y, 50, EditorGUIUtility.singleLineHeight), "点光", light.isPointLight);
if (EditorGUI.EndChangeCheck())
{
Undo.RecordObject(target, "DrawListItems");
CallValidate();
}
} }
private void DrawHeader(Rect rect) private void DrawHeader(Rect rect)
@ -76,11 +110,16 @@ namespace X.Rendering.Scene
public override void OnInspectorGUI() public override void OnInspectorGUI()
{ {
serializedObject.Update(); serializedObject.Update();
base.OnInspectorGUI(); base.OnInspectorGUI();
lightList.DoLayoutList(); lightList.DoLayoutList();
serializedObject.ApplyModifiedProperties(); serializedObject.ApplyModifiedProperties();
} }
private void OnDestroy()
{
Tools.hidden = false;
}
public void OnSceneGUI() public void OnSceneGUI()
{ {
DrawBoundHandle(); DrawBoundHandle();
@ -88,30 +127,58 @@ namespace X.Rendering.Scene
{ {
return; return;
} }
SerializedProperty element = lightList.serializedProperty.GetArrayElementAtIndex(selectIndex); var light = lightDatas[selectIndex];
Tools.hidden = true;
var rot = new float4(element.vector4Value).xyz;
rot += DrawRotationHandle(element.vector4Value);
element.vector4Value = new float4(rot, element.vector4Value.w);
if (!light.isPointLight)
{
var rot = (float3)light.lightPosition;
rot += DrawRotationHandle(light.lightPosition);
light.lightPosition = rot;
}
else
{
var pos = (float3)light.lightPosition;
pos += DrawPositionHandle(light.lightPosition);
light.lightPosition = pos;
}
serializedObject.ApplyModifiedProperties(); serializedObject.ApplyModifiedProperties();
} }
protected void CallValidate()
{
target.GetType().GetMethod("OnValidate", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance).Invoke(target, null);
}
protected float3 DrawPositionHandle(Vector3 vec)
{
EditorGUI.BeginChangeCheck();
var newPos = Handles.PositionHandle(vec, Quaternion.identity);
float3 delta = float3.zero;
if (EditorGUI.EndChangeCheck())
{
Undo.RecordObject(target, "DrawPositionHandle");
delta = newPos - vec;
CallValidate();
}
return delta;
}
protected float3 DrawRotationHandle(Vector3 vec) protected float3 DrawRotationHandle(Vector3 vec)
{ {
EditorGUI.BeginChangeCheck(); EditorGUI.BeginChangeCheck();
var rotation = Quaternion.LookRotation(vec); var rotation = Quaternion.LookRotation(vec);
Vector3 newEuler = Vector3.zero; Vector3 newEuler = Vector3.zero;
Vector3 oldEuler = rotation.eulerAngles; Vector3 oldEuler = rotation.eulerAngles;
var col = Handles.color; var col = Handles.color;
var pos = transform.position; var pos = transform.position;
if (boundsProperty != null) if (boundsProperty != null)
{ {
pos = boundsProperty.boundsValue.center; pos = boundsProperty.boundsValue.center;
} }
Handles.color = Handles.xAxisColor; Handles.color = Handles.xAxisColor;
newEuler.x = Handles.Disc(Quaternion.Euler(oldEuler.x, 0, 0), pos, Vector3.left, HandleUtility.GetHandleSize(pos) * 1.5f, false, 0.1f).eulerAngles.x; newEuler.x = Handles.Disc(Quaternion.Euler(oldEuler.x, 0, 0), pos, Vector3.left, HandleUtility.GetHandleSize(pos) * 1.5f, false, 0.1f).eulerAngles.x;
@ -122,21 +189,16 @@ namespace X.Rendering.Scene
EditorGUI.EndChangeCheck(); EditorGUI.EndChangeCheck();
Handles.ConeHandleCap(0, pos, Quaternion.Euler(newEuler), HandleUtility.GetHandleSize(pos), EventType.Repaint); Handles.ConeHandleCap(0, pos, Quaternion.Euler(newEuler), HandleUtility.GetHandleSize(pos), EventType.Repaint);
Handles.color = col; Handles.color = col;
float3 delta; float3 delta = float3.zero;
var newVec = (Quaternion.Euler(newEuler) * Vector3.forward).normalized; var newVec = (Quaternion.Euler(newEuler) * Vector3.forward).normalized;
if (newVec != vec) if (newVec != vec)
{ {
Undo.RecordObject(target, "DrawRotationHandle"); Undo.RecordObject(target, "DrawRotationHandle");
// Perform the handle move and update the serialized data
delta = newVec - vec; delta = newVec - vec;
} CallValidate();
else
{
delta = float3.zero;
} }
return delta; return delta;
@ -146,7 +208,7 @@ namespace X.Rendering.Scene
{ {
if (boundsProperty == null) if (boundsProperty == null)
{ {
return; return;
} }
EditorGUI.BeginChangeCheck(); EditorGUI.BeginChangeCheck();
@ -156,7 +218,7 @@ namespace X.Rendering.Scene
var newPos = Handles.PositionHandle(bounds.center, transform.rotation); var newPos = Handles.PositionHandle(bounds.center, transform.rotation);
boundsHandle.center = bounds.center; boundsHandle.center = bounds.center;
boundsHandle.size = bounds.size; boundsHandle.size = bounds.size;
boundsHandle.DrawHandle(); boundsHandle.DrawHandle();
if (EditorGUI.EndChangeCheck()) if (EditorGUI.EndChangeCheck())
{ {
Undo.RecordObject(target, "DrawBoundHandle"); Undo.RecordObject(target, "DrawBoundHandle");

View File

@ -14550,16 +14550,18 @@ MonoBehaviour:
CascadeShadowOffset: {x: 0, y: 0, z: 1} CascadeShadowOffset: {x: 0, y: 0, z: 1}
updateInterval: 1 updateInterval: 1
capsuleLights: capsuleLights:
- {x: 0.009531173, y: -0.76794606, z: -0.6404436, w: 1} - lightPosition: {x: 0.30918866, y: -0.7392774, z: -0.5982234}
lightIntensity: 0.92
isPointLight: 0
capsuleAOSetting: capsuleAOSetting:
AmbientIntensity: 3.5 AmbientIntensity: 3.5
ConeAngle: 10.72 ConeAngle: 7.86
ShadowIntensity: 0.28 ShadowIntensity: 0.28
ShadowSharpness: 10.59 ShadowSharpness: 10.3
lightStartID: 0 lightStartID: 0
lightEndID: 1 lightEndID: 1
CapsuleLightsDir: CapsuleLightsDir:
- {x: -0.009531173, y: 0.76794606, z: 0.6404436, w: 1} - {x: -0.30918866, y: 0.7392774, z: 0.5982234, w: 0.92}
- {x: 0, y: 0, z: 0, w: 0} - {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0} - {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0} - {x: 0, y: 0, z: 0, w: 0}
@ -14594,9 +14596,9 @@ MonoBehaviour:
CapsuleLightsDirCount: 1 CapsuleLightsDirCount: 1
capsuleAOAreaSettings: capsuleAOAreaSettings:
- AmbientIntensity: 3.5 - AmbientIntensity: 3.5
ConeAngle: 10.72 ConeAngle: 7.86
ShadowIntensity: 0.28 ShadowIntensity: 0.28
ShadowSharpness: 10.59 ShadowSharpness: 10.3
lightStartID: 0 lightStartID: 0
lightEndID: 1 lightEndID: 1
sceneAreaEffects: [] sceneAreaEffects: []

View File

@ -9,7 +9,7 @@ namespace X.Rendering.Scene
[SerializeField] [SerializeField]
internal CapsuleShadowAreaSetting capsuleAOSetting = CapsuleShadowAreaSetting.GetDefault(); internal CapsuleShadowAreaSetting capsuleAOSetting = CapsuleShadowAreaSetting.GetDefault();
[SerializeField, HideInInspector] [SerializeField, HideInInspector]
internal Vector4[] capsuleLights; internal LightData[] capsuleLights;
[SerializeField, HideInInspector] [SerializeField, HideInInspector]
internal Bounds Bounds = new Bounds(Vector3.zero, Vector3.one); internal Bounds Bounds = new Bounds(Vector3.zero, Vector3.one);

View File

@ -46,6 +46,14 @@ namespace X.Rendering.Scene
} }
} }
[Serializable]
public class LightData
{
public Vector3 lightPosition;
public float lightIntensity = 1;
public bool isPointLight = true;
}
internal class CapsuleShadowPass : ScriptableRenderPass, IDisposable internal class CapsuleShadowPass : ScriptableRenderPass, IDisposable
{ {
[Serializable] [Serializable]

View File

@ -64,8 +64,7 @@ namespace X.Rendering.Scene
private void OnDestroy() private void OnDestroy()
{ {
Shader.DisableKeyword(MultiCapsuleAO); SetEnable(false);
Shader.DisableKeyword(MultiCapsuleShadowAndAO);
shadowRemapPass?.Dispose(); shadowRemapPass?.Dispose();
capsuleAOPass?.Dispose(); capsuleAOPass?.Dispose();
Instance = null; Instance = null;
@ -87,6 +86,8 @@ namespace X.Rendering.Scene
} }
else else
{ {
Shader.DisableKeyword(MultiCapsuleAO);
Shader.DisableKeyword(MultiCapsuleShadowAndAO);
RenderPipelineManager.beginCameraRendering -= OnBeginCamera; RenderPipelineManager.beginCameraRendering -= OnBeginCamera;
} }
} }
@ -108,6 +109,7 @@ namespace X.Rendering.Scene
UpdateCapsuleLights(); UpdateCapsuleLights();
} }
private void OnValidate() private void OnValidate()
{ {
UpdateRenderAssetsSettings(); UpdateRenderAssetsSettings();
@ -127,13 +129,18 @@ namespace X.Rendering.Scene
for (int i = 0; i < capsuleLights?.Length; i++) for (int i = 0; i < capsuleLights?.Length; i++)
{ {
var light = capsuleLights[i]; var light = capsuleLights[i];
var v = -Vector3.Normalize(light); var v = light.lightPosition;
if(!light.isPointLight)
{
v = -Vector3.Normalize(light.lightPosition);
}
lightDirs.Add(new Vector4() lightDirs.Add(new Vector4()
{ {
x = v.x, x = v.x,
y = v.y, y = v.y,
z = v.z, z = v.z,
w = light.w w = light.lightIntensity
}); });
} }
capsuleAOSetting.lightStartID = 0; capsuleAOSetting.lightStartID = 0;
@ -148,13 +155,18 @@ namespace X.Rendering.Scene
for (int j = 0; j < sceneAreaEffect.capsuleLights.Length; j++) for (int j = 0; j < sceneAreaEffect.capsuleLights.Length; j++)
{ {
var light = sceneAreaEffect.capsuleLights[j]; var light = sceneAreaEffect.capsuleLights[j];
var v = -Vector3.Normalize(light); var v = light.lightPosition;
if (!light.isPointLight)
{
v = -Vector3.Normalize(light.lightPosition);
}
lightDirs.Add(new Vector4() lightDirs.Add(new Vector4()
{ {
x = v.x, x = v.x,
y = v.y, y = v.y,
z = v.z, z = v.z,
w = light.w w = light.lightIntensity
}); });
} }
@ -236,7 +248,7 @@ namespace X.Rendering.Scene
#region CapsuleAO #region CapsuleAO
[SerializeField , HideInInspector] [SerializeField , HideInInspector]
private Vector4[] capsuleLights; private LightData[] capsuleLights;
[SerializeField] [SerializeField]
private CapsuleShadowAreaSetting capsuleAOSetting = CapsuleShadowAreaSetting.GetDefault(); private CapsuleShadowAreaSetting capsuleAOSetting = CapsuleShadowAreaSetting.GetDefault();
[HideInInspector] [HideInInspector]

View File

@ -256,8 +256,9 @@ void CalcCapsuleShadow(float3 worldPos, float3 worldNormal, out float shadow, o
for (uint b = area.lightStartID; b < area.lightEndID; ++b) for (uint b = area.lightStartID; b < area.lightEndID; ++b)
{ {
float4 lightDir = _CapsuleLightsDir[b]; float4 lightDir = _CapsuleLightsDir[b];
float4 cone = GetConeProperties(lightDir.xyz, area.ConeAngle); //float4 cone = GetConeProperties(lightDir.xyz, area.ConeAngle);
float tempIntensity = intensity / saturate(1 * smoothstep(0.1, 2, lightDir.w)); float4 cone = GetConeProperties(normalize(lightDir.xyz - worldPos), area.ConeAngle);
float tempIntensity = intensity / smoothstep(0.1, 2, lightDir.w);
float tempShadow = CalcCapsuleShadowByIndex(worldPos, cone.xyz, c.capsuleStartID, c.capsuleEndID, area.ShadowSharpness, tempIntensity, area.ShadowIntensity); float tempShadow = CalcCapsuleShadowByIndex(worldPos, cone.xyz, c.capsuleStartID, c.capsuleEndID, area.ShadowSharpness, tempIntensity, area.ShadowIntensity);
// float tempShadow = CalcCapsuleShadowByIndexV2(worldPos, cone, c.capsuleStartID, c.capsuleEndID, tempIntensity, area.ShadowIntensity); // float tempShadow = CalcCapsuleShadowByIndexV2(worldPos, cone, c.capsuleStartID, c.capsuleEndID, tempIntensity, area.ShadowIntensity);
shadow = min(shadow, tempShadow); shadow = min(shadow, tempShadow);