diff --git a/Assets/Res/Main/Scene/LightTest.unity b/Assets/Res/Main/Scene/LightTest.unity index 1c0dd10..8249887 100644 --- a/Assets/Res/Main/Scene/LightTest.unity +++ b/Assets/Res/Main/Scene/LightTest.unity @@ -122,6 +122,78 @@ NavMeshSettings: debug: m_Flags: 0 m_NavMeshData: {fileID: 0} +--- !u!1 &6388584 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6388586} + - component: {fileID: 6388585} + - component: {fileID: 6388587} + m_Layer: 0 + m_Name: ShadowColliderSystem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &6388585 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6388584} + m_Enabled: 0 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 836b4625937ba9d45be59618cd2a6a15, type: 3} + m_Name: + m_EditorClassIdentifier: + shadowLight: {fileID: 354864581} + shadowWall: {fileID: 1371778128} + shadowLayerName: Shadow + obstacleLayerMask: + serializedVersion: 2 + m_Bits: 1024 + generateOnStart: 1 + updateInRealTime: 0 + updateInterval: 0.1 + shadowColliders: [] +--- !u!4 &6388586 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6388584} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &6388587 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6388584} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 7911d7cd239cfb44c910a896590b2db4, type: 3} + m_Name: + m_EditorClassIdentifier: + shadowLight: {fileID: 354864581} + shadowWall: {fileID: 1371778128} + shadowLayerName: Shadow + keepOriginalMesh: 1 + shadowIntensity: 1 --- !u!1 &282165411 GameObject: m_ObjectHideFlags: 0 @@ -133,9 +205,6 @@ GameObject: - component: {fileID: 282165415} - component: {fileID: 282165414} - component: {fileID: 282165412} - - component: {fileID: 282165416} - - component: {fileID: 282165417} - - component: {fileID: 282165418} m_Layer: 0 m_Name: ShadowCamera m_TagString: Untagged @@ -222,11 +291,11 @@ Camera: far clip plane: 1000 field of view: 60 orthographic: 1 - orthographic size: 3 + orthographic size: 5 m_Depth: 0 m_CullingMask: serializedVersion: 2 - m_Bits: 512 + m_Bits: 1536 m_RenderingPath: -1 m_TargetTexture: {fileID: 8400000, guid: 3746a9ea25b5f084f963f36250ae89a2, type: 2} m_TargetDisplay: 0 @@ -247,78 +316,12 @@ Transform: m_GameObject: {fileID: 282165411} serializedVersion: 2 m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 5, z: 0} + m_LocalPosition: {x: 0, y: 5, z: 4.51} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!114 &282165416 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 282165411} - m_Enabled: 0 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 45374fb251a6d21488433ebd2dcd2203, type: 3} - m_Name: - m_EditorClassIdentifier: - shadowLight: {fileID: 354864581} - obstacleLayer: - m_Bits: 512 - realtimeUpdate: 1 - use2DMode: 1 - rayDistance: 10 - rayCount: 100 - shadowCamera: {fileID: 282165414} - shadowTexture: {fileID: 8400000, guid: 3746a9ea25b5f084f963f36250ae89a2, type: 2} - shadowIntensityThreshold: 0.3 - simplificationThreshold: 0.1 - updateFrameInterval: 3 - minPointDistance: 0.1 - edgeCollider2D: {fileID: 0} - polygonCollider2D: {fileID: 0} - meshCollider3D: {fileID: 0} - shadowMesh: {fileID: 0} - frameCount: 0 ---- !u!114 &282165417 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 282165411} - m_Enabled: 0 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: ac3308532951bea4fa59009510cc632d, type: 3} - m_Name: - m_EditorClassIdentifier: - shadowCamera: {fileID: 282165414} - shadowRenderTexture: {fileID: 8400000, guid: 3746a9ea25b5f084f963f36250ae89a2, type: 2} - wall: {fileID: 767553978} - colliderHeight: 0.1 - shadowTexture: {fileID: 0} - shadowColliders: [] ---- !u!114 &282165418 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 282165411} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 4c8c04e11b9681342bda2a7a35b300b8, type: 3} - m_Name: - m_EditorClassIdentifier: - directionalLight: {fileID: 354864581} - wall: {fileID: 767553978} - casterLayer: - m_Bits: 512 - colliderHeight: 0.1 - shadowColliders: [] --- !u!1 &354864579 GameObject: m_ObjectHideFlags: 0 @@ -372,13 +375,13 @@ Light: m_Type: 0 m_Shape: 0 m_Color: {r: 1, g: 1, b: 1, a: 1} - m_Intensity: 20 - m_Range: 10 + m_Intensity: 200 + m_Range: 20 m_SpotAngle: 52.683002 m_InnerSpotAngle: 44.48507 m_CookieSize: 10 m_Shadows: - m_Type: 2 + m_Type: 1 m_Resolution: -1 m_CustomResolution: -1 m_Strength: 1 @@ -414,7 +417,7 @@ Light: m_Lightmapping: 4 m_LightShadowCasterMode: 0 m_AreaSize: {x: 1, y: 1} - m_BounceIntensity: 1 + m_BounceIntensity: 10 m_ColorTemperature: 6570 m_UseColorTemperature: 0 m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} @@ -431,7 +434,7 @@ Transform: m_GameObject: {fileID: 354864579} serializedVersion: 2 m_LocalRotation: {x: -0.10489331, y: 0.14298823, z: 0.015222758, w: 0.9840325} - m_LocalPosition: {x: -1.1246443, y: 4.4885726, z: -0.15423861} + m_LocalPosition: {x: -2.271, y: 3.618, z: -4.017} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] @@ -574,6 +577,127 @@ Transform: m_Children: [] m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &507957216 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 507957221} + - component: {fileID: 507957220} + - component: {fileID: 507957219} + - component: {fileID: 507957218} + - component: {fileID: 507957217} + m_Layer: 9 + m_Name: Cube (2) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &507957217 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 507957216} + m_Enabled: 0 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 717ba394b4fc8354db9479f2f858d521, type: 3} + m_Name: + m_EditorClassIdentifier: + mainCamera: {fileID: 0} + model3D: {fileID: 507957216} + edgeSegments: 16 +--- !u!65 &507957218 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 507957216} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &507957219 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 507957216} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 31321ba15b8f8eb4c954353edc038b1d, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!33 &507957220 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 507957216} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!4 &507957221 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 507957216} + serializedVersion: 2 + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0.54599994, y: 5.58, z: 2.41} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &767553978 GameObject: m_ObjectHideFlags: 0 @@ -586,14 +710,14 @@ GameObject: - component: {fileID: 767553981} - component: {fileID: 767553980} - component: {fileID: 767553983} - - component: {fileID: 767553984} + - component: {fileID: 767553985} m_Layer: 0 m_Name: Plane m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 - m_IsActive: 1 + m_IsActive: 0 --- !u!23 &767553980 MeshRenderer: m_ObjectHideFlags: 0 @@ -654,7 +778,7 @@ Transform: serializedVersion: 2 m_LocalRotation: {x: -0.7071068, y: 0, z: 0, w: 0.7071068} m_LocalPosition: {x: 0, y: 5, z: 5} - m_LocalScale: {x: 10, y: 10, z: 10} + m_LocalScale: {x: 2, y: 2, z: 2} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} @@ -673,26 +797,31 @@ MonoBehaviour: m_EditorClassIdentifier: shadowCamera: {fileID: 282165414} shadowRT: {fileID: 8400000, guid: 3746a9ea25b5f084f963f36250ae89a2, type: 2} - shadowCasterLayer: - serializedVersion: 2 - m_Bits: 512 - colliderPrecision: 0.1 ---- !u!114 &767553984 -MonoBehaviour: + polygonCollider: {fileID: 0} + shadowThreshold: 0.3 + gridSize: 2 + simplifyTolerance: 2 +--- !u!65 &767553985 +BoxCollider: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 767553978} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 21f7e71103c1a5941af3223174264656, type: 3} - m_Name: - m_EditorClassIdentifier: - spotLight: {fileID: 354864581} - shadowCaster: {fileID: 1455178660} - rayCount: 36 - maxShadowDistance: 10 + serializedVersion: 3 + m_Size: {x: 10, y: 1.2295777, z: 10.000002} + m_Center: {x: 0, y: -0.61478895, z: 1.6312508e-15} --- !u!1 &1283729761 GameObject: m_ObjectHideFlags: 0 @@ -811,6 +940,194 @@ Transform: m_Children: [] m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1 &1371778123 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1371778128} + - component: {fileID: 1371778127} + - component: {fileID: 1371778126} + - component: {fileID: 1371778125} + - component: {fileID: 1371778130} + - component: {fileID: 1371778129} + - component: {fileID: 1371778124} + - component: {fileID: 1371778131} + m_Layer: 10 + m_Name: Cube + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1371778124 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1371778123} + m_Enabled: 0 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 21f7e71103c1a5941af3223174264656, type: 3} + m_Name: + m_EditorClassIdentifier: + spotLight: {fileID: 354864581} + shadowCasters: [] + shadowCasterLayer: + serializedVersion: 2 + m_Bits: 0 + shadowReceiverLayer: + serializedVersion: 2 + m_Bits: 0 + maxShadowDistance: 10 + shadowCollider: {fileID: 1974410756} +--- !u!65 &1371778125 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1371778123} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &1371778126 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1371778123} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 31321ba15b8f8eb4c954353edc038b1d, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!33 &1371778127 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1371778123} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!4 &1371778128 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1371778123} + serializedVersion: 2 + m_LocalRotation: {x: -0.7071068, y: 0, z: -0, w: 0.7071068} + m_LocalPosition: {x: 0, y: 5, z: 6} + m_LocalScale: {x: 10, y: 1, z: 10} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1974410755} + - {fileID: 1835604431} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1371778129 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1371778123} + m_Enabled: 0 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 28f43899f7559ca4e915497eaf23cc4f, type: 3} + m_Name: + m_EditorClassIdentifier: + shadowCamera: {fileID: 282165414} + shadowRT: {fileID: 8400000, guid: 3746a9ea25b5f084f963f36250ae89a2, type: 2} + polygonCollider: {fileID: 1974410756} + shadowThreshold: 0 + gridSize: 2 + simplifyTolerance: 0.1 +--- !u!114 &1371778130 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1371778123} + m_Enabled: 0 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 7b369cd814f44044d8a55791d065e3fb, type: 3} + m_Name: + m_EditorClassIdentifier: + shadowCamera: {fileID: 282165414} + shadowRT: {fileID: 8400000, guid: 3746a9ea25b5f084f963f36250ae89a2, type: 2} + polygonCollider: {fileID: 1974410756} + shadowThreshold: 0.1 + gridResolution: 64 + minContourArea: 10 + maxGapDistance: 20 +--- !u!114 &1371778131 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1371778123} + m_Enabled: 0 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: eb1369db1529b6543ba24519d5c2a35d, type: 3} + m_Name: + m_EditorClassIdentifier: + shadowCamera: {fileID: 282165414} + shadowRT: {fileID: 8400000, guid: 3746a9ea25b5f084f963f36250ae89a2, type: 2} + polygonCollider: {fileID: 1974410756} + shadowThreshold: 0.1 + downSample: 4 + minShadowSize: 0.1 --- !u!1 &1455178660 GameObject: m_ObjectHideFlags: 0 @@ -823,6 +1140,7 @@ GameObject: - component: {fileID: 1455178663} - component: {fileID: 1455178662} - component: {fileID: 1455178661} + - component: {fileID: 1455178665} m_Layer: 9 m_Name: Cube m_TagString: Untagged @@ -910,19 +1228,263 @@ Transform: m_GameObject: {fileID: 1455178660} serializedVersion: 2 m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 5, z: 2.41} + m_LocalPosition: {x: -0.787, y: 5.58, z: 2.41} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1455178665 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1455178660} + m_Enabled: 0 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 717ba394b4fc8354db9479f2f858d521, type: 3} + m_Name: + m_EditorClassIdentifier: + mainCamera: {fileID: 0} + model3D: {fileID: 1455178660} + edgeSegments: 16 +--- !u!1 &1835604430 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1835604431} + - component: {fileID: 1835604433} + - component: {fileID: 1835604432} + - component: {fileID: 1835604434} + m_Layer: 10 + m_Name: GameObject (1) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!4 &1835604431 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1835604430} + serializedVersion: 2 + m_LocalRotation: {x: 0.7071068, y: -0, z: 0, w: 0.7071068} + m_LocalPosition: {x: 0.181, y: 0.5, z: 0.5159} + m_LocalScale: {x: 0.1, y: 0.09999998, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1371778128} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!50 &1835604432 +Rigidbody2D: + serializedVersion: 4 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1835604430} + m_BodyType: 0 + m_Simulated: 1 + m_UseFullKinematicContacts: 0 + m_UseAutoMass: 0 + m_Mass: 1 + m_LinearDrag: 0 + m_AngularDrag: 0.05 + m_GravityScale: 1 + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_Interpolate: 0 + m_SleepingMode: 1 + m_CollisionDetection: 0 + m_Constraints: 0 +--- !u!212 &1835604433 +SpriteRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1835604430} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 0 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10754, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 0 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 1 + m_Sprite: {fileID: 21300000, guid: 3d67b5c335d66e74d81f6f34263a17be, type: 3} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_FlipX: 0 + m_FlipY: 0 + m_DrawMode: 0 + m_Size: {x: 1, y: 1} + m_AdaptiveModeThreshold: 0.5 + m_SpriteTileMode: 0 + m_WasSpriteAssigned: 1 + m_MaskInteraction: 0 + m_SpriteSortPoint: 0 +--- !u!58 &1835604434 +CircleCollider2D: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1835604430} + m_Enabled: 1 + m_Density: 1 + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_ForceSendLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_ForceReceiveLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_ContactCaptureLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_CallbackLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_IsTrigger: 0 + m_UsedByEffector: 0 + m_UsedByComposite: 0 + m_Offset: {x: 0, y: 0.0000009536743} + serializedVersion: 2 + m_Radius: 2.5600011 +--- !u!1 &1974410754 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1974410755} + - component: {fileID: 1974410756} + m_Layer: 10 + m_Name: GameObject + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1974410755 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1974410754} + serializedVersion: 2 + m_LocalRotation: {x: 0.7071068, y: 0, z: 0, w: 0.7071068} + m_LocalPosition: {x: 0, y: 0.5, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1371778128} + m_LocalEulerAnglesHint: {x: 90, y: 0, z: 0} +--- !u!60 &1974410756 +PolygonCollider2D: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1974410754} + m_Enabled: 1 + m_Density: 1 + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_ForceSendLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_ForceReceiveLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_ContactCaptureLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_CallbackLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_IsTrigger: 0 + m_UsedByEffector: 0 + m_UsedByComposite: 0 + m_Offset: {x: 0, y: 0} + m_SpriteTilingProperty: + border: {x: 0.049999997, y: 0.049999997, z: 0.049999997, w: 0.049999997} + pivot: {x: 0.5, y: 0.5} + oldSize: {x: 0.16, y: 0.16} + newSize: {x: 0.16, y: 0.16} + adaptiveTilingThreshold: 0.5 + drawMode: 0 + adaptiveTiling: 0 + m_AutoTiling: 0 + m_Points: + m_Paths: + - [] + m_UseDelaunayMesh: 0 --- !u!1660057539 &9223372036854775807 SceneRoots: m_ObjectHideFlags: 0 m_Roots: - {fileID: 354864582} + - {fileID: 1371778128} - {fileID: 767553982} - {fileID: 488143182} - {fileID: 1283729764} - {fileID: 282165415} - {fileID: 1455178664} + - {fileID: 507957221} + - {fileID: 6388586} diff --git a/Assets/Scripts/Test/Light/Dynamic3DTo2DCollider.cs b/Assets/Scripts/Test/Light/Dynamic3DTo2DCollider.cs new file mode 100644 index 0000000..ad44305 --- /dev/null +++ b/Assets/Scripts/Test/Light/Dynamic3DTo2DCollider.cs @@ -0,0 +1,129 @@ +using UnityEngine; +using System.Collections.Generic; + +public class Dynamic3DTo2DCollider : MonoBehaviour +{ + public Camera mainCamera; + public GameObject model3D; + [Range(4, 32)] public int edgeSegments = 16; + + void Start() + { + if (mainCamera == null) + mainCamera = Camera.main; + + Convert3DTo2DCollider(); + } + + void Convert3DTo2DCollider() + { + MeshFilter meshFilter = model3D.GetComponent(); + if (meshFilter == null) return; + + // 获取网格的所有顶点 + Vector3[] vertices = meshFilter.mesh.vertices; + int[] triangles = meshFilter.mesh.triangles; + + // 收集所有在轮廓边缘的顶点 + List silhouettePoints = GetSilhouettePoints(vertices, triangles); + + if (silhouettePoints.Count > 2) + { + // 创建2D碰撞器 + GameObject obj = new GameObject(gameObject.name + "2D"); + PolygonCollider2D collider2D = obj.AddComponent(); + collider2D.points = silhouettePoints.ToArray(); + + // 禁用3D碰撞器 + Collider collider3D = model3D.GetComponent(); + if (collider3D != null) collider3D.enabled = false; + } + } + + List GetSilhouettePoints(Vector3[] vertices, int[] triangles) + { + List screenPoints = new List(); + HashSet uniquePoints = new HashSet(); + + // 转换所有顶点到屏幕空间 + for (int i = 0; i < vertices.Length; i++) + { + Vector3 worldPos = model3D.transform.TransformPoint(vertices[i]); + Vector2 screenPos = mainCamera.WorldToScreenPoint(worldPos); + + // 只添加在相机前方的点 + if (IsInFrontOfCamera(worldPos)) + { + uniquePoints.Add(screenPos); + } + } + + screenPoints.AddRange(uniquePoints); + + // 计算凸包来获得轮廓 + return CalculateConvexHull(screenPoints); + } + + bool IsInFrontOfCamera(Vector3 worldPos) + { + Vector3 viewportPos = mainCamera.WorldToViewportPoint(worldPos); + return viewportPos.z > 0; + } + + // 计算凸包的Graham Scan算法 + List CalculateConvexHull(List points) + { + if (points.Count < 3) return points; + + // 找到最左下角的点 + Vector2 pivot = points[0]; + for (int i = 1; i < points.Count; i++) + { + if (points[i].y < pivot.y || (points[i].y == pivot.y && points[i].x < pivot.x)) + pivot = points[i]; + } + + // 按极角排序 + points.Sort((a, b) => + { + float angleA = Mathf.Atan2(a.y - pivot.y, a.x - pivot.x); + float angleB = Mathf.Atan2(b.y - pivot.y, b.x - pivot.x); + + if (angleA < angleB) return -1; + if (angleA > angleB) return 1; + + // 如果角度相同,按距离排序 + float distA = (a - pivot).sqrMagnitude; + float distB = (b - pivot).sqrMagnitude; + return distA.CompareTo(distB); + }); + + // Graham Scan算法 + List hull = new List(); + hull.Add(points[0]); + hull.Add(points[1]); + + for (int i = 2; i < points.Count; i++) + { + while (hull.Count >= 2) + { + Vector2 a = hull[hull.Count - 2]; + Vector2 b = hull[hull.Count - 1]; + Vector2 c = points[i]; + + if (Cross(b - a, c - b) <= 0) + hull.RemoveAt(hull.Count - 1); + else + break; + } + hull.Add(points[i]); + } + + return hull; + } + + float Cross(Vector2 a, Vector2 b) + { + return a.x * b.y - a.y * b.x; + } +} \ No newline at end of file diff --git a/Assets/Scripts/Test/Light/Dynamic3DTo2DCollider.cs.meta b/Assets/Scripts/Test/Light/Dynamic3DTo2DCollider.cs.meta new file mode 100644 index 0000000..838554f --- /dev/null +++ b/Assets/Scripts/Test/Light/Dynamic3DTo2DCollider.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 717ba394b4fc8354db9479f2f858d521 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Test/Light/MarchingSquaresShadowCollider.cs b/Assets/Scripts/Test/Light/MarchingSquaresShadowCollider.cs new file mode 100644 index 0000000..074d4ce --- /dev/null +++ b/Assets/Scripts/Test/Light/MarchingSquaresShadowCollider.cs @@ -0,0 +1,340 @@ +using UnityEngine; +using System.Collections.Generic; +using System.Linq; + +public class MarchingSquaresShadowCollider : MonoBehaviour +{ + [Header("References")] + public Camera shadowCamera; + public RenderTexture shadowRT; + public PolygonCollider2D polygonCollider; + + [Header("Settings")] + [Range(0f, 1f)] + public float shadowThreshold = 0.5f; + public int gridResolution = 40; + public float minContourArea = 50f; + public float maxGapDistance = 20f; + + private Texture2D processedTexture; + private List> separateContours = new List>(); + + void Start() + { + if (polygonCollider == null) + polygonCollider = GetComponent(); + + processedTexture = new Texture2D(shadowRT.width, shadowRT.height, TextureFormat.RGBA32, false); + GenerateCollider(); + } + + void Update() + { + if (Input.GetKeyDown(KeyCode.Space)) + { + GenerateCollider(); + } + } + + [ContextMenu("Generate Collider")] + public void GenerateCollider() + { + if (shadowCamera == null || shadowRT == null) return; + + // 渲染并读取纹理 + shadowCamera.Render(); + RenderTexture.active = shadowRT; + processedTexture.ReadPixels(new Rect(0, 0, shadowRT.width, shadowRT.height), 0, 0); + processedTexture.Apply(); + RenderTexture.active = null; + + // 找到所有独立的轮廓 + separateContours = FindSeparateContours(); + + // 设置多边形碰撞器路径 + if (separateContours.Count > 0) + { + polygonCollider.pathCount = separateContours.Count; + + for (int i = 0; i < separateContours.Count; i++) + { + List worldPoints = ConvertToWorldCoordinates(separateContours[i]); + polygonCollider.SetPath(i, worldPoints); + } + + Debug.Log($"Created {separateContours.Count} separate collider paths"); + } + else + { + polygonCollider.pathCount = 0; + Debug.LogWarning("No contours found"); + } + } + + List> FindSeparateContours() + { + List allEdgePoints = ExtractEdgePoints(); + List> contours = new List>(); + + // 使用区域生长算法找到独立的轮廓 + List unassignedPoints = new List(allEdgePoints); + + while (unassignedPoints.Count > 0) + { + List currentContour = new List(); + Queue pointsToProcess = new Queue(); + + // 从第一个未分配的点开始 + pointsToProcess.Enqueue(unassignedPoints[0]); + unassignedPoints.RemoveAt(0); + + while (pointsToProcess.Count > 0) + { + Vector2 current = pointsToProcess.Dequeue(); + currentContour.Add(current); + + // 查找附近的点 + for (int i = unassignedPoints.Count - 1; i >= 0; i--) + { + if (Vector2.Distance(current, unassignedPoints[i]) <= maxGapDistance) + { + pointsToProcess.Enqueue(unassignedPoints[i]); + unassignedPoints.RemoveAt(i); + } + } + } + + // 连接轮廓点并过滤小区域 + if (currentContour.Count > 3) + { + List connectedContour = ConnectContourPoints(currentContour); + float area = CalculateContourArea(connectedContour); + + if (area >= minContourArea) + { + contours.Add(connectedContour); + } + } + } + + Debug.Log($"Found {contours.Count} separate contours"); + return contours; + } + + List ExtractEdgePoints() + { + List points = new List(); + int width = processedTexture.width; + int height = processedTexture.height; + int step = Mathf.Max(width, height) / gridResolution; + + // 扫描整个纹理寻找阴影边缘 + for (int x = step; x < width - step; x += step) + { + for (int y = step; y < height - step; y += step) + { + if (IsEdgePoint(x, y, step)) + { + points.Add(new Vector2(x, y)); + } + } + } + + Debug.Log($"Found {points.Count} edge points"); + return points; + } + + bool IsEdgePoint(int x, int y, int step) + { + Color center = processedTexture.GetPixel(x, y); + bool isShadow = center.grayscale < shadowThreshold; + + if (!isShadow) return false; + + // 检查8邻域是否有非阴影点 + for (int dx = -step; dx <= step; dx += step) + { + for (int dy = -step; dy <= step; dy += step) + { + if (dx == 0 && dy == 0) continue; + + int nx = x + dx; + int ny = y + dy; + + if (nx >= 0 && nx < processedTexture.width && ny >= 0 && ny < processedTexture.height) + { + Color neighbor = processedTexture.GetPixel(nx, ny); + if (neighbor.grayscale >= shadowThreshold) + { + return true; + } + } + } + } + + return false; + } + + List ConnectContourPoints(List points) + { + if (points.Count < 3) return points; + + List connected = new List(); + List remaining = new List(points); + + // 找到最左边的点作为起点 + Vector2 start = remaining.OrderBy(p => p.x).First(); + connected.Add(start); + remaining.Remove(start); + + Vector2 current = start; + + // 按顺时针方向连接点 + while (remaining.Count > 0) + { + // 找到与当前点角度变化最小的点 + float bestAngle = float.MaxValue; + Vector2 bestPoint = remaining[0]; + int bestIndex = 0; + + Vector2 prevDir = connected.Count > 1 ? + (current - connected[connected.Count - 2]).normalized : + Vector2.right; + + for (int i = 0; i < remaining.Count; i++) + { + Vector2 toNext = (remaining[i] - current).normalized; + float angle = Vector2.SignedAngle(prevDir, toNext); + + // 优先选择向右转的点(顺时针) + if (angle < bestAngle && angle >= 0) + { + bestAngle = angle; + bestPoint = remaining[i]; + bestIndex = i; + } + } + + // 如果没有找到合适的点,选择最近的点 + if (bestAngle == float.MaxValue) + { + bestPoint = remaining.OrderBy(p => Vector2.Distance(current, p)).First(); + bestIndex = remaining.IndexOf(bestPoint); + } + + connected.Add(bestPoint); + remaining.RemoveAt(bestIndex); + current = bestPoint; + } + + // 确保轮廓闭合 + if (Vector2.Distance(connected[0], connected[connected.Count - 1]) > maxGapDistance) + { + connected.Add(connected[0]); + } + + return connected; + } + + float CalculateContourArea(List points) + { + if (points.Count < 3) return 0f; + + float area = 0f; + int n = points.Count; + + for (int i = 0; i < n; i++) + { + Vector2 current = points[i]; + Vector2 next = points[(i + 1) % n]; + area += (current.x * next.y) - (next.x * current.y); + } + + return Mathf.Abs(area / 2f); + } + + List ConvertToWorldCoordinates(List texturePoints) + { + List worldPoints = new List(); + + foreach (Vector2 texCoord in texturePoints) + { + Vector3 viewportPos = new Vector3( + texCoord.x / processedTexture.width, + texCoord.y / processedTexture.height, + shadowCamera.nearClipPlane + ); + + Vector3 worldPos = shadowCamera.ViewportToWorldPoint(viewportPos); + worldPoints.Add(new Vector2(worldPos.x, worldPos.y)); + } + + return worldPoints; + } + + // 调试可视化 + void OnDrawGizmosSelected() + { + if (separateContours == null) return; + + Color[] colors = { Color.red, Color.green, Color.blue, Color.yellow, Color.cyan, Color.magenta }; + + for (int i = 0; i < separateContours.Count; i++) + { + Gizmos.color = colors[i % colors.Length]; + List contour = separateContours[i]; + + foreach (Vector2 point in contour) + { + Vector3 viewportPos = new Vector3( + point.x / processedTexture.width, + point.y / processedTexture.height, + shadowCamera.nearClipPlane + ); + Vector3 worldPos = shadowCamera.ViewportToWorldPoint(viewportPos); + Gizmos.DrawSphere(worldPos, 0.05f); + } + + // 绘制轮廓线 + if (contour.Count > 1) + { + for (int j = 0; j < contour.Count; j++) + { + Vector2 start = contour[j]; + Vector2 end = contour[(j + 1) % contour.Count]; + + Vector3 startWorld = shadowCamera.ViewportToWorldPoint(new Vector3( + start.x / processedTexture.width, + start.y / processedTexture.height, + shadowCamera.nearClipPlane + )); + Vector3 endWorld = shadowCamera.ViewportToWorldPoint(new Vector3( + end.x / processedTexture.width, + end.y / processedTexture.height, + shadowCamera.nearClipPlane + )); + + Gizmos.DrawLine(startWorld, endWorld); + } + } + } + } + + [ContextMenu("Debug Contour Info")] + void DebugContourInfo() + { + shadowCamera.Render(); + RenderTexture.active = shadowRT; + processedTexture.ReadPixels(new Rect(0, 0, shadowRT.width, shadowRT.height), 0, 0); + processedTexture.Apply(); + RenderTexture.active = null; + + List> contours = FindSeparateContours(); + + for (int i = 0; i < contours.Count; i++) + { + float area = CalculateContourArea(contours[i]); + Debug.Log($"Contour {i}: {contours[i].Count} points, area: {area}"); + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/Test/Light/MarchingSquaresShadowCollider.cs.meta b/Assets/Scripts/Test/Light/MarchingSquaresShadowCollider.cs.meta new file mode 100644 index 0000000..79ffe76 --- /dev/null +++ b/Assets/Scripts/Test/Light/MarchingSquaresShadowCollider.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7b369cd814f44044d8a55791d065e3fb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Test/Light/MeshShadowProjector.cs b/Assets/Scripts/Test/Light/MeshShadowProjector.cs new file mode 100644 index 0000000..8d39be0 --- /dev/null +++ b/Assets/Scripts/Test/Light/MeshShadowProjector.cs @@ -0,0 +1,336 @@ +using UnityEngine; +using System.Collections.Generic; + +public class MeshShadowProjector : MonoBehaviour +{ + [Header("投影设置")] + public Light shadowLight; + public Transform shadowWall; + public string shadowLayerName = "Shadow"; + + [Header("Mesh设置")] + public bool keepOriginalMesh = true; // 是否保留原始mesh + public float shadowIntensity = 0.5f; // 阴影强度 + + private List modifiedObjects = new List(); + private Vector3 wallNormal; + private Vector3 wallPosition; + + void Start() + { + if (shadowLight == null) shadowLight = FindObjectOfType(); + if (shadowWall == null) shadowWall = FindMainWall(); + + CalculateWallPlane(); + GenerateAllShadowMeshes(); + } + + [ContextMenu("生成所有阴影Mesh")] + public void GenerateAllShadowMeshes() + { + ClearAllShadowMeshes(); + + var shadowObjects = FindObjectsInLayer(shadowLayerName); + foreach (GameObject obj in shadowObjects) + { + GenerateShadowMesh(obj); + } + + Debug.Log($"为 {modifiedObjects.Count} 个物体生成了阴影Mesh"); + } + + void GenerateShadowMesh(GameObject shadowCaster) + { + MeshFilter meshFilter = shadowCaster.GetComponent(); + if (meshFilter == null) return; + + // 获取原始mesh + Mesh originalMesh = meshFilter.mesh; + + // 创建新的mesh(组合原始mesh + 投影mesh) + Mesh combinedMesh = CreateCombinedMesh(originalMesh, shadowCaster.transform); + + // 应用新mesh + if (keepOriginalMesh) + { + // 创建新物体来存放阴影mesh + CreateShadowObject(shadowCaster, combinedMesh); + } + else + { + // 直接修改原物体 + meshFilter.mesh = combinedMesh; + UpdateMeshCollider(shadowCaster, combinedMesh); + modifiedObjects.Add(shadowCaster); + } + } + + Mesh CreateCombinedMesh(Mesh originalMesh, Transform objectTransform) + { + // 创建新mesh + Mesh newMesh = new Mesh(); + + List vertices = new List(); + List triangles = new List(); + List normals = new List(); + List uv = new List(); + + // 1. 添加原始mesh的顶点和三角形 + vertices.AddRange(originalMesh.vertices); + triangles.AddRange(originalMesh.triangles); + + // 复制原始法线和UV + if (originalMesh.normals.Length == originalMesh.vertices.Length) + normals.AddRange(originalMesh.normals); + else + for (int i = 0; i < originalMesh.vertices.Length; i++) + normals.Add(Vector3.up); + + if (originalMesh.uv.Length == originalMesh.vertices.Length) + uv.AddRange(originalMesh.uv); + else + for (int i = 0; i < originalMesh.vertices.Length; i++) + uv.Add(Vector2.zero); + + // 2. 添加投影到墙面的顶点 + int originalVertexCount = vertices.Count; + List projectedVertices = new List(); + List projectedTriangles = new List(); + + // 投影每个顶点到墙面 + foreach (Vector3 localVertex in originalMesh.vertices) + { + Vector3 worldVertex = objectTransform.TransformPoint(localVertex); + Vector3 projectedWorld = ProjectPointToWall(worldVertex); + Vector3 projectedLocal = objectTransform.InverseTransformPoint(projectedWorld); + + projectedVertices.Add(projectedLocal); + } + + // 添加投影顶点 + vertices.AddRange(projectedVertices); + + // 为投影顶点添加法线和UV + for (int i = 0; i < projectedVertices.Count; i++) + { + normals.Add(-objectTransform.forward); // 面向墙面 + uv.Add(new Vector2(1, 1)); // 使用不同的UV区域 + } + + // 3. 创建连接原始mesh和投影mesh的侧面三角形 + for (int i = 0; i < originalMesh.triangles.Length; i += 3) + { + int v1 = originalMesh.triangles[i]; + int v2 = originalMesh.triangles[i + 1]; + int v3 = originalMesh.triangles[i + 2]; + + // 对应的投影顶点索引 + int p1 = v1 + originalVertexCount; + int p2 = v2 + originalVertexCount; + int p3 = v3 + originalVertexCount; + + // 创建侧面四边形(两个三角形) + // 三角形1 + projectedTriangles.Add(v1); + projectedTriangles.Add(p1); + projectedTriangles.Add(v2); + + projectedTriangles.Add(v2); + projectedTriangles.Add(p1); + projectedTriangles.Add(p2); + + // 三角形2 + projectedTriangles.Add(v2); + projectedTriangles.Add(p2); + projectedTriangles.Add(v3); + + projectedTriangles.Add(v3); + projectedTriangles.Add(p2); + projectedTriangles.Add(p3); + + // 三角形3 + projectedTriangles.Add(v3); + projectedTriangles.Add(p3); + projectedTriangles.Add(v1); + + projectedTriangles.Add(v1); + projectedTriangles.Add(p3); + projectedTriangles.Add(p1); + } + + // 4. 添加投影面的三角形(反转原始三角形) + int[] originalTriangles = originalMesh.triangles; + for (int i = 0; i < originalTriangles.Length; i += 3) + { + // 反转 winding order + projectedTriangles.Add(originalTriangles[i + 2] + originalVertexCount); + projectedTriangles.Add(originalTriangles[i + 1] + originalVertexCount); + projectedTriangles.Add(originalTriangles[i] + originalVertexCount); + } + + // 5. 合并所有三角形 + triangles.AddRange(projectedTriangles); + + // 6. 应用到新mesh + newMesh.vertices = vertices.ToArray(); + newMesh.triangles = triangles.ToArray(); + newMesh.normals = normals.ToArray(); + newMesh.uv = uv.ToArray(); + + newMesh.RecalculateBounds(); + newMesh.RecalculateTangents(); + + return newMesh; + } + + void CreateShadowObject(GameObject original, Mesh shadowMesh) + { + GameObject shadowObject = new GameObject($"{original.name}_ShadowMesh"); + shadowObject.transform.SetParent(original.transform); + shadowObject.transform.localPosition = Vector3.zero; + shadowObject.transform.localRotation = Quaternion.identity; + shadowObject.transform.localScale = Vector3.one; + + // 添加Mesh Filter + MeshFilter meshFilter = shadowObject.AddComponent(); + meshFilter.mesh = shadowMesh; + + // 添加Mesh Collider + MeshCollider meshCollider = shadowObject.AddComponent(); + meshCollider.sharedMesh = shadowMesh; + meshCollider.convex = false; // 对于复杂mesh使用非凸体 + + // 可选:添加材质用于可视化 + MeshRenderer renderer = shadowObject.AddComponent(); + renderer.material = original.GetComponent().material; + + modifiedObjects.Add(shadowObject); + } + + void UpdateMeshCollider(GameObject obj, Mesh mesh) + { + MeshCollider meshCollider = obj.GetComponent(); + if (meshCollider == null) + meshCollider = obj.AddComponent(); + + meshCollider.sharedMesh = mesh; + meshCollider.convex = false; + } + + Material CreateShadowMaterial() + { + Material material = new Material(Shader.Find("Standard")); + material.color = new Color(0, 0, 0, shadowIntensity); + material.SetFloat("_Mode", 2); // Fade mode + material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha); + material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha); + material.SetInt("_ZWrite", 0); + material.DisableKeyword("_ALPHATEST_ON"); + material.EnableKeyword("_ALPHABLEND_ON"); + material.DisableKeyword("_ALPHAPREMULTIPLY_ON"); + material.renderQueue = 3000; + return material; + } + + Vector3 ProjectPointToWall(Vector3 worldPoint) + { + Vector3 lightDirection = GetLightDirection(worldPoint); + return IntersectWithWall(worldPoint, lightDirection); + } + + Vector3 GetLightDirection(Vector3 targetPoint) + { + if (shadowLight.type == LightType.Directional) + { + return -shadowLight.transform.forward; + } + else + { + return (targetPoint - shadowLight.transform.position).normalized; + } + } + + Vector3 IntersectWithWall(Vector3 point, Vector3 direction) + { + float denominator = Vector3.Dot(direction, wallNormal); + + if (Mathf.Abs(denominator) < 0.0001f) + return point; + + float t = Vector3.Dot(wallPosition - point, wallNormal) / denominator; + return point + direction * t; + } + + void CalculateWallPlane() + { + if (shadowWall != null) + { + wallPosition = shadowWall.position; + wallNormal = -shadowWall.forward; + } + } + + Transform FindMainWall() + { + BoxCollider[] colliders = FindObjectsOfType(); + return colliders.Length > 0 ? colliders[0].transform : transform; + } + + List FindObjectsInLayer(string layerName) + { + int layer = LayerMask.NameToLayer(layerName); + List result = new List(); + + foreach (GameObject obj in FindObjectsOfType()) + { + if (obj.activeInHierarchy && obj.layer == layer) + { + result.Add(obj); + } + } + + return result; + } + + [ContextMenu("清空所有阴影Mesh")] + void ClearAllShadowMeshes() + { + foreach (GameObject obj in modifiedObjects) + { + if (obj != null) + { + if (obj.name.EndsWith("_ShadowMesh")) + DestroyImmediate(obj); + else + ResetOriginalMesh(obj); + } + } + modifiedObjects.Clear(); + } + + void ResetOriginalMesh(GameObject obj) + { + MeshFilter meshFilter = obj.GetComponent(); + if (meshFilter != null && meshFilter.mesh != null) + { + // 重新加载原始mesh + Mesh originalMesh = Instantiate(Resources.Load(obj.name)) ?? CreateSimpleMesh(); + meshFilter.mesh = originalMesh; + + MeshCollider collider = obj.GetComponent(); + if (collider != null) + collider.sharedMesh = originalMesh; + } + } + + Mesh CreateSimpleMesh() + { + // 创建默认的立方体mesh + return GameObject.CreatePrimitive(PrimitiveType.Cube).GetComponent().sharedMesh; + } + + void OnDestroy() + { + ClearAllShadowMeshes(); + } +} \ No newline at end of file diff --git a/Assets/Scripts/Test/Light/MeshShadowProjector.cs.meta b/Assets/Scripts/Test/Light/MeshShadowProjector.cs.meta new file mode 100644 index 0000000..1c0e994 --- /dev/null +++ b/Assets/Scripts/Test/Light/MeshShadowProjector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7911d7cd239cfb44c910a896590b2db4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Test/Light/New.meta b/Assets/Scripts/Test/Light/New.meta new file mode 100644 index 0000000..3884929 --- /dev/null +++ b/Assets/Scripts/Test/Light/New.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f17787cb19d6fd24ab50665a7b16a04a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Test/Light/New/MarchingSquaresProcessor.cs b/Assets/Scripts/Test/Light/New/MarchingSquaresProcessor.cs new file mode 100644 index 0000000..b2f4e79 --- /dev/null +++ b/Assets/Scripts/Test/Light/New/MarchingSquaresProcessor.cs @@ -0,0 +1,259 @@ +using UnityEngine; +using System.Collections.Generic; + +[System.Serializable] +public class MarchingSquaresProcessor +{ + [Header("Marching Squares设置")] + public float isoLevel = 0.5f; + public bool smoothEdges = true; + public float smoothness = 0.1f; + + // Marching Squares查找表 + private static readonly int[,] transitionTable = new int[,] + { + {-1, -1, -1, -1}, // 0: 空单元格 + { 0, 3, -1, -1}, // 1: 只有左下角 + { 1, 0, -1, -1}, // 2: 只有右下角 + { 1, 3, -1, -1}, // 3: 下边 + { 2, 1, -1, -1}, // 4: 只有右上角 + { 0, 3, 2, 1}, // 5: S形状 + { 2, 0, -1, -1}, // 6: 右边 + { 2, 3, -1, -1}, // 7: 右下三角 + { 3, 2, -1, -1}, // 8: 只有左上角 + { 0, 2, -1, -1}, // 9: 左边 + { 0, 1, 3, 2}, // 10: S形状(反转) + { 1, 2, -1, -1}, // 11: 左下三角 + { 3, 1, -1, -1}, // 12: 上边 + { 3, 0, -1, -1}, // 13: 右上三角 + { 1, 3, -1, -1}, // 14: 左上三角 + {-1, -1, -1, -1} // 15: 全满 + }; + + public List> ExtractContours(DensityGrid grid) + { + var contours = new List>(); + bool[,] visited = new bool[grid.Width, grid.Height]; + + for (int x = 0; x < grid.Width - 1; x++) + { + for (int y = 0; y < grid.Height - 1; y++) + { + if (!visited[x, y] && IsBoundaryCell(grid, x, y)) + { + var contour = MarchCell(grid, x, y, visited); + if (contour != null && contour.Count >= 3) + { + if (smoothEdges) + contour = SmoothContour(contour); + contours.Add(contour); + } + } + } + } + + return contours; + } + + List MarchCell(DensityGrid grid, int startX, int startY, bool[,] visited) + { + var contour = new List(); + int x = startX, y = startY; + int step = 0; + int maxSteps = grid.Width * grid.Height; // 防止无限循环 + + do + { + // 边界检查 + if (x < 0 || x >= grid.Width - 1 || y < 0 || y >= grid.Height - 1) + break; + + if (visited[x, y]) + break; + + visited[x, y] = true; + + int config = GetCellConfiguration(grid, x, y); + var edgePoints = GetEdgePoints(grid, x, y, config); + + // 只添加有效的点 + foreach (var point in edgePoints) + { + if (!contour.Contains(point)) // 简单的去重 + contour.Add(point); + } + + // 移动到下一个单元格 + if (!MoveToNextCell(config, ref x, ref y)) + break; + + step++; + + } while ((x != startX || y != startY) && step < maxSteps); + + return contour; + } + + int GetCellConfiguration(DensityGrid grid, int x, int y) + { + int config = 0; + + // 安全地获取值,处理边界情况 + float a = GetSafeValue(grid, x, y); + float b = GetSafeValue(grid, x + 1, y); + float c = GetSafeValue(grid, x + 1, y + 1); + float d = GetSafeValue(grid, x, y + 1); + + if (a >= isoLevel) config |= 1; + if (b >= isoLevel) config |= 2; + if (c >= isoLevel) config |= 4; + if (d >= isoLevel) config |= 8; + + return config; + } + + float GetSafeValue(DensityGrid grid, int x, int y) + { + if (x < 0 || x >= grid.Width || y < 0 || y >= grid.Height) + return 0f; + return grid.GetValue(x, y); + } + + Vector2[] GetEdgePoints(DensityGrid grid, int x, int y, int config) + { + var points = new List(); + + // 根据配置添加边点 + switch (config) + { + case 1: + case 14: + points.Add(InterpolateEdge(grid, x, y, x, y + 1)); // 左边 + points.Add(InterpolateEdge(grid, x, y, x + 1, y)); // 底边 + break; + case 2: + case 13: + points.Add(InterpolateEdge(grid, x, y, x + 1, y)); // 底边 + points.Add(InterpolateEdge(grid, x + 1, y, x + 1, y + 1)); // 右边 + break; + case 3: + case 12: + points.Add(InterpolateEdge(grid, x, y, x, y + 1)); // 左边 + points.Add(InterpolateEdge(grid, x + 1, y, x + 1, y + 1)); // 右边 + break; + case 4: + case 11: + points.Add(InterpolateEdge(grid, x + 1, y, x + 1, y + 1)); // 右边 + points.Add(InterpolateEdge(grid, x, y + 1, x + 1, y + 1)); // 顶边 + break; + case 5: + points.Add(InterpolateEdge(grid, x, y, x, y + 1)); // 左边 + points.Add(InterpolateEdge(grid, x, y, x + 1, y)); // 底边 + points.Add(InterpolateEdge(grid, x + 1, y, x + 1, y + 1)); // 右边 + points.Add(InterpolateEdge(grid, x, y + 1, x + 1, y + 1)); // 顶边 + break; + case 6: + case 9: + points.Add(InterpolateEdge(grid, x, y, x + 1, y)); // 底边 + points.Add(InterpolateEdge(grid, x, y + 1, x + 1, y + 1)); // 顶边 + break; + case 7: + case 8: + points.Add(InterpolateEdge(grid, x, y, x, y + 1)); // 左边 + points.Add(InterpolateEdge(grid, x, y + 1, x + 1, y + 1)); // 顶边 + break; + case 10: + points.Add(InterpolateEdge(grid, x, y, x, y + 1)); // 左边 + points.Add(InterpolateEdge(grid, x, y, x + 1, y)); // 底边 + points.Add(InterpolateEdge(grid, x + 1, y, x + 1, y + 1)); // 右边 + points.Add(InterpolateEdge(grid, x, y + 1, x + 1, y + 1)); // 顶边 + break; + } + + return points.ToArray(); + } + + Vector2 InterpolateEdge(DensityGrid grid, int x1, int y1, int x2, int y2) + { + // 安全获取值 + float v1 = GetSafeValue(grid, x1, y1); + float v2 = GetSafeValue(grid, x2, y2); + + if (Mathf.Abs(v1 - v2) < 0.001f) + return grid.GridToLocalPosition(x1, y1); + + float t = (isoLevel - v1) / (v2 - v1); + t = Mathf.Clamp01(t); + + Vector2 p1 = grid.GridToLocalPosition(x1, y1); + Vector2 p2 = grid.GridToLocalPosition(x2, y2); + + return Vector2.Lerp(p1, p2, t); + } + + bool MoveToNextCell(int config, ref int x, ref int y) + { + // 简化的移动逻辑 - 根据配置决定下一个单元格 + switch (config) + { + case 1: + case 3: + case 7: + case 5: + y++; break; // 向上移动 + case 2: + case 6: + case 10: + case 14: + x++; break; // 向右移动 + case 4: + case 12: + case 13: + case 15: + y--; break; // 向下移动 + case 8: + case 9: + case 11: + x--; break; // 向左移动 + default: + return false; // 无法移动 + } + + return true; + } + + List SmoothContour(List contour) + { + if (contour.Count < 4) return contour; + + var smoothed = new List(); + for (int i = 0; i < contour.Count; i++) + { + Vector2 prev = contour[(i - 1 + contour.Count) % contour.Count]; + Vector2 current = contour[i]; + Vector2 next = contour[(i + 1) % contour.Count]; + + Vector2 smoothedPoint = (prev + current * 2f + next) / 4f; + smoothed.Add(smoothedPoint); + } + return smoothed; + } + + bool IsBoundaryCell(DensityGrid grid, int x, int y) + { + // 安全检查 + if (x < 0 || x >= grid.Width - 1 || y < 0 || y >= grid.Height - 1) + return false; + + float value = grid.GetValue(x, y); + return value >= isoLevel && value < 1.0f; // 边界单元格 + } + + public void DrawGridGizmos(Transform wall) + { + // 调试可视化代码可以留空或简化 +#if UNITY_EDITOR + // 可选:添加网格可视化 +#endif + } +} \ No newline at end of file diff --git a/Assets/Scripts/Test/Light/New/MarchingSquaresProcessor.cs.meta b/Assets/Scripts/Test/Light/New/MarchingSquaresProcessor.cs.meta new file mode 100644 index 0000000..81bf0f7 --- /dev/null +++ b/Assets/Scripts/Test/Light/New/MarchingSquaresProcessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e2a4c434153f3614d8381195368e2fec +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Test/Light/New/ShadowCollider.cs b/Assets/Scripts/Test/Light/New/ShadowCollider.cs new file mode 100644 index 0000000..89b395f --- /dev/null +++ b/Assets/Scripts/Test/Light/New/ShadowCollider.cs @@ -0,0 +1,54 @@ +using UnityEngine; +using System.Collections.Generic; + +public class ShadowCollider : MonoBehaviour +{ + [Header("阴影碰撞器")] + public GameObject sourceObject; + public PolygonCollider2D polygonCollider; + + [Header("调试")] + public bool showGizmos = true; + public Color gizmoColor = new Color(1, 0, 0, 0.3f); + + public void Initialize(List> contours) + { + polygonCollider = GetComponent(); + if (polygonCollider == null) + polygonCollider = gameObject.AddComponent(); + + UpdateCollider(contours); + } + + public void UpdateCollider(List> contours) + { + if (polygonCollider == null) return; + + polygonCollider.pathCount = contours.Count; + for (int i = 0; i < contours.Count; i++) + { + polygonCollider.SetPath(i, contours[i].ToArray()); + } + } + +#if UNITY_EDITOR + void OnDrawGizmos() + { + if (!showGizmos || polygonCollider == null) return; + + Gizmos.color = gizmoColor; + Vector3 offset = transform.forward * 0.01f; + + for (int pathIndex = 0; pathIndex < polygonCollider.pathCount; pathIndex++) + { + var path = polygonCollider.GetPath(pathIndex); + for (int i = 0; i < path.Length; i++) + { + Vector3 point1 = transform.TransformPoint(path[i]); + Vector3 point2 = transform.TransformPoint(path[(i + 1) % path.Length]); + Gizmos.DrawLine(point1 + offset, point2 + offset); + } + } + } +#endif +} \ No newline at end of file diff --git a/Assets/Scripts/Test/Light/New/ShadowCollider.cs.meta b/Assets/Scripts/Test/Light/New/ShadowCollider.cs.meta new file mode 100644 index 0000000..f93fa45 --- /dev/null +++ b/Assets/Scripts/Test/Light/New/ShadowCollider.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3a96ca5e4a935984392a295d8855f0f3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Test/Light/New/ShadowColliderSystem.cs b/Assets/Scripts/Test/Light/New/ShadowColliderSystem.cs new file mode 100644 index 0000000..e0c86db --- /dev/null +++ b/Assets/Scripts/Test/Light/New/ShadowColliderSystem.cs @@ -0,0 +1,183 @@ +using UnityEngine; +using System.Collections.Generic; +using System.Linq; +using UnityEngine.Rendering.Universal; + +public class ShadowColliderSystem : MonoBehaviour +{ + [Header("系统设置")] + public Light shadowLight; + public Transform shadowWall; + public string shadowLayerName = "Shadow"; + public LayerMask obstacleLayerMask = -1; + + [Header("生成设置")] + public bool generateOnStart = true; + public bool updateInRealTime = false; + public float updateInterval = 0.1f; + + [Header("阴影碰撞器")] + public List shadowColliders = new List(); + + private ShadowProjector projector; + private ShadowMeshGenerator meshGenerator; + private MarchingSquaresProcessor marchingSquares; + private float updateTimer; + + void Start() + { + InitializeComponents(); + + if (generateOnStart) + { + GenerateAllShadowColliders(); + } + } + + void Update() + { + if (updateInRealTime) + { + updateTimer += Time.deltaTime; + if (updateTimer >= updateInterval) + { + UpdateAllShadowColliders(); + updateTimer = 0f; + } + } + } + + void InitializeComponents() + { + // 自动查找必要的组件 + if (shadowLight == null) shadowLight = ShadowUtils.FindMainLight(); + if (shadowWall == null) shadowWall = ShadowUtils.FindMainWall(); + + // 初始化子系统 + projector = new ShadowProjector(shadowLight, shadowWall, obstacleLayerMask); + meshGenerator = new ShadowMeshGenerator(); + marchingSquares = new MarchingSquaresProcessor(); + } + + [ContextMenu("生成所有阴影碰撞器")] + public void GenerateAllShadowColliders() + { + ClearAllShadowColliders(); + + var shadowObjects = ShadowUtils.FindObjectsInLayer(shadowLayerName); + foreach (GameObject obj in shadowObjects) + { + GenerateShadowCollider(obj); + } + + Debug.Log($"生成了 {shadowColliders.Count} 个阴影碰撞器"); + } + + [ContextMenu("更新所有阴影碰撞器")] + public void UpdateAllShadowColliders() + { + foreach (var shadowCollider in shadowColliders) + { + if (shadowCollider != null) + { + UpdateShadowCollider(shadowCollider); + } + } + } + + public void GenerateShadowCollider(GameObject shadowCaster) + { + if (!IsValidShadowCaster(shadowCaster)) return; + + try + { + // 1. 投影网格到墙面 + var projectedMesh = projector.ProjectMeshToWall(shadowCaster); + if (!projectedMesh.IsValid) + { + Debug.LogWarning($"无法为 {shadowCaster.name} 生成有效投影网格"); + return; + } + + // 2. 生成阴影密度网格 + var densityGrid = meshGenerator.GenerateDensityGrid(projectedMesh, shadowWall); + + // 3. 使用Marching Squares提取轮廓 + var contours = marchingSquares.ExtractContours(densityGrid); + if (contours == null || contours.Count == 0) + { + Debug.LogWarning($"无法为 {shadowCaster.name} 提取轮廓"); + return; + } + + // 4. 创建阴影碰撞器对象 + var shadowCollider = CreateShadowColliderObject(shadowCaster.name, contours); + shadowCollider.sourceObject = shadowCaster; + shadowColliders.Add(shadowCollider); + + Debug.Log($"成功为 {shadowCaster.name} 生成阴影碰撞器,包含 {contours.Count} 个轮廓"); + } + catch (System.Exception e) + { + Debug.LogError($"为 {shadowCaster.name} 生成阴影碰撞器时出错: {e.Message}"); + } + } + public void UpdateShadowCollider(ShadowCollider shadowCollider) + { + if (shadowCollider.sourceObject == null) return; + + var projectedMesh = projector.ProjectMeshToWall(shadowCollider.sourceObject); + var densityGrid = meshGenerator.GenerateDensityGrid(projectedMesh, shadowWall); + var contours = marchingSquares.ExtractContours(densityGrid); + + shadowCollider.UpdateCollider(contours); + } + + [ContextMenu("清空所有阴影碰撞器")] + public void ClearAllShadowColliders() + { + foreach (var collider in shadowColliders) + { + if (collider != null && collider.gameObject != null) + { + DestroyImmediate(collider.gameObject); + } + } + shadowColliders.Clear(); + } + + bool IsValidShadowCaster(GameObject obj) + { + return obj != null && + obj.activeInHierarchy && + obj.GetComponent() != null; + } + + ShadowCollider CreateShadowColliderObject(string name, List> contours) + { + GameObject colliderObj = new GameObject($"{name}_ShadowCollider"); + colliderObj.transform.SetParent(shadowWall); + colliderObj.transform.localPosition = Vector3.zero; + colliderObj.transform.localRotation = Quaternion.identity; + + var shadowCollider = colliderObj.AddComponent(); + shadowCollider.Initialize(contours); + + return shadowCollider; + } + + void OnDestroy() + { + ClearAllShadowColliders(); + } + +#if UNITY_EDITOR + void OnDrawGizmosSelected() + { + if (marchingSquares != null && shadowWall != null) + { + marchingSquares.DrawGridGizmos(shadowWall); + } + } +#endif +} \ No newline at end of file diff --git a/Assets/Scripts/Test/Light/New/ShadowColliderSystem.cs.meta b/Assets/Scripts/Test/Light/New/ShadowColliderSystem.cs.meta new file mode 100644 index 0000000..94ef599 --- /dev/null +++ b/Assets/Scripts/Test/Light/New/ShadowColliderSystem.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 836b4625937ba9d45be59618cd2a6a15 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Test/Light/New/ShadowMeshGenerator.cs b/Assets/Scripts/Test/Light/New/ShadowMeshGenerator.cs new file mode 100644 index 0000000..4cba90d --- /dev/null +++ b/Assets/Scripts/Test/Light/New/ShadowMeshGenerator.cs @@ -0,0 +1,123 @@ +using UnityEngine; +using System.Collections.Generic; + +[System.Serializable] +public class ShadowMeshGenerator +{ + [Header("网格设置")] + public int gridResolution = 64; + public float gridSize = 1.0f; + public float influenceRadius = 0.5f; + + public DensityGrid GenerateDensityGrid(ProjectedMesh mesh, Transform wall) + { + var bounds = CalculateMeshBounds(mesh); + var grid = new DensityGrid(bounds, gridResolution, gridSize); + + // 为每个网格点计算密度 + for (int x = 0; x < grid.Width; x++) + { + for (int y = 0; y < grid.Height; y++) + { + Vector2 gridPos = grid.GridToLocalPosition(x, y); + float density = CalculateDensityAtPoint(gridPos, mesh); + grid.SetValue(x, y, density); + } + } + + return grid; + } + + float CalculateDensityAtPoint(Vector2 point, ProjectedMesh mesh) + { + float totalDensity = 0f; + int samples = 0; + + // 采样网格点周围的顶点影响 + foreach (var vertex in mesh.vertices) + { + Vector2 vertex2D = new Vector2(vertex.x, vertex.y); + float distance = Vector2.Distance(point, vertex2D); + + if (distance < influenceRadius) + { + float influence = 1f - (distance / influenceRadius); + totalDensity += influence; + samples++; + } + } + + return samples > 0 ? totalDensity / samples : 0f; + } + + Bounds CalculateMeshBounds(ProjectedMesh mesh) + { + if (mesh.vertices.Count == 0) + return new Bounds(Vector3.zero, Vector3.one); + + Vector3 min = mesh.vertices[0]; + Vector3 max = mesh.vertices[0]; + + foreach (var vertex in mesh.vertices) + { + min = Vector3.Min(min, vertex); + max = Vector3.Max(max, vertex); + } + + return new Bounds((min + max) * 0.5f, max - min); + } +} + +[System.Serializable] +public class DensityGrid +{ + public int Width { get; private set; } + public int Height { get; private set; } + public float CellSize { get; private set; } + public Bounds WorldBounds { get; private set; } + + private float[,] values; + private Vector3 gridOrigin; + + public DensityGrid(Bounds bounds, int resolution, float cellSize) + { + WorldBounds = bounds; + CellSize = cellSize; + Width = resolution; + Height = resolution; + + gridOrigin = bounds.min; + values = new float[Width, Height]; + } + + public void SetValue(int x, int y, float value) + { + if (x >= 0 && x < Width && y >= 0 && y < Height) + { + values[x, y] = Mathf.Clamp01(value); + } + } + + public float GetValue(int x, int y) + { + if (x >= 0 && x < Width && y >= 0 && y < Height) + { + return values[x, y]; + } + return 0f; + } + + public Vector2 GridToLocalPosition(int x, int y) + { + return new Vector2( + x * CellSize + gridOrigin.x, + y * CellSize + gridOrigin.y + ); + } + + public Vector3 GridToWorldPosition(int x, int y, Transform wall) + { + Vector2 localPos = GridToLocalPosition(x, y); + return wall.TransformPoint(new Vector3(localPos.x, localPos.y, 0)); + } +} \ No newline at end of file diff --git a/Assets/Scripts/Test/Light/New/ShadowMeshGenerator.cs.meta b/Assets/Scripts/Test/Light/New/ShadowMeshGenerator.cs.meta new file mode 100644 index 0000000..5c23fee --- /dev/null +++ b/Assets/Scripts/Test/Light/New/ShadowMeshGenerator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 85170fe0e92d3604fbf662a3620570e0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Test/Light/New/ShadowProjector.cs b/Assets/Scripts/Test/Light/New/ShadowProjector.cs new file mode 100644 index 0000000..bee43a6 --- /dev/null +++ b/Assets/Scripts/Test/Light/New/ShadowProjector.cs @@ -0,0 +1,136 @@ +using UnityEngine; +using System.Collections.Generic; + +[System.Serializable] +public class ShadowProjector +{ + public Light lightSource; + public Transform projectionWall; + public LayerMask obstacleMask; + + private Vector3 wallNormal; + private Vector3 wallPosition; + + public ShadowProjector(Light light, Transform wall, LayerMask obstacleMask) + { + this.lightSource = light; + this.projectionWall = wall; + this.obstacleMask = obstacleMask; + CalculateWallPlane(); + } + + public ProjectedMesh ProjectMeshToWall(GameObject shadowCaster) + { + var meshFilter = shadowCaster.GetComponent(); + if (meshFilter == null) return new ProjectedMesh(); + + var mesh = meshFilter.mesh; + var vertices = mesh.vertices; + var triangles = mesh.triangles; + + List projectedVertices = new List(); + List projectedTriangles = new List(); + + // 投影每个顶点 + for (int i = 0; i < vertices.Length; i++) + { + Vector3 worldVertex = shadowCaster.transform.TransformPoint(vertices[i]); + Vector3 projectedVertex = ProjectPoint(worldVertex); + + if (!IsObstructed(worldVertex, projectedVertex)) + { + projectedVertices.Add(projectedVertex); + } + } + + // 重新构建三角形(简化版本) + // 实际应该使用更复杂的三角化算法 + for (int i = 0; i < triangles.Length; i += 3) + { + if (IsValidTriangle(projectedVertices, triangles, i)) + { + projectedTriangles.Add(triangles[i]); + projectedTriangles.Add(triangles[i + 1]); + projectedTriangles.Add(triangles[i + 2]); + } + } + + return new ProjectedMesh + { + vertices = projectedVertices, + triangles = projectedTriangles.ToArray(), + sourceObject = shadowCaster + }; + } + + Vector3 ProjectPoint(Vector3 worldPoint) + { + Vector3 lightDirection = GetLightDirection(worldPoint); + return IntersectWithWall(worldPoint, lightDirection); + } + + Vector3 GetLightDirection(Vector3 targetPoint) + { + if (lightSource.type == LightType.Directional) + { + return -lightSource.transform.forward; + } + else + { + return (targetPoint - lightSource.transform.position).normalized; + } + } + + Vector3 IntersectWithWall(Vector3 point, Vector3 direction) + { + float denominator = Vector3.Dot(direction, wallNormal); + + if (Mathf.Abs(denominator) < 0.0001f) + return point; + + float t = Vector3.Dot(wallPosition - point, wallNormal) / denominator; + return point + direction * t; + } + + bool IsObstructed(Vector3 start, Vector3 end) + { + Vector3 direction = (end - start).normalized; + float distance = Vector3.Distance(start, end); + + RaycastHit hit; + if (Physics.Raycast(start, direction, out hit, distance, obstacleMask)) + { + return hit.collider.gameObject != projectionWall.gameObject; + } + + return false; + } + + bool IsValidTriangle(List vertices, int[] triangles, int startIndex) + { + int i1 = triangles[startIndex]; + int i2 = triangles[startIndex + 1]; + int i3 = triangles[startIndex + 2]; + + return i1 < vertices.Count && i2 < vertices.Count && i3 < vertices.Count; + } + + void CalculateWallPlane() + { + if (projectionWall != null) + { + wallPosition = projectionWall.position; + wallNormal = -projectionWall.forward; + } + } +} + +[System.Serializable] +public struct ProjectedMesh +{ + public List vertices; + public int[] triangles; + public GameObject sourceObject; + + public bool IsValid => vertices != null && vertices.Count >= 3; +} \ No newline at end of file diff --git a/Assets/Scripts/Test/Light/New/ShadowProjector.cs.meta b/Assets/Scripts/Test/Light/New/ShadowProjector.cs.meta new file mode 100644 index 0000000..fca7fb1 --- /dev/null +++ b/Assets/Scripts/Test/Light/New/ShadowProjector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 462c6c18ec968ae4badc890a169194e1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Test/Light/New/ShadowUtils.cs b/Assets/Scripts/Test/Light/New/ShadowUtils.cs new file mode 100644 index 0000000..d34b454 --- /dev/null +++ b/Assets/Scripts/Test/Light/New/ShadowUtils.cs @@ -0,0 +1,42 @@ +using UnityEngine; +using System.Collections.Generic; +using System.Linq; + +public static class ShadowUtils +{ + public static Light FindMainLight() + { + Light[] lights = Object.FindObjectsOfType(); + return lights.FirstOrDefault(l => l.type == LightType.Directional && l.enabled) ?? + lights.FirstOrDefault(l => l.type == LightType.Spot && l.enabled); + } + + public static Transform FindMainWall() + { + var walls = Object.FindObjectsOfType() + .Where(c => c is BoxCollider) + .OrderByDescending(c => + { + var box = c as BoxCollider; + var size = Vector3.Scale(box.size, c.transform.lossyScale); + return size.x * size.y; + }); + + return walls.FirstOrDefault()?.transform; + } + + public static List FindObjectsInLayer(string layerName) + { + int layer = LayerMask.NameToLayer(layerName); + return Object.FindObjectsOfType() + .Where(obj => obj.activeInHierarchy && obj.layer == layer) + .ToList(); + } + + public static List FindObjectsInLayer(int layer) + { + return Object.FindObjectsOfType() + .Where(obj => obj.activeInHierarchy && obj.layer == layer) + .ToList(); + } +} \ No newline at end of file diff --git a/Assets/Scripts/Test/Light/New/ShadowUtils.cs.meta b/Assets/Scripts/Test/Light/New/ShadowUtils.cs.meta new file mode 100644 index 0000000..fff8a37 --- /dev/null +++ b/Assets/Scripts/Test/Light/New/ShadowUtils.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d5f9eb8ac9da6a8488b456411e1e7370 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Test/Light/RaycastShadowCollider.cs b/Assets/Scripts/Test/Light/RaycastShadowCollider.cs index ceb1e77..5748e44 100644 --- a/Assets/Scripts/Test/Light/RaycastShadowCollider.cs +++ b/Assets/Scripts/Test/Light/RaycastShadowCollider.cs @@ -1,82 +1,274 @@ -using UnityEngine; +using UnityEngine; using System.Collections.Generic; public class RaycastShadowCollider : MonoBehaviour { - public Light spotLight; // ۹ - public GameObject shadowCaster; // ͶӰ - public int rayCount = 36; // + public Light spotLight; + public List shadowCasters = new List(); + public LayerMask shadowCasterLayer; + public LayerMask shadowReceiverLayer; public float maxShadowDistance = 10f; - - private PolygonCollider2D shadowCollider; + public PolygonCollider2D shadowCollider; void Start() { - shadowCollider = GetComponent(); - if (shadowCollider == null) - shadowCollider = gameObject.AddComponent(); + UpdateShadowColliders(); } void Update() { - UpdateShadowCollider(); + //UpdateShadowCollider(); } - - void UpdateShadowCollider() + void UpdateShadowColliders() + { + foreach (var shadowCaster in shadowCasters) + { + UpdateShadowCollider(shadowCaster); + } + } + void UpdateShadowCollider(GameObject shadowCaster) { List shadowPoints = new List(); - // ߽ƹⷽͶ - Bounds bounds = shadowCaster.GetComponent().bounds; - Vector3[] boundPoints = GetBoundPoints(bounds); + // 获取阴影投射器的边界点(世界坐标) + Vector3[] worldBoundPoints = GetBoundPoints(shadowCaster); - foreach (Vector3 point in boundPoints) + foreach (Vector3 worldPoint in worldBoundPoints) { - Vector3 toLight = (spotLight.transform.position - point).normalized; - Ray ray = new Ray(point, toLight); + // 方向:从灯光指向边界点 + Vector3 toPoint = (worldPoint - spotLight.transform.position).normalized; + + // 创建从灯光位置发出的射线 + Ray ray = new Ray(spotLight.transform.position, toPoint); RaycastHit hit; - if (Physics.Raycast(ray, out hit, maxShadowDistance)) + // 调试:显示射线方向 + Debug.DrawRay(spotLight.transform.position, toPoint * maxShadowDistance, Color.yellow); + + if (Physics.Raycast(ray, out hit, maxShadowDistance, shadowReceiverLayer)) { - if (hit.collider.gameObject == gameObject) // ǽ + // 检查是否击中了阴影投射器 + if (hit.collider.gameObject == gameObject) { - // תǽľֲϵ - Vector3 localHit = transform.InverseTransformPoint(hit.point); + // 将世界坐标的碰撞点转换到阴影碰撞器的本地坐标 + Vector3 localHit = shadowCollider.transform.InverseTransformPoint(hit.point); shadowPoints.Add(new Vector2(localHit.x, localHit.y)); + + // 调试:在碰撞点创建小球 + // GameObject sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere); + //sphere.transform.position = hit.point; + // sphere.transform.localScale = Vector3.one * 0.1f; + //Destroy(sphere, 0.1f); } } + //else + //{ + // // 如果没有击中,使用最大距离的点 + // Vector3 maxPoint = spotLight.transform.position + toPoint * maxShadowDistance; + // Vector3 localMaxPoint = shadowCollider.transform.InverseTransformPoint(maxPoint); + // shadowPoints.Add(new Vector2(localMaxPoint.x, localMaxPoint.y)); + + // // 调试:在最大距离点创建小球 + // GameObject sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere); + // sphere.transform.position = maxPoint; + // sphere.transform.localScale = Vector3.one * 0.1f; + // sphere.GetComponent().material.color = Color.blue; + // Destroy(sphere, 0.1f); + //} } - // Եγ͹ + // 设置碰撞器路径 if (shadowPoints.Count > 2) { - List convexHull = ComputeConvexHull(shadowPoints); - shadowCollider.SetPath(0, convexHull); + // 对点进行排序以确保正确的多边形 + shadowPoints = SortShadowPoints(shadowPoints); + shadowCollider.SetPath(0, shadowPoints); + } + else + { + shadowCollider.pathCount = 0; } } - Vector3[] GetBoundPoints(Bounds bounds) + Vector3[] GetBoundPoints(GameObject target) { + + Bounds bounds = target.GetComponent().bounds; return new Vector3[] { - bounds.min, - bounds.max, - new Vector3(bounds.min.x, bounds.min.y, bounds.max.z), - new Vector3(bounds.min.x, bounds.max.y, bounds.min.z), - new Vector3(bounds.max.x, bounds.min.y, bounds.min.z), - new Vector3(bounds.min.x, bounds.max.y, bounds.max.z), - new Vector3(bounds.max.x, bounds.min.y, bounds.max.z), - new Vector3(bounds.max.x, bounds.max.y, bounds.min.z) + bounds.min, + bounds.max, + new Vector3(bounds.min.x, bounds.min.y, bounds.max.z), + new Vector3(bounds.min.x, bounds.max.y, bounds.min.z), + new Vector3(bounds.max.x, bounds.min.y, bounds.min.z), + new Vector3(bounds.min.x, bounds.max.y, bounds.max.z), + new Vector3(bounds.max.x, bounds.min.y, bounds.max.z), + new Vector3(bounds.max.x, bounds.max.y, bounds.min.z) }; } - // ͹㷨Graham Scan + //List SortPointsClockwise(List points) + //{ + // if (points.Count < 3) return points; + + // // 计算中心点 + // Vector2 center = Vector2.zero; + // foreach (Vector2 point in points) + // { + // center += point; + // } + // center /= points.Count; + + // // 按角度排序 + // points.Sort((a, b) => + // { + // Vector2 dirA = a - center; + // Vector2 dirB = b - center; + // float angleA = Mathf.Atan2(dirA.y, dirA.x); + // float angleB = Mathf.Atan2(dirB.y, dirB.x); + // return angleA.CompareTo(angleB); + // }); + // points.Add(points[points.Count-1]); + // return points; + //} + List SortPointsClockwise(List points) + { + if (points.Count < 3) return points; + + // 方法1:使用凸包算法(推荐) + List convexHull = ComputeConvexHull(points); + return convexHull; + + // 或者方法2:改进的角度排序(如果确定是凸多边形) + // return ImprovedAngleSort(points); + } + + // 计算凸包 - Graham Scan 算法 List ComputeConvexHull(List points) { if (points.Count < 3) return points; - // ʵ͹㷨... - // ʹUnityCollider2D.CreatePrimitiveߵ - return points; // 򻯷 + // 找到最左下角的点作为起点 + Vector2 startPoint = points[0]; + foreach (Vector2 point in points) + { + if (point.y < startPoint.y || (point.y == startPoint.y && point.x < startPoint.x)) + { + startPoint = point; + } + } + + // 按极角排序 + List sortedPoints = new List(points); + sortedPoints.Sort((a, b) => + { + if (a == startPoint) return -1; + if (b == startPoint) return 1; + + Vector2 dirA = a - startPoint; + Vector2 dirB = b - startPoint; + + float cross = Cross(dirA, dirB); + if (Mathf.Abs(cross) < 0.001f) // 共线情况 + { + return dirA.sqrMagnitude.CompareTo(dirB.sqrMagnitude); + } + return cross > 0 ? -1 : 1; + }); + + // 构建凸包 + List hull = new List(); + hull.Add(startPoint); + hull.Add(sortedPoints[1]); + + for (int i = 2; i < sortedPoints.Count; i++) + { + while (hull.Count >= 2) + { + Vector2 a = hull[hull.Count - 2]; + Vector2 b = hull[hull.Count - 1]; + Vector2 c = sortedPoints[i]; + + if (Cross(b - a, c - a) <= 0) + { + hull.RemoveAt(hull.Count - 1); + } + else + { + break; + } + } + hull.Add(sortedPoints[i]); + } + + return hull; + } + + // 叉积计算 + float Cross(Vector2 a, Vector2 b) + { + return a.x * b.y - a.y * b.x; + } + + // 改进的角度排序(仅适用于凸多边形) + List ImprovedAngleSort(List points) + { + // 计算中心点 + Vector2 center = Vector2.zero; + foreach (Vector2 point in points) + { + center += point; + } + center /= points.Count; + + // 按角度排序,处理相同角度的情况 + points.Sort((a, b) => + { + Vector2 dirA = a - center; + Vector2 dirB = b - center; + + float angleA = Mathf.Atan2(dirA.y, dirA.x); + float angleB = Mathf.Atan2(dirB.y, dirB.x); + + // 处理角度接近的情况 + if (Mathf.Abs(angleA - angleB) < 0.001f) + { + return dirA.sqrMagnitude.CompareTo(dirB.sqrMagnitude); + } + + return angleA.CompareTo(angleB); + }); + + return points; + } + + // 专门为阴影投影点设计的排序方法 + List SortShadowPoints(List points) + { + if (points.Count < 3) return points; + + // 对于阴影点,通常形成凸多边形,使用凸包算法 + List hull = ComputeConvexHull(points); + + // 确保点是顺时针顺序(Unity碰撞器需要) + if (!IsClockwise(hull)) + { + hull.Reverse(); + } + + return hull; + } + + // 检查多边形是否是顺时针顺序 + bool IsClockwise(List points) + { + float area = 0; + for (int i = 0; i < points.Count; i++) + { + Vector2 current = points[i]; + Vector2 next = points[(i + 1) % points.Count]; + area += (next.x - current.x) * (next.y + current.y); + } + return area > 0; } } \ No newline at end of file diff --git a/Assets/Scripts/Test/Light/ShadowColliderGenerator.cs b/Assets/Scripts/Test/Light/ShadowColliderGenerator.cs index d6c97bd..e17c21b 100644 --- a/Assets/Scripts/Test/Light/ShadowColliderGenerator.cs +++ b/Assets/Scripts/Test/Light/ShadowColliderGenerator.cs @@ -1,124 +1,288 @@ using UnityEngine; using System.Collections.Generic; +using System.Linq; public class ShadowColliderGenerator : MonoBehaviour { - public Camera shadowCamera; // רȾӰ - public RenderTexture shadowRT; // Ⱦ - public LayerMask shadowCasterLayer; // ͶӰ - public float colliderPrecision = 0.1f; // ײ徫 + [Header("References")] + public Camera shadowCamera; + public RenderTexture shadowRT; + public PolygonCollider2D polygonCollider; + + [Header("Settings")] + [Range(0f, 1f)] + public float shadowThreshold = 0.3f; + public int gridSize = 2; // 网格大小,越小越精确 + public float simplifyTolerance = 1f; private Texture2D processedTexture; - private PolygonCollider2D polygonCollider; void Start() { - // ʼȾ - shadowRT = new RenderTexture(512, 512, 24); - shadowCamera.targetTexture = shadowRT; - - // õ - processedTexture = new Texture2D(512, 512, TextureFormat.RGB24, false); - - polygonCollider = GetComponent(); if (polygonCollider == null) - polygonCollider = gameObject.AddComponent(); + polygonCollider = GetComponent(); + + processedTexture = new Texture2D(shadowRT.width, shadowRT.height, TextureFormat.R8, false); + GenerateCollider(); } void Update() { - GenerateShadowCollider(); + if (Input.GetKeyDown(KeyCode.Space)) + { + GenerateCollider(); + } } - void GenerateShadowCollider() + [ContextMenu("Generate Collider")] + public void GenerateCollider() { - // 1. ȾӰ + if (shadowCamera == null || shadowRT == null) return; + + // 渲染阴影 shadowCamera.Render(); - // 2. GPUȡCPU + // 读取纹理 RenderTexture.active = shadowRT; processedTexture.ReadPixels(new Rect(0, 0, shadowRT.width, shadowRT.height), 0, 0); processedTexture.Apply(); RenderTexture.active = null; - // 3. ӰԵ - List edgePoints = DetectEdges(processedTexture); + // 生成轮廓 + List contour = GenerateContourFromTexture(); - // 4. תΪ겢ײ - if (edgePoints.Count > 2) + if (contour.Count > 2) { - List worldPoints = ConvertToWorldCoordinates(edgePoints); + List worldPoints = ConvertToWorldCoordinates(contour); polygonCollider.SetPath(0, worldPoints); + Debug.Log($"Collider generated with {worldPoints.Count} points"); + } + else + { + polygonCollider.pathCount = 0; + Debug.Log("No contour generated"); } } - List DetectEdges(Texture2D texture) + List GenerateContourFromTexture() { - List edges = new List(); - Color[] pixels = texture.GetPixels(); + int width = processedTexture.width; + int height = processedTexture.height; - int width = texture.width; - int height = texture.height; + // 创建二值化网格 + bool[,] grid = CreateBinaryGrid(width, height); - // 򵥵ıԵ㷨 - for (int y = 1; y < height - 1; y += (int)(1f / colliderPrecision)) + // 找到所有边界点 + List boundaryPoints = FindBoundaryPoints(grid); + + // 连接边界点形成轮廓 + List contour = ConnectBoundaryPoints(boundaryPoints); + + return contour; + } + + bool[,] CreateBinaryGrid(int width, int height) + { + bool[,] grid = new bool[width / gridSize, height / gridSize]; + + for (int x = 0; x < grid.GetLength(0); x++) { - for (int x = 1; x < width - 1; x += (int)(1f / colliderPrecision)) + for (int y = 0; y < grid.GetLength(1); y++) { - int index = y * width + x; + int texX = x * gridSize; + int texY = y * gridSize; + Color pixel = processedTexture.GetPixel(texX, texY); + grid[x, y] = pixel.grayscale < shadowThreshold; + } + } - // 鵱ǰΧصIJ - if (IsEdgePixel(pixels, index, width)) + return grid; + } + + List FindBoundaryPoints(bool[,] grid) + { + List boundaryPoints = new List(); + int width = grid.GetLength(0); + int height = grid.GetLength(1); + + for (int x = 0; x < width; x++) + { + for (int y = 0; y < height; y++) + { + if (grid[x, y]) { - edges.Add(new Vector2(x, y)); + // 检查是否是边界(有非阴影像素邻居) + bool isBoundary = false; + + // 检查4邻域 + if (x == 0 || !grid[x - 1, y]) isBoundary = true; + else if (x == width - 1 || !grid[x + 1, y]) isBoundary = true; + else if (y == 0 || !grid[x, y - 1]) isBoundary = true; + else if (y == height - 1 || !grid[x, y + 1]) isBoundary = true; + + if (isBoundary) + { + boundaryPoints.Add(new Vector2(x * gridSize, y * gridSize)); + } } } } - return edges; + Debug.Log($"Found {boundaryPoints.Count} boundary points"); + return boundaryPoints; } - bool IsEdgePixel(Color[] pixels, int index, int width) + List ConnectBoundaryPoints(List points) { - Color current = pixels[index]; - float currentBrightness = current.r + current.g + current.b; + if (points.Count < 3) return points; - // - float[] neighborBrightness = new float[4] - { - pixels[index - 1].r + pixels[index - 1].g + pixels[index - 1].b, // - pixels[index + 1].r + pixels[index + 1].g + pixels[index + 1].b, // - pixels[index - width].r + pixels[index - width].g + pixels[index - width].b, // - pixels[index + width].r + pixels[index + width].g + pixels[index + width].b // - }; + List contour = new List(); + List remaining = new List(points); - // ǰھӲϴΪDZԵ - float threshold = 0.3f; - for (int i = 0; i < 4; i++) + // 找到最左边的点作为起点 + Vector2 start = remaining.OrderBy(p => p.x).First(); + contour.Add(start); + remaining.Remove(start); + + Vector2 current = start; + Vector2 previousDirection = Vector2.right; + + int maxIterations = points.Count * 2; + int iterations = 0; + + while (remaining.Count > 0 && iterations < maxIterations) { - if (Mathf.Abs(currentBrightness - neighborBrightness[i]) > threshold) - return true; + iterations++; + + // 找到与当前方向最一致的下一个点 + float bestScore = float.MinValue; + Vector2 bestPoint = Vector2.zero; + int bestIndex = -1; + + for (int i = 0; i < remaining.Count; i++) + { + Vector2 toPoint = (remaining[i] - current).normalized; + float distance = Vector2.Distance(current, remaining[i]); + + // 评分:方向一致性 + 距离权重 + float directionScore = Vector2.Dot(previousDirection, toPoint); + float distanceScore = 1f / (distance + 0.1f); + float totalScore = directionScore + distanceScore * 0.1f; + + if (totalScore > bestScore && distance < 50f) // 距离限制 + { + bestScore = totalScore; + bestPoint = remaining[i]; + bestIndex = i; + } + } + + if (bestIndex >= 0) + { + previousDirection = (bestPoint - current).normalized; + contour.Add(bestPoint); + remaining.RemoveAt(bestIndex); + current = bestPoint; + } + else + { + break; + } } - return false; + // 确保轮廓闭合 + if (contour.Count > 2 && Vector2.Distance(contour[0], contour[contour.Count - 1]) > 30f) + { + contour.Add(contour[0]); + } + + // 简化轮廓 + contour = SimplifyContour(contour); + + Debug.Log($"Connected {contour.Count} points into contour"); + return contour; + } + + List SimplifyContour(List contour) + { + if (contour.Count <= 3) return contour; + + List simplified = new List(); + simplified.Add(contour[0]); + + for (int i = 1; i < contour.Count - 1; i++) + { + // 如果角度变化太大,保留这个点 + if (i > 1) + { + Vector2 prevDir = (contour[i] - contour[i - 1]).normalized; + Vector2 nextDir = (contour[i + 1] - contour[i]).normalized; + float angle = Vector2.Angle(prevDir, nextDir); + + if (angle > 30f) // 角度阈值 + { + simplified.Add(contour[i]); + } + } + } + + simplified.Add(contour[contour.Count - 1]); + + return simplified; } List ConvertToWorldCoordinates(List texturePoints) { List worldPoints = new List(); - Bounds wallBounds = GetComponent().bounds; - foreach (Vector2 point in texturePoints) + foreach (Vector2 texCoord in texturePoints) { - // תΪǽֲ - Vector2 localPoint = new Vector2( - point.x / shadowRT.width * wallBounds.size.x - wallBounds.size.x * 0.5f, - point.y / shadowRT.height * wallBounds.size.y - wallBounds.size.y * 0.5f + Vector3 viewportPos = new Vector3( + texCoord.x / processedTexture.width, + texCoord.y / processedTexture.height, + shadowCamera.nearClipPlane ); - worldPoints.Add(localPoint); + Vector3 worldPos = shadowCamera.ViewportToWorldPoint(viewportPos); + worldPoints.Add(new Vector2(worldPos.x, worldPos.y)); } return worldPoints; } + + // 调试:显示边界点 + void OnDrawGizmosSelected() + { + if (processedTexture == null) return; + + Gizmos.color = Color.red; + + // 显示边界点 + bool[,] grid = CreateBinaryGrid(processedTexture.width, processedTexture.height); + List boundaryPoints = FindBoundaryPoints(grid); + + foreach (Vector2 point in boundaryPoints) + { + Vector3 viewportPos = new Vector3( + point.x / processedTexture.width, + point.y / processedTexture.height, + shadowCamera.nearClipPlane + ); + Vector3 worldPos = shadowCamera.ViewportToWorldPoint(viewportPos); + Gizmos.DrawSphere(worldPos, 0.02f); + } + + // 显示碰撞器轮廓 + if (polygonCollider != null && polygonCollider.pathCount > 0) + { + Gizmos.color = Color.green; + Vector2[] path = polygonCollider.GetPath(0); + for (int i = 0; i < path.Length; i++) + { + Vector3 start = path[i]; + Vector3 end = path[(i + 1) % path.Length]; + Gizmos.DrawLine(start, end); + } + } + } } \ No newline at end of file diff --git a/Assets/Scripts/Test/Light/ShadowRT.renderTexture b/Assets/Scripts/Test/Light/ShadowRT.renderTexture index 21c3928..8ef0158 100644 --- a/Assets/Scripts/Test/Light/ShadowRT.renderTexture +++ b/Assets/Scripts/Test/Light/ShadowRT.renderTexture @@ -37,4 +37,4 @@ RenderTexture: m_WrapW: 1 m_Dimension: 2 m_VolumeDepth: 1 - m_ShadowSamplingMode: 2 + m_ShadowSamplingMode: 0 diff --git a/Assets/Scripts/Test/Light/SimpleShadowCollider.cs b/Assets/Scripts/Test/Light/SimpleShadowCollider.cs new file mode 100644 index 0000000..9d232d8 --- /dev/null +++ b/Assets/Scripts/Test/Light/SimpleShadowCollider.cs @@ -0,0 +1,256 @@ +using UnityEngine; +using System.Collections.Generic; + +public class SimpleShadowCollider : MonoBehaviour +{ + [Header("References")] + public Camera shadowCamera; + public RenderTexture shadowRT; + public PolygonCollider2D polygonCollider; + + [Header("Settings")] + [Range(0f, 1f)] + public float shadowThreshold = 0.3f; + public int downSample = 4; // 降低采样率提高性能 + public float minShadowSize = 0.1f; // 最小阴影尺寸 + + private Texture2D processedTexture; + private bool[,] shadowGrid; + + void Start() + { + if (polygonCollider == null) + polygonCollider = GetComponent(); + + processedTexture = new Texture2D(shadowRT.width, shadowRT.height, TextureFormat.RGBA32, false); + GenerateCollider(); + } + + void Update() + { + if (Input.GetKeyDown(KeyCode.Space)) + { + GenerateCollider(); + } + } + + [ContextMenu("Generate Collider")] + public void GenerateCollider() + { + if (shadowCamera == null || shadowRT == null) return; + + // 渲染阴影 + shadowCamera.Render(); + + // 读取纹理 + RenderTexture.active = shadowRT; + processedTexture.ReadPixels(new Rect(0, 0, shadowRT.width, shadowRT.height), 0, 0); + processedTexture.Apply(); + RenderTexture.active = null; + + // 生成碰撞体 + GenerateColliderFromTexture(); + } + + void GenerateColliderFromTexture() + { + int width = processedTexture.width / downSample; + int height = processedTexture.height / downSample; + + // 创建阴影网格 + shadowGrid = new bool[width, height]; + + // 采样纹理 + for (int x = 0; x < width; x++) + { + for (int y = 0; y < height; y++) + { + int texX = x * downSample; + int texY = y * downSample; + Color pixel = processedTexture.GetPixel(texX, texY); + shadowGrid[x, y] = pixel.grayscale < shadowThreshold; + } + } + + // 找到所有阴影区域 + List> shadowRegions = FindShadowRegions(); + + // 设置碰撞器路径 + if (shadowRegions.Count > 0) + { + polygonCollider.pathCount = shadowRegions.Count; + for (int i = 0; i < shadowRegions.Count; i++) + { + List worldPoints = ConvertToWorldCoordinates(shadowRegions[i]); + polygonCollider.SetPath(i, worldPoints); + } + Debug.Log($"Generated {shadowRegions.Count} shadow colliders"); + } + else + { + polygonCollider.pathCount = 0; + Debug.Log("No shadow regions found"); + } + } + + List> FindShadowRegions() + { + List> regions = new List>(); + bool[,] visited = new bool[shadowGrid.GetLength(0), shadowGrid.GetLength(1)]; + + for (int x = 0; x < shadowGrid.GetLength(0); x++) + { + for (int y = 0; y < shadowGrid.GetLength(1); y++) + { + if (shadowGrid[x, y] && !visited[x, y]) + { + // 找到连续的阴影区域 + List regionPixels = FloodFill(x, y, visited); + + if (regionPixels.Count >= minShadowSize * (shadowGrid.GetLength(0) * shadowGrid.GetLength(1))) + { + // 转换为边界框 + List bounds = GetBoundingBox(regionPixels); + regions.Add(bounds); + } + } + } + } + + return regions; + } + + List FloodFill(int startX, int startY, bool[,] visited) + { + List region = new List(); + Queue queue = new Queue(); + + queue.Enqueue(new Vector2Int(startX, startY)); + visited[startX, startY] = true; + + while (queue.Count > 0) + { + Vector2Int current = queue.Dequeue(); + region.Add(current); + + // 检查4个方向的邻居 + CheckNeighbor(current.x + 1, current.y, visited, queue); + CheckNeighbor(current.x - 1, current.y, visited, queue); + CheckNeighbor(current.x, current.y + 1, visited, queue); + CheckNeighbor(current.x, current.y - 1, visited, queue); + } + + return region; + } + + void CheckNeighbor(int x, int y, bool[,] visited, Queue queue) + { + if (x >= 0 && x < shadowGrid.GetLength(0) && y >= 0 && y < shadowGrid.GetLength(1)) + { + if (shadowGrid[x, y] && !visited[x, y]) + { + visited[x, y] = true; + queue.Enqueue(new Vector2Int(x, y)); + } + } + } + + List GetBoundingBox(List pixels) + { + if (pixels.Count == 0) return new List(); + + // 找到边界 + int minX = int.MaxValue, maxX = int.MinValue; + int minY = int.MaxValue, maxY = int.MinValue; + + foreach (Vector2Int pixel in pixels) + { + if (pixel.x < minX) minX = pixel.x; + if (pixel.x > maxX) maxX = pixel.x; + if (pixel.y < minY) minY = pixel.y; + if (pixel.y > maxY) maxY = pixel.y; + } + + // 创建矩形边界 + List bounds = new List + { + new Vector2(minX * downSample, minY * downSample), + new Vector2(maxX * downSample, minY * downSample), + new Vector2(maxX * downSample, maxY * downSample), + new Vector2(minX * downSample, maxY * downSample) + }; + + return bounds; + } + + List ConvertToWorldCoordinates(List texturePoints) + { + List worldPoints = new List(); + + foreach (Vector2 texCoord in texturePoints) + { + Vector3 viewportPos = new Vector3( + texCoord.x / processedTexture.width, + texCoord.y / processedTexture.height, + shadowCamera.nearClipPlane + ); + + Vector3 worldPos = shadowCamera.ViewportToWorldPoint(viewportPos); + worldPoints.Add(new Vector2(worldPos.x, worldPos.y)); + } + + return worldPoints; + } + + // 调试:在Scene视图中显示阴影区域 + void OnDrawGizmosSelected() + { + if (shadowGrid == null) return; + + Gizmos.color = Color.red; + float cellSizeX = 1f / shadowGrid.GetLength(0); + float cellSizeY = 1f / shadowGrid.GetLength(1); + + for (int x = 0; x < shadowGrid.GetLength(0); x++) + { + for (int y = 0; y < shadowGrid.GetLength(1); y++) + { + if (shadowGrid[x, y]) + { + Vector3 viewportPos = new Vector3( + (x + 0.5f) * cellSizeX, + (y + 0.5f) * cellSizeY, + shadowCamera.nearClipPlane + ); + Vector3 worldPos = shadowCamera.ViewportToWorldPoint(viewportPos); + Gizmos.DrawWireCube(worldPos, new Vector3(cellSizeX, cellSizeY, 0.1f)); + } + } + } + } + + [ContextMenu("Debug Shadow Info")] + void DebugShadowInfo() + { + shadowCamera.Render(); + RenderTexture.active = shadowRT; + processedTexture.ReadPixels(new Rect(0, 0, shadowRT.width, shadowRT.height), 0, 0); + processedTexture.Apply(); + RenderTexture.active = null; + + int shadowPixels = 0; + int totalPixels = processedTexture.width * processedTexture.height; + + for (int x = 0; x < processedTexture.width; x += 10) + { + for (int y = 0; y < processedTexture.height; y += 10) + { + if (processedTexture.GetPixel(x, y).grayscale < shadowThreshold) + shadowPixels++; + } + } + + Debug.Log($"Shadow coverage: {shadowPixels}/{(totalPixels / 100)} ({(float)shadowPixels / (totalPixels / 100) * 100f:F1}%)"); + Debug.Log($"Texture size: {processedTexture.width}x{processedTexture.height}"); + } +} \ No newline at end of file diff --git a/Assets/Scripts/Test/Light/SimpleShadowCollider.cs.meta b/Assets/Scripts/Test/Light/SimpleShadowCollider.cs.meta new file mode 100644 index 0000000..3326f1d --- /dev/null +++ b/Assets/Scripts/Test/Light/SimpleShadowCollider.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: eb1369db1529b6543ba24519d5c2a35d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/ProjectSettings/TagManager.asset b/ProjectSettings/TagManager.asset index 8d9a8a6..4744edd 100644 --- a/ProjectSettings/TagManager.asset +++ b/ProjectSettings/TagManager.asset @@ -16,7 +16,7 @@ TagManager: - - DestroyItDebris - Shadow - - + - Panel - - - diff --git a/UserSettings/Layouts/default-2022.dwlt b/UserSettings/Layouts/default-2022.dwlt index e57c286..3922edd 100644 --- a/UserSettings/Layouts/default-2022.dwlt +++ b/UserSettings/Layouts/default-2022.dwlt @@ -15,11 +15,11 @@ MonoBehaviour: m_PixelRect: serializedVersion: 2 x: 0 - y: 43.2 - width: 2048 - height: 1188.8 + y: 43 + width: 2560 + height: 1349 m_ShowMode: 4 - m_Title: Scene + m_Title: Inspector m_RootView: {fileID: 2} m_MinSize: {x: 875, y: 721} m_MaxSize: {x: 10000, y: 10000} @@ -44,8 +44,8 @@ MonoBehaviour: serializedVersion: 2 x: 0 y: 0 - width: 2048 - height: 1188.8 + width: 2560 + height: 1349 m_MinSize: {x: 875, y: 300} m_MaxSize: {x: 10000, y: 10000} m_UseTopView: 1 @@ -69,7 +69,7 @@ MonoBehaviour: serializedVersion: 2 x: 0 y: 0 - width: 2048 + width: 2560 height: 30 m_MinSize: {x: 0, y: 0} m_MaxSize: {x: 0, y: 0} @@ -90,8 +90,8 @@ MonoBehaviour: m_Position: serializedVersion: 2 x: 0 - y: 1168.8 - width: 2048 + y: 1329 + width: 2560 height: 20 m_MinSize: {x: 0, y: 0} m_MaxSize: {x: 0, y: 0} @@ -114,12 +114,12 @@ MonoBehaviour: serializedVersion: 2 x: 0 y: 30 - width: 2048 - height: 1138.8 + width: 2560 + height: 1299 m_MinSize: {x: 300, y: 100} m_MaxSize: {x: 24288, y: 16192} vertical: 0 - controlID: 42 + controlID: 40 draggingID: 0 --- !u!114 &6 MonoBehaviour: @@ -140,12 +140,12 @@ MonoBehaviour: serializedVersion: 2 x: 0 y: 0 - width: 1501.6 - height: 1138.8 + width: 1877 + height: 1299 m_MinSize: {x: 200, y: 100} m_MaxSize: {x: 16192, y: 16192} vertical: 1 - controlID: 43 + controlID: 41 draggingID: 0 --- !u!114 &7 MonoBehaviour: @@ -166,12 +166,12 @@ MonoBehaviour: serializedVersion: 2 x: 0 y: 0 - width: 1501.6 - height: 758.4 + width: 1877 + height: 865 m_MinSize: {x: 200, y: 50} m_MaxSize: {x: 16192, y: 8096} vertical: 0 - controlID: 44 + controlID: 42 draggingID: 0 --- !u!114 &8 MonoBehaviour: @@ -190,8 +190,8 @@ MonoBehaviour: serializedVersion: 2 x: 0 y: 0 - width: 325.6 - height: 758.4 + width: 407 + height: 865 m_MinSize: {x: 201, y: 221} m_MaxSize: {x: 4001, y: 4021} m_ActualView: {fileID: 13} @@ -214,10 +214,10 @@ MonoBehaviour: m_Children: [] m_Position: serializedVersion: 2 - x: 325.6 + x: 407 y: 0 - width: 1176 - height: 758.4 + width: 1470 + height: 865 m_MinSize: {x: 202, y: 221} m_MaxSize: {x: 4002, y: 4021} m_ActualView: {fileID: 14} @@ -247,9 +247,9 @@ MonoBehaviour: m_Position: serializedVersion: 2 x: 0 - y: 758.4 - width: 1501.6 - height: 380.40002 + y: 865 + width: 1877 + height: 434 m_MinSize: {x: 101, y: 121} m_MaxSize: {x: 4001, y: 4021} m_ActualView: {fileID: 12} @@ -276,12 +276,12 @@ MonoBehaviour: m_Children: [] m_Position: serializedVersion: 2 - x: 1501.6 + x: 1877 y: 0 - width: 546.4 - height: 1138.8 - m_MinSize: {x: 275, y: 100} - m_MaxSize: {x: 4000, y: 4000} + width: 683 + height: 1299 + m_MinSize: {x: 276, y: 121} + m_MaxSize: {x: 4001, y: 4021} m_ActualView: {fileID: 25} m_Panes: - {fileID: 25} @@ -304,15 +304,15 @@ MonoBehaviour: m_MaxSize: {x: 4000, y: 4000} m_TitleContent: m_Text: Console - m_Image: {fileID: -4950941429401207979, guid: 0000000000000000d000000000000000, + m_Image: {fileID: -4327648978806127646, guid: 0000000000000000d000000000000000, type: 0} m_Tooltip: m_Pos: serializedVersion: 2 x: 0 - y: 832 - width: 1500.6 - height: 359.40002 + y: 938 + width: 1876 + height: 413 m_SerializedDataModeController: m_DataMode: 0 m_PreferredDataMode: 0 @@ -339,15 +339,15 @@ MonoBehaviour: m_MaxSize: {x: 4000, y: 4000} m_TitleContent: m_Text: Hierarchy - m_Image: {fileID: -3734745235275155857, guid: 0000000000000000d000000000000000, + m_Image: {fileID: 7966133145522015247, guid: 0000000000000000d000000000000000, type: 0} m_Tooltip: m_Pos: serializedVersion: 2 x: 0 - y: 73.6 - width: 324.6 - height: 737.4 + y: 73 + width: 406 + height: 844 m_SerializedDataModeController: m_DataMode: 0 m_PreferredDataMode: 0 @@ -361,9 +361,9 @@ MonoBehaviour: m_SceneHierarchy: m_TreeViewState: scrollPos: {x: 0, y: 0} - m_SelectedIDs: 46d1fbff - m_LastClickedID: -274106 - m_ExpandedIDs: 8673fdff5ea9fdffd8cefdff22d1fdff80d3fdff3c85feff12f2ffffe0f7ffff18840000 + m_SelectedIDs: + m_LastClickedID: 0 + m_ExpandedIDs: 08fbffffe27c0000 m_RenameOverlay: m_UserAcceptedRename: 0 m_Name: @@ -403,15 +403,15 @@ MonoBehaviour: m_MaxSize: {x: 4000, y: 4000} m_TitleContent: m_Text: Scene - m_Image: {fileID: 8634526014445323508, guid: 0000000000000000d000000000000000, + m_Image: {fileID: 2593428753322112591, guid: 0000000000000000d000000000000000, type: 0} m_Tooltip: m_Pos: serializedVersion: 2 - x: 325.6 - y: 73.6 - width: 1174 - height: 737.4 + x: 407 + y: 73 + width: 1468 + height: 844 m_SerializedDataModeController: m_DataMode: 0 m_PreferredDataMode: 0 @@ -783,9 +783,9 @@ MonoBehaviour: m_PlayAudio: 0 m_AudioPlay: 0 m_Position: - m_Target: {x: -1.4945829, y: 36.10217, z: 125.86397} + m_Target: {x: -0.6338736, y: 2.8792658, z: 9.9932} speed: 2 - m_Value: {x: -1.4945829, y: 36.10217, z: 125.86397} + m_Value: {x: -0.6338736, y: 2.8792658, z: 9.9932} m_RenderMode: 0 m_CameraMode: drawMode: 0 @@ -831,13 +831,13 @@ MonoBehaviour: m_GridAxis: 1 m_gridOpacity: 0.5 m_Rotation: - m_Target: {x: -0.11434219, y: 0.0062596397, z: 0.00068356807, w: 0.99344337} + m_Target: {x: 0.1730932, y: 0.018612249, z: -0.0032754778, w: 0.98472977} speed: 2 - m_Value: {x: -0.11434045, y: 0.005067412, z: 0.0005463472, w: 0.9934286} + m_Value: {x: 0.17309225, y: 0.018612146, z: -0.0032754599, w: 0.98472434} m_Size: - m_Target: 80.36852 + m_Target: 8.308297 speed: 2 - m_Value: 76.90768 + m_Value: 8.308297 m_Ortho: m_Target: 0 speed: 2 @@ -855,7 +855,7 @@ MonoBehaviour: m_FarClip: 10000 m_DynamicClip: 0 m_OcclusionCulling: 0 - m_LastSceneViewRotation: {x: 0.07008733, y: -0.042786285, z: 0.0029896083, w: 0.99662733} + m_LastSceneViewRotation: {x: 0, y: 0, z: 0, w: 1} m_LastSceneViewOrtho: 0 m_ReplacementShader: {fileID: 0} m_ReplacementString: @@ -878,15 +878,15 @@ MonoBehaviour: m_MaxSize: {x: 4000, y: 4000} m_TitleContent: m_Text: Game - m_Image: {fileID: 4621777727084837110, guid: 0000000000000000d000000000000000, + m_Image: {fileID: -6423792434712278376, guid: 0000000000000000d000000000000000, type: 0} m_Tooltip: m_Pos: serializedVersion: 2 - x: 325.6 - y: 73.6 - width: 1174 - height: 737.4 + x: 407 + y: 73 + width: 1468 + height: 844 m_SerializedDataModeController: m_DataMode: 0 m_PreferredDataMode: 0 @@ -918,10 +918,10 @@ MonoBehaviour: m_VRangeLocked: 0 hZoomLockedByDefault: 0 vZoomLockedByDefault: 0 - m_HBaseRangeMin: -1024 - m_HBaseRangeMax: 1024 - m_VBaseRangeMin: -576 - m_VBaseRangeMax: 576 + m_HBaseRangeMin: -1280 + m_HBaseRangeMax: 1280 + m_VBaseRangeMin: -720 + m_VBaseRangeMax: 720 m_HAllowExceedBaseRangeMin: 1 m_HAllowExceedBaseRangeMax: 1 m_VAllowExceedBaseRangeMin: 1 @@ -939,23 +939,23 @@ MonoBehaviour: serializedVersion: 2 x: 0 y: 21 - width: 1174 - height: 716.4 - m_Scale: {x: 0.5732422, y: 0.5732422} - m_Translation: {x: 587, y: 358.2} + width: 1468 + height: 823 + m_Scale: {x: 0.5715278, y: 0.5715278} + m_Translation: {x: 733.99994, y: 411.5} m_MarginLeft: 0 m_MarginRight: 0 m_MarginTop: 0 m_MarginBottom: 0 m_LastShownAreaInsideMargins: serializedVersion: 2 - x: -1024 - y: -624.8668 - width: 2048 - height: 1249.7336 + x: -1284.277 + y: -720 + width: 2568.554 + height: 1440 m_MinimalGUI: 1 - m_defaultScale: 0.5732422 - m_LastWindowPixelSize: {x: 1467.5, y: 921.75} + m_defaultScale: 0.5715278 + m_LastWindowPixelSize: {x: 1468, y: 844} m_ClearInEditMode: 1 m_NoCameraWarning: 1 m_LowResolutionForAspectRatios: 01000001000000000000 @@ -978,7 +978,7 @@ MonoBehaviour: m_MaxSize: {x: 4000, y: 4000} m_TitleContent: m_Text: Package Manager - m_Image: {fileID: 5076950121296946556, guid: 0000000000000000d000000000000000, + m_Image: {fileID: -2824328813065806953, guid: 0000000000000000d000000000000000, type: 0} m_Tooltip: m_Pos: @@ -1088,7 +1088,7 @@ MonoBehaviour: x: 407 y: 73 width: 1468 - height: 832 + height: 844 m_SerializedDataModeController: m_DataMode: 0 m_PreferredDataMode: 0 @@ -1117,15 +1117,15 @@ MonoBehaviour: m_MaxSize: {x: 4000, y: 4000} m_TitleContent: m_Text: Asset Store - m_Image: {fileID: -7444545952099596278, guid: 0000000000000000d000000000000000, + m_Image: {fileID: -8693916549880196297, guid: 0000000000000000d000000000000000, type: 0} m_Tooltip: m_Pos: serializedVersion: 2 - x: 325.6 - y: 73.6 - width: 1174 - height: 737.4 + x: 407 + y: 73 + width: 1468 + height: 844 m_SerializedDataModeController: m_DataMode: 0 m_PreferredDataMode: 0 @@ -1152,15 +1152,15 @@ MonoBehaviour: m_MaxSize: {x: 10000, y: 10000} m_TitleContent: m_Text: Project - m_Image: {fileID: -5179483145760003458, guid: 0000000000000000d000000000000000, + m_Image: {fileID: -5467254957812901981, guid: 0000000000000000d000000000000000, type: 0} m_Tooltip: m_Pos: serializedVersion: 2 x: 0 - y: 832 - width: 1500.6 - height: 359.40002 + y: 938 + width: 1876 + height: 413 m_SerializedDataModeController: m_DataMode: 0 m_PreferredDataMode: 0 @@ -1192,14 +1192,14 @@ MonoBehaviour: m_LastFolders: - Assets/Scripts/Test/Light m_LastFoldersGridSize: 16 - m_LastProjectPath: D:\UnityProject\BlueArchiveMiniGame + m_LastProjectPath: C:\UnityProject\BlueArchiveMiniGame m_LockTracker: m_IsLocked: 0 m_FolderTreeState: - scrollPos: {x: 0, y: 124.599976} - m_SelectedIDs: 568c0000 - m_LastClickedID: 35926 - m_ExpandedIDs: 0000000072770000648300007c83000082830000cc83000000ca9a3bffffff7f + scrollPos: {x: 0, y: 27} + m_SelectedIDs: ce7f0000 + m_LastClickedID: 32718 + m_ExpandedIDs: 00000000c47d0000c67d0000c87d0000ca7d0000cc7d0000ce7d0000d07d0000c47f0000ce7f000000ca9a3b m_RenameOverlay: m_UserAcceptedRename: 0 m_Name: @@ -1227,7 +1227,7 @@ MonoBehaviour: scrollPos: {x: 0, y: 0} m_SelectedIDs: m_LastClickedID: 0 - m_ExpandedIDs: 0000000064830000 + m_ExpandedIDs: 00000000c47d0000c67d0000c87d0000ca7d0000cc7d0000ce7d0000d07d0000 m_RenameOverlay: m_UserAcceptedRename: 0 m_Name: @@ -1252,26 +1252,26 @@ MonoBehaviour: m_Icon: {fileID: 0} m_ResourceFile: m_ListAreaState: - m_SelectedInstanceIDs: 8673fdff - m_LastClickedInstanceID: -167034 + m_SelectedInstanceIDs: + m_LastClickedInstanceID: 0 m_HadKeyboardFocusLastEvent: 1 m_ExpandedInstanceIDs: c6230000068f1200828d00000c8d0000121d050042e40400b2930000c4fa0400ae0e0500f2ef0400682a4200802a42008a17420050a10000ee090500bc130500eccd000032030000bef80000c2a300000000000040f500007a860000647c0600f2b606001cb7060010170100b6290100e8ae00000aae0400447f0000d283000082ae0000d4beffff66c70000 m_RenameOverlay: m_UserAcceptedRename: 0 - m_Name: RaycastShadowCollider - m_OriginalName: RaycastShadowCollider + m_Name: + m_OriginalName: m_EditFieldRect: serializedVersion: 2 x: 0 y: 0 width: 0 height: 0 - m_UserData: 38236 + m_UserData: 0 m_IsWaitingForDelay: 0 m_IsRenaming: 0 - m_OriginalEventType: 0 + m_OriginalEventType: 11 m_IsRenamingFilename: 1 - m_ClientGUIView: {fileID: 10} + m_ClientGUIView: {fileID: 9} m_CreateAssetUtility: m_EndAction: {fileID: 0} m_InstanceID: 0 @@ -1299,7 +1299,7 @@ MonoBehaviour: m_MaxSize: {x: 4000, y: 4000} m_TitleContent: m_Text: Animator - m_Image: {fileID: 1711060831702674872, guid: 0000000000000000d000000000000000, + m_Image: {fileID: -1673928668082335149, guid: 0000000000000000d000000000000000, type: 0} m_Tooltip: m_Pos: @@ -1423,7 +1423,7 @@ MonoBehaviour: m_MaxSize: {x: 4000, y: 4000} m_TitleContent: m_Text: Animation - m_Image: {fileID: -3237396543322336831, guid: 0000000000000000d000000000000000, + m_Image: {fileID: -8166618308981325432, guid: 0000000000000000d000000000000000, type: 0} m_Tooltip: m_Pos: @@ -1444,7 +1444,7 @@ MonoBehaviour: m_OverlaysVisible: 1 m_LockTracker: m_IsLocked: 0 - m_LastSelectedObjectID: -167034 + m_LastSelectedObjectID: -21542028 --- !u!114 &24 MonoBehaviour: m_ObjectHideFlags: 52 @@ -1461,7 +1461,7 @@ MonoBehaviour: m_MaxSize: {x: 4000, y: 4000} m_TitleContent: m_Text: Audio Mixer - m_Image: {fileID: -3283902137440876849, guid: 0000000000000000d000000000000000, + m_Image: {fileID: 2344599766593239149, guid: 0000000000000000d000000000000000, type: 0} m_Tooltip: m_Pos: @@ -1644,15 +1644,15 @@ MonoBehaviour: m_MaxSize: {x: 4000, y: 4000} m_TitleContent: m_Text: Inspector - m_Image: {fileID: -440750813802333266, guid: 0000000000000000d000000000000000, + m_Image: {fileID: -2667387946076563598, guid: 0000000000000000d000000000000000, type: 0} m_Tooltip: m_Pos: serializedVersion: 2 - x: 1501.6 - y: 73.6 - width: 545.4 - height: 1117.8 + x: 1877 + y: 73 + width: 682 + height: 1278 m_SerializedDataModeController: m_DataMode: 0 m_PreferredDataMode: 0 @@ -1692,7 +1692,7 @@ MonoBehaviour: m_MaxSize: {x: 4000, y: 4000} m_TitleContent: m_Text: Lighting - m_Image: {fileID: -1477008817101679558, guid: 0000000000000000d000000000000000, + m_Image: {fileID: -1347227620855488341, guid: 0000000000000000d000000000000000, type: 0} m_Tooltip: m_Pos: