diff --git a/AIClient/AgentScripts/BuildTownSquare.cs b/AIClient/AgentScripts/BuildTownSquare.cs index 765167d..451dc2b 100644 --- a/AIClient/AgentScripts/BuildTownSquare.cs +++ b/AIClient/AgentScripts/BuildTownSquare.cs @@ -310,8 +310,9 @@ public static class BuildTownSquare var light = lightGo.AddComponent(); light.type = LightType.Directional; light.color = new Color(1f, 0.96f, 0.88f); - light.intensity = 1.05f; + light.intensity = 1.15f; light.shadows = LightShadows.Soft; + light.shadowStrength = 1f; lightGo.transform.rotation = Quaternion.Euler(50f, -30f, 0f); var camGo = new GameObject("Main Camera"); @@ -330,9 +331,9 @@ public static class BuildTownSquare PrefabUtility.InstantiatePrefab(plaza); RenderSettings.ambientMode = AmbientMode.Trilight; - RenderSettings.ambientSkyColor = new Color(0.55f, 0.7f, 0.85f); - RenderSettings.ambientEquatorColor = new Color(0.5f, 0.52f, 0.48f); - RenderSettings.ambientGroundColor = new Color(0.35f, 0.32f, 0.28f); + RenderSettings.ambientSkyColor = new Color(0.32f, 0.40f, 0.50f); + RenderSettings.ambientEquatorColor = new Color(0.24f, 0.26f, 0.24f); + RenderSettings.ambientGroundColor = new Color(0.16f, 0.15f, 0.13f); EditorSceneManager.SaveScene(scene, ScenePath); return ScenePath; diff --git a/AIClient/Assets/Bundles/Characters/MaleExplorer/MaleExplorer_ao.png b/AIClient/Assets/Bundles/Characters/MaleExplorer/MaleExplorer_ao.png index 9846c0a..405d64b 100644 Binary files a/AIClient/Assets/Bundles/Characters/MaleExplorer/MaleExplorer_ao.png and b/AIClient/Assets/Bundles/Characters/MaleExplorer/MaleExplorer_ao.png differ diff --git a/AIClient/Assets/Bundles/Characters/MaleExplorer/MaleExplorer_color.png b/AIClient/Assets/Bundles/Characters/MaleExplorer/MaleExplorer_color.png index 76ae495..568c614 100644 Binary files a/AIClient/Assets/Bundles/Characters/MaleExplorer/MaleExplorer_color.png and b/AIClient/Assets/Bundles/Characters/MaleExplorer/MaleExplorer_color.png differ diff --git a/AIClient/Assets/Bundles/Characters/MaleExplorer/MaleExplorer_metallic.png b/AIClient/Assets/Bundles/Characters/MaleExplorer/MaleExplorer_metallic.png index e0023f3..29540f3 100644 Binary files a/AIClient/Assets/Bundles/Characters/MaleExplorer/MaleExplorer_metallic.png and b/AIClient/Assets/Bundles/Characters/MaleExplorer/MaleExplorer_metallic.png differ diff --git a/AIClient/Assets/Bundles/Characters/MaleExplorer/MaleExplorer_normal.png b/AIClient/Assets/Bundles/Characters/MaleExplorer/MaleExplorer_normal.png index f0f3c15..7efa427 100644 Binary files a/AIClient/Assets/Bundles/Characters/MaleExplorer/MaleExplorer_normal.png and b/AIClient/Assets/Bundles/Characters/MaleExplorer/MaleExplorer_normal.png differ diff --git a/AIClient/Assets/Bundles/Characters/MaleExplorer/MaleExplorer_roughness.png b/AIClient/Assets/Bundles/Characters/MaleExplorer/MaleExplorer_roughness.png index c9865f6..cdb314e 100644 Binary files a/AIClient/Assets/Bundles/Characters/MaleExplorer/MaleExplorer_roughness.png and b/AIClient/Assets/Bundles/Characters/MaleExplorer/MaleExplorer_roughness.png differ diff --git a/AIClient/Assets/Bundles/Scenes/Town/TownSquare/TownSquare.unity b/AIClient/Assets/Bundles/Scenes/Town/TownSquare/TownSquare.unity index 824efae..92e2ef4 100644 --- a/AIClient/Assets/Bundles/Scenes/Town/TownSquare/TownSquare.unity +++ b/AIClient/Assets/Bundles/Scenes/Town/TownSquare/TownSquare.unity @@ -20,9 +20,9 @@ RenderSettings: m_FogDensity: 0.01 m_LinearFogStart: 0 m_LinearFogEnd: 300 - m_AmbientSkyColor: {r: 0.55, g: 0.7, b: 0.85, a: 1} - m_AmbientEquatorColor: {r: 0.5, g: 0.52, b: 0.48, a: 1} - m_AmbientGroundColor: {r: 0.35, g: 0.32, b: 0.28, a: 1} + m_AmbientSkyColor: {r: 0.32, g: 0.4, b: 0.5, a: 1} + m_AmbientEquatorColor: {r: 0.24, g: 0.26, b: 0.24, a: 1} + m_AmbientGroundColor: {r: 0.16, g: 0.15, b: 0.13, a: 1} m_AmbientIntensity: 1 m_AmbientMode: 1 m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} @@ -281,6 +281,7 @@ GameObject: m_Component: - component: {fileID: 2073245442} - component: {fileID: 2073245441} + - component: {fileID: 2073245443} m_Layer: 0 m_Name: Directional Light m_TagString: Untagged @@ -300,7 +301,7 @@ Light: m_Type: 1 m_Shape: 0 m_Color: {r: 1, g: 0.96, b: 0.88, a: 1} - m_Intensity: 1.05 + m_Intensity: 1.15 m_Range: 10 m_SpotAngle: 30 m_InnerSpotAngle: 21.80208 @@ -365,6 +366,29 @@ Transform: m_Children: [] m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &2073245443 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2073245440} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 474bcb49853aa07438625e644c072ee6, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Version: 3 + m_UsePipelineSettings: 1 + m_AdditionalLightsShadowResolutionTier: 2 + m_LightLayerMask: 1 + m_RenderingLayers: 1 + m_CustomShadowLayers: 0 + m_ShadowLayerMask: 1 + m_ShadowRenderingLayers: 1 + m_LightCookieSize: {x: 1, y: 1} + m_LightCookieOffset: {x: 0, y: 0} + m_SoftShadowQuality: 0 --- !u!1660057539 &9223372036854775807 SceneRoots: m_ObjectHideFlags: 0 diff --git a/AIClient/Assets/Bundles/Scenes/Town/TownSquare/bench/bench_base.png b/AIClient/Assets/Bundles/Scenes/Town/TownSquare/bench/bench_base.png index e8de7ce..fcfb801 100644 Binary files a/AIClient/Assets/Bundles/Scenes/Town/TownSquare/bench/bench_base.png and b/AIClient/Assets/Bundles/Scenes/Town/TownSquare/bench/bench_base.png differ diff --git a/AIClient/Assets/Bundles/Scenes/Town/TownSquare/bench/bench_mix.png b/AIClient/Assets/Bundles/Scenes/Town/TownSquare/bench/bench_mix.png index e4b6fae..0e38b2e 100644 Binary files a/AIClient/Assets/Bundles/Scenes/Town/TownSquare/bench/bench_mix.png and b/AIClient/Assets/Bundles/Scenes/Town/TownSquare/bench/bench_mix.png differ diff --git a/AIClient/Assets/Bundles/Scenes/Town/TownSquare/board/board_base.png b/AIClient/Assets/Bundles/Scenes/Town/TownSquare/board/board_base.png index dcc6148..b47e13a 100644 Binary files a/AIClient/Assets/Bundles/Scenes/Town/TownSquare/board/board_base.png and b/AIClient/Assets/Bundles/Scenes/Town/TownSquare/board/board_base.png differ diff --git a/AIClient/Assets/Bundles/Scenes/Town/TownSquare/board/board_mix.png b/AIClient/Assets/Bundles/Scenes/Town/TownSquare/board/board_mix.png index 709d9af..1ab83d2 100644 Binary files a/AIClient/Assets/Bundles/Scenes/Town/TownSquare/board/board_mix.png and b/AIClient/Assets/Bundles/Scenes/Town/TownSquare/board/board_mix.png differ diff --git a/AIClient/Assets/Bundles/Scenes/Town/TownSquare/bush/bush_base.png b/AIClient/Assets/Bundles/Scenes/Town/TownSquare/bush/bush_base.png index c2e5f57..2f2ec0a 100644 Binary files a/AIClient/Assets/Bundles/Scenes/Town/TownSquare/bush/bush_base.png and b/AIClient/Assets/Bundles/Scenes/Town/TownSquare/bush/bush_base.png differ diff --git a/AIClient/Assets/Bundles/Scenes/Town/TownSquare/bush/bush_mix.png b/AIClient/Assets/Bundles/Scenes/Town/TownSquare/bush/bush_mix.png index 4a9b7a4..20547e8 100644 Binary files a/AIClient/Assets/Bundles/Scenes/Town/TownSquare/bush/bush_mix.png and b/AIClient/Assets/Bundles/Scenes/Town/TownSquare/bush/bush_mix.png differ diff --git a/AIClient/Assets/Bundles/Scenes/Town/TownSquare/fountain/fountain_base.png b/AIClient/Assets/Bundles/Scenes/Town/TownSquare/fountain/fountain_base.png index fa59420..8c42b78 100644 Binary files a/AIClient/Assets/Bundles/Scenes/Town/TownSquare/fountain/fountain_base.png and b/AIClient/Assets/Bundles/Scenes/Town/TownSquare/fountain/fountain_base.png differ diff --git a/AIClient/Assets/Bundles/Scenes/Town/TownSquare/fountain/fountain_mix.png b/AIClient/Assets/Bundles/Scenes/Town/TownSquare/fountain/fountain_mix.png index 6f60679..4bda9f7 100644 Binary files a/AIClient/Assets/Bundles/Scenes/Town/TownSquare/fountain/fountain_mix.png and b/AIClient/Assets/Bundles/Scenes/Town/TownSquare/fountain/fountain_mix.png differ diff --git a/AIClient/Assets/Bundles/Scenes/Town/TownSquare/ground/ground_base.png b/AIClient/Assets/Bundles/Scenes/Town/TownSquare/ground/ground_base.png index 48d3374..b618509 100644 Binary files a/AIClient/Assets/Bundles/Scenes/Town/TownSquare/ground/ground_base.png and b/AIClient/Assets/Bundles/Scenes/Town/TownSquare/ground/ground_base.png differ diff --git a/AIClient/Assets/Bundles/Scenes/Town/TownSquare/ground/ground_mix.png b/AIClient/Assets/Bundles/Scenes/Town/TownSquare/ground/ground_mix.png index 63f6615..797db18 100644 Binary files a/AIClient/Assets/Bundles/Scenes/Town/TownSquare/ground/ground_mix.png and b/AIClient/Assets/Bundles/Scenes/Town/TownSquare/ground/ground_mix.png differ diff --git a/AIClient/Assets/Bundles/Scenes/Town/TownSquare/lamp/lamp_base.png b/AIClient/Assets/Bundles/Scenes/Town/TownSquare/lamp/lamp_base.png index 4cce96b..7ebb658 100644 Binary files a/AIClient/Assets/Bundles/Scenes/Town/TownSquare/lamp/lamp_base.png and b/AIClient/Assets/Bundles/Scenes/Town/TownSquare/lamp/lamp_base.png differ diff --git a/AIClient/Assets/Bundles/Scenes/Town/TownSquare/lamp/lamp_mix.png b/AIClient/Assets/Bundles/Scenes/Town/TownSquare/lamp/lamp_mix.png index cc72625..ef9fd09 100644 Binary files a/AIClient/Assets/Bundles/Scenes/Town/TownSquare/lamp/lamp_mix.png and b/AIClient/Assets/Bundles/Scenes/Town/TownSquare/lamp/lamp_mix.png differ diff --git a/AIClient/Assets/Bundles/Scenes/Town/TownSquare/shop/shop_base.png b/AIClient/Assets/Bundles/Scenes/Town/TownSquare/shop/shop_base.png index 3fbd02a..a7a1410 100644 Binary files a/AIClient/Assets/Bundles/Scenes/Town/TownSquare/shop/shop_base.png and b/AIClient/Assets/Bundles/Scenes/Town/TownSquare/shop/shop_base.png differ diff --git a/AIClient/Assets/Bundles/Scenes/Town/TownSquare/shop/shop_mix.png b/AIClient/Assets/Bundles/Scenes/Town/TownSquare/shop/shop_mix.png index e848684..4ebba7b 100644 Binary files a/AIClient/Assets/Bundles/Scenes/Town/TownSquare/shop/shop_mix.png and b/AIClient/Assets/Bundles/Scenes/Town/TownSquare/shop/shop_mix.png differ diff --git a/AIClient/Assets/Bundles/Scenes/Town/TownSquare/tree/tree_base.png b/AIClient/Assets/Bundles/Scenes/Town/TownSquare/tree/tree_base.png index 7c4f3ed..f27e6ee 100644 Binary files a/AIClient/Assets/Bundles/Scenes/Town/TownSquare/tree/tree_base.png and b/AIClient/Assets/Bundles/Scenes/Town/TownSquare/tree/tree_base.png differ diff --git a/AIClient/Assets/Bundles/Scenes/Town/TownSquare/tree/tree_mix.png b/AIClient/Assets/Bundles/Scenes/Town/TownSquare/tree/tree_mix.png index a6a92e2..54f1212 100644 Binary files a/AIClient/Assets/Bundles/Scenes/Town/TownSquare/tree/tree_mix.png and b/AIClient/Assets/Bundles/Scenes/Town/TownSquare/tree/tree_mix.png differ diff --git a/AIClient/Assets/Bundles/Shaders/XShader/XPbr.shader b/AIClient/Assets/Bundles/Shaders/XShader/XPbr.shader index 27ae32f..5092a02 100644 --- a/AIClient/Assets/Bundles/Shaders/XShader/XPbr.shader +++ b/AIClient/Assets/Bundles/Shaders/XShader/XPbr.shader @@ -13,6 +13,10 @@ Shader "Test/XPbr" _Metallic("Metallic", Range(0.0, 1.0)) = 0.8 _Roughness("Roughness", Range(0.0, 1.0)) = 0.6 _AO("AO", Range(0.0, 1.0)) = 1.0 + + [HideInInspector][NoScaleOffset]unity_Lightmaps("unity_Lightmaps", 2DArray) = "" {} + [HideInInspector][NoScaleOffset]unity_LightmapsInd("unity_LightmapsInd", 2DArray) = "" {} + [HideInInspector][NoScaleOffset]unity_ShadowMasks("unity_ShadowMasks", 2DArray) = "" {} } SubShader @@ -33,13 +37,16 @@ Shader "Test/XPbr" #pragma target 2.0 #pragma multi_compile _ _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE _MAIN_LIGHT_SHADOWS_SCREEN - #pragma multi_compile _ _ADDITIONAL_LIGHTS_VERTEX _ADDITIONAL_LIGHTS + #pragma multi_compile _ _ADDITIONAL_LIGHTS_VERTEX _ADDITIONAL_LIGHTS + #pragma multi_compile_fragment _ _ADDITIONAL_LIGHT_SHADOWS + #pragma multi_compile_fragment _ _SHADOWS_SOFT _SHADOWS_SOFT_LOW _SHADOWS_SOFT_MEDIUM _SHADOWS_SOFT_HIGH + + #pragma multi_compile _ LIGHTMAP_SHADOW_MIXING + #pragma multi_compile _ SHADOWS_SHADOWMASK + #pragma multi_compile _ DIRLIGHTMAP_COMBINED #pragma multi_compile _ LIGHTMAP_ON #pragma multi_compile _ DYNAMICLIGHTMAP_ON - #pragma multi_compile_fragment _ _ADDITIONAL_LIGHT_SHADOWS - #pragma multi_compile_fragment _ _SHADOWS_SOFT _SHADOWS_SOFT_LOW _SHADOWS_SOFT_MEDIUM _SHADOWS_SOFT_HIGH - #pragma shader_feature_local_fragment _ALPHATEST_ON #pragma vertex vert @@ -155,18 +162,13 @@ Shader "Test/XPbr" ColorMask 0 HLSLPROGRAM - // Required to compile gles 2.0 with standard srp library #pragma prefer_hlslcc gles #pragma exclude_renderers d3d11_9x #pragma target 2.0 - // ------------------------------------- - // Material Keywords #pragma shader_feature_local_fragment _ALPHATEST_ON - - //-------------------------------------- - // GPU Instancing #pragma multi_compile_instancing + #pragma multi_compile_vertex _ _CASTING_PUNCTUAL_LIGHT_SHADOW #pragma vertex vert #pragma fragment frag @@ -175,6 +177,7 @@ Shader "Test/XPbr" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl" float3 _LightDirection; + float3 _LightPosition; Varyings vert(Attributes input) { @@ -185,13 +188,18 @@ Shader "Test/XPbr" float3 positionWS = TransformObjectToWorld(input.positionOS.xyz); float3 normalWS = TransformObjectToWorldNormal(input.normalOS); + #if defined(_CASTING_PUNCTUAL_LIGHT_SHADOW) + float3 lightDirectionWS = normalize(_LightPosition - positionWS); + #else + float3 lightDirectionWS = _LightDirection; + #endif - float4 positionCS = TransformWorldToHClip(ApplyShadowBias(positionWS, normalWS, _LightDirection)); + float4 positionCS = TransformWorldToHClip(ApplyShadowBias(positionWS, normalWS, lightDirectionWS)); #if UNITY_REVERSED_Z - positionCS.z = min(positionCS.z, positionCS.w * UNITY_NEAR_CLIP_VALUE); + positionCS.z = min(positionCS.z, UNITY_NEAR_CLIP_VALUE); #else - positionCS.z = max(positionCS.z, positionCS.w * UNITY_NEAR_CLIP_VALUE); + positionCS.z = max(positionCS.z, UNITY_NEAR_CLIP_VALUE); #endif output.positionCS = positionCS; @@ -210,6 +218,136 @@ Shader "Test/XPbr" } ENDHLSL } + + Pass + { + Name "DepthOnly" + Tags{ "LightMode" = "DepthOnly" } + + ZWrite On + ColorMask R + + HLSLPROGRAM + #pragma prefer_hlslcc gles + #pragma exclude_renderers d3d11_9x + #pragma target 2.0 + + #pragma shader_feature_local_fragment _ALPHATEST_ON + #pragma multi_compile_instancing + + #pragma vertex vert + #pragma fragment frag + + #include "XPbr_Base.hlsl" + + Varyings vert(Attributes input) + { + Varyings output = (Varyings)0; + UNITY_SETUP_INSTANCE_ID(input); + UNITY_TRANSFER_INSTANCE_ID(input, output); + UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output); + + output.positionCS = TransformObjectToHClip(input.positionOS.xyz); + output.uv = TRANSFORM_TEX(input.texcoord, _MainTex); + return output; + } + + half frag(Varyings input) : SV_TARGET + { + #if defined(_ALPHATEST_ON) + half alpha = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, input.uv).a; + clip(alpha - _Cutoff); + #endif + return input.positionCS.z; + } + ENDHLSL + } + + Pass + { + Name "Meta" + Tags{ "LightMode" = "Meta" } + + Cull Off + + HLSLPROGRAM + #pragma target 2.0 + #pragma vertex vert + #pragma fragment frag + #pragma shader_feature_local_fragment _ALPHATEST_ON + #pragma shader_feature EDITOR_VISUALIZATION + + #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" + #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/MetaInput.hlsl" + + CBUFFER_START(UnityPerMaterial) + float4 _MainTex_ST; + half4 _BaseColor; + half _Cutoff; + half _Metallic; + half _Roughness; + half _AO; + CBUFFER_END + TEXTURE2D(_MainTex); SAMPLER(sampler_MainTex); + TEXTURE2D(_MixTex); SAMPLER(sampler_MixTex); + + struct MetaAttributes + { + float4 positionOS : POSITION; + float3 normalOS : NORMAL; + float2 uv0 : TEXCOORD0; + float2 uv1 : TEXCOORD1; + float2 uv2 : TEXCOORD2; + UNITY_VERTEX_INPUT_INSTANCE_ID + }; + + struct MetaVaryings + { + float4 positionCS : SV_POSITION; + float2 uv : TEXCOORD0; + #ifdef EDITOR_VISUALIZATION + float2 VizUV : TEXCOORD1; + float4 LightCoord : TEXCOORD2; + #endif + }; + + MetaVaryings vert(MetaAttributes input) + { + MetaVaryings output = (MetaVaryings)0; + output.positionCS = UnityMetaVertexPosition(input.positionOS.xyz, input.uv1, input.uv2); + output.uv = TRANSFORM_TEX(input.uv0, _MainTex); + #ifdef EDITOR_VISUALIZATION + UnityEditorVizData(input.positionOS.xyz, input.uv0, input.uv1, input.uv2, output.VizUV, output.LightCoord); + #endif + return output; + } + + half4 frag(MetaVaryings input) : SV_Target + { + half4 albedoAlpha = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, input.uv); + #if defined(_ALPHATEST_ON) + clip(albedoAlpha.a - _Cutoff); + #endif + half4 mixTex = SAMPLE_TEXTURE2D(_MixTex, sampler_MixTex, input.uv); + half3 albedo = albedoAlpha.rgb * _BaseColor.rgb; + half metallic = saturate(mixTex.b * _Metallic); + half smoothness = 1.0 - saturate(mixTex.a * _Roughness); + half alpha = 1.0; + + BRDFData brdfData; + InitializeBRDFData(albedo, metallic, half3(0.0, 0.0, 0.0), smoothness, alpha, brdfData); + + MetaInput metaInput; + metaInput.Albedo = brdfData.diffuse + brdfData.specular * brdfData.roughness * 0.5; + metaInput.Emission = half3(0.0, 0.0, 0.0); + #ifdef EDITOR_VISUALIZATION + metaInput.VizUV = input.VizUV; + metaInput.LightCoord = input.LightCoord; + #endif + return UnityMetaFragment(metaInput); + } + ENDHLSL + } } FallBack Off diff --git a/AIClient/Assets/Bundles/Shaders/XShader/XPbr_Base.hlsl b/AIClient/Assets/Bundles/Shaders/XShader/XPbr_Base.hlsl index 1bd6ada..47cbf20 100644 --- a/AIClient/Assets/Bundles/Shaders/XShader/XPbr_Base.hlsl +++ b/AIClient/Assets/Bundles/Shaders/XShader/XPbr_Base.hlsl @@ -121,11 +121,10 @@ void InitializeInputData(Varyings input, half3 normalTS, out InputData inputData inputData.bakedGI = SAMPLE_GI(input.staticLightmapUV, input.vertexSH, inputData.normalWS); #else inputData.bakedGI = SampleSH(inputData.normalWS); -#endif - // 仅在运行时全局环境光开启后才覆盖(Game.cs 设置);否则保留场景自身 SH/光照贴图, - // 避免编辑器预览比 URP Lit 亮(旧写法无条件覆盖成硬编码的高强度三色环境光) + // 仅覆盖动态物体的探针环境光。光照贴图(含烘焙阴影/间接光)必须保留。 if (_XRuntimeAmbientEnabled > 0.5h) inputData.bakedGI = SampleXRuntimeAmbient(inputData.normalWS); +#endif inputData.normalizedScreenSpaceUV = GetNormalizedScreenSpaceUV(input.positionCS); inputData.shadowMask = SAMPLE_SHADOWMASK(input.staticLightmapUV); diff --git a/AIClient/Assets/Settings/URP/UniversalRP-1LowQuality.asset b/AIClient/Assets/Settings/URP/UniversalRP-1LowQuality.asset index 44e6467..4996f70 100644 --- a/AIClient/Assets/Settings/URP/UniversalRP-1LowQuality.asset +++ b/AIClient/Assets/Settings/URP/UniversalRP-1LowQuality.asset @@ -34,7 +34,7 @@ MonoBehaviour: m_LODCrossFadeDitheringType: 1 m_ShEvalMode: 0 m_MainLightRenderingMode: 1 - m_MainLightShadowsSupported: 0 + m_MainLightShadowsSupported: 1 m_MainLightShadowmapResolution: 1024 m_AdditionalLightsRenderingMode: 1 m_AdditionalLightsPerObjectLimit: 2 @@ -45,7 +45,7 @@ MonoBehaviour: m_AdditionalLightsShadowResolutionTierHigh: 1024 m_ReflectionProbeBlending: 0 m_ReflectionProbeBoxProjection: 0 - m_ShadowDistance: 10 + m_ShadowDistance: 150 m_ShadowCascadeCount: 1 m_Cascade2Split: 0.16666667 m_Cascade3Split: {x: 0.25800002, y: 0.5776} diff --git a/AIClient/Assets/Settings/URP/UniversalRP-2MediumQuality.asset b/AIClient/Assets/Settings/URP/UniversalRP-2MediumQuality.asset index fb45080..5773af3 100644 --- a/AIClient/Assets/Settings/URP/UniversalRP-2MediumQuality.asset +++ b/AIClient/Assets/Settings/URP/UniversalRP-2MediumQuality.asset @@ -34,8 +34,8 @@ MonoBehaviour: m_LODCrossFadeDitheringType: 1 m_ShEvalMode: 0 m_MainLightRenderingMode: 1 - m_MainLightShadowsSupported: 0 - m_MainLightShadowmapResolution: 512 + m_MainLightShadowsSupported: 1 + m_MainLightShadowmapResolution: 1024 m_AdditionalLightsRenderingMode: 1 m_AdditionalLightsPerObjectLimit: 4 m_AdditionalLightShadowsSupported: 0 @@ -45,7 +45,7 @@ MonoBehaviour: m_AdditionalLightsShadowResolutionTierHigh: 1024 m_ReflectionProbeBlending: 0 m_ReflectionProbeBoxProjection: 0 - m_ShadowDistance: 15 + m_ShadowDistance: 150 m_ShadowCascadeCount: 1 m_Cascade2Split: 0.16666667 m_Cascade3Split: {x: 0.25800002, y: 0.5776} diff --git a/AIClient/Assets/Settings/URP/UniversalRP-3HighQuality.asset b/AIClient/Assets/Settings/URP/UniversalRP-3HighQuality.asset index 5886c4c..f42c217 100644 --- a/AIClient/Assets/Settings/URP/UniversalRP-3HighQuality.asset +++ b/AIClient/Assets/Settings/URP/UniversalRP-3HighQuality.asset @@ -35,7 +35,7 @@ MonoBehaviour: m_ShEvalMode: 0 m_MainLightRenderingMode: 1 m_MainLightShadowsSupported: 1 - m_MainLightShadowmapResolution: 1024 + m_MainLightShadowmapResolution: 2048 m_AdditionalLightsRenderingMode: 1 m_AdditionalLightsPerObjectLimit: 4 m_AdditionalLightShadowsSupported: 0 @@ -45,7 +45,7 @@ MonoBehaviour: m_AdditionalLightsShadowResolutionTierHigh: 1024 m_ReflectionProbeBlending: 0 m_ReflectionProbeBoxProjection: 0 - m_ShadowDistance: 15 + m_ShadowDistance: 150 m_ShadowCascadeCount: 2 m_Cascade2Split: 0.26666668 m_Cascade3Split: {x: 0.25800002, y: 0.5776} diff --git a/AIClient/Assets/Settings/URP/UniversalRP-4VeryHighQuality.asset b/AIClient/Assets/Settings/URP/UniversalRP-4VeryHighQuality.asset index 772f4f5..2b1f1d9 100644 --- a/AIClient/Assets/Settings/URP/UniversalRP-4VeryHighQuality.asset +++ b/AIClient/Assets/Settings/URP/UniversalRP-4VeryHighQuality.asset @@ -45,7 +45,7 @@ MonoBehaviour: m_AdditionalLightsShadowResolutionTierHigh: 1024 m_ReflectionProbeBlending: 0 m_ReflectionProbeBoxProjection: 0 - m_ShadowDistance: 30 + m_ShadowDistance: 150 m_ShadowCascadeCount: 2 m_Cascade2Split: 0.2 m_Cascade3Split: {x: 0.10000001, y: 0.3} diff --git a/GameResProductProc.md b/GameResProductProc.md index 17fe2b3..6b93a3b 100644 --- a/GameResProductProc.md +++ b/GameResProductProc.md @@ -267,6 +267,7 @@ python Tools/gpt_image_generate.py --result-only --quality high --aspect-ratio 1 - 角色安装可参考:`Tools/install_character_bundles.py`。场景分件:拷到 `Bundles/Scenes/{类型}/{场景号}/{英文短名}/`(`Tools/output/run_townsquare_pipeline.py`)。设计原稿不进 Bundles。 - 碎叶等非流形:`bl_decimate.py` 在 collapse 卡住后会体素重网格再减面。 - 轴向:混元 GLB = glTF Y-up。烘焙在 Blender 里用 Z-up;**导出 FBX 时** `prepare_game_export` 转回 Y-up,原点放在**底面中点**。**局部 -Z 是正面**(设计图朝相机的那面,与 glTF 相机看向 -Z 一致)。Unity 摆放用「-Z 指向目标」,不要用 `LookRotation` 默认的 +Z forward,也不要再绕 X 扶正或抬高度。 +- 最终 `_base.png` / `_mix.png`(以及烘焙五通道 PNG)写出时做 **PNG 无损压缩**(zlib 最高档;有 Pillow 则 `optimize=True`)。像素不变,只缩小文件。 - 角色 Prefab:Unity 菜单 `AIGame/M3/Setup Character Prefab`。其他类型的 Prefab 步骤在细化时写明。 --- diff --git a/ResourceCreate.md b/ResourceCreate.md index c779dfa..9fadf1a 100644 --- a/ResourceCreate.md +++ b/ResourceCreate.md @@ -97,6 +97,7 @@ python Tools/hunyuan_3d_generate.py -i ref.png -o out.glb --no-interactive-login -> model_translator(默认)-> XPbr 两张图 + .mat/.meta <名>_base.png RGB=Albedo A=AO/透明 <名>_mix.png RG=球面法线 B=Metallic A=Roughness + 写出 PNG 时无损压缩(Blender compression=100 + zlib 9 / Pillow optimize) ``` ### AI / 命令行调用 diff --git a/Tools/model_tools/README.md b/Tools/model_tools/README.md index 6220413..604b111 100644 --- a/Tools/model_tools/README.md +++ b/Tools/model_tools/README.md @@ -9,6 +9,7 @@ -> model_translator:打包为 XPbr 两张图 + .mat/.meta _base.png RGB=Albedo A=AO/透明 _mix.png RG=球面法线 B=Metallic A=Roughness + 写出时 PNG 无损压缩(体积更小,像素不变) ``` ## 环境 diff --git a/Tools/model_tools/bl_bake.py b/Tools/model_tools/bl_bake.py index f758532..e352574 100644 --- a/Tools/model_tools/bl_bake.py +++ b/Tools/model_tools/bl_bake.py @@ -7,6 +7,7 @@ import os import sys sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +from png_compress import compress_png, prepare_blender_png DEFAULT_RAY_PCT = 0.02 # 测量失败时回退:低模包围盒对角线 * 2% RAY_SAFETY = 1.5 # 自适应射线安全系数(分离 P99 × 此值) @@ -199,8 +200,10 @@ def _bake_pass(low, high, target_node, name, bake_type, size, colorspace, path = os.path.abspath(os.path.join(outdir, "%s_%s.png" % (stem, name))) img.filepath_raw = path img.file_format = 'PNG' + prepare_blender_png(100) img.save() bpy.data.images.remove(img) + compress_png(path) return os.path.basename(path) diff --git a/Tools/model_tools/bl_convert.py b/Tools/model_tools/bl_convert.py index a4e406e..90a4f49 100644 --- a/Tools/model_tools/bl_convert.py +++ b/Tools/model_tools/bl_convert.py @@ -9,6 +9,7 @@ import numpy as np # blender --python 不会把脚本目录加入 sys.path,手动加入以复用 unity_assets(纯 stdlib) sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +from png_compress import compress_png, prepare_blender_png from unity_assets import safe_name AO_NAME_RE = re.compile(r"(ao|occlusion|ambient)", re.I) @@ -269,8 +270,10 @@ def _save_png(path, rgba): img.filepath_raw = path img.file_format = 'PNG' img.alpha_mode = 'CHANNEL_PACKED' + prepare_blender_png(100) img.save() bpy.data.images.remove(img) + compress_png(path) def _convert_material(mat, model_name, outdir, max_size, used_snames, src_dir): diff --git a/Tools/model_tools/model_bake.py b/Tools/model_tools/model_bake.py index bffb42f..70d4d85 100644 --- a/Tools/model_tools/model_bake.py +++ b/Tools/model_tools/model_bake.py @@ -8,6 +8,7 @@ import os from bl_bake import output_stem from bl_decimate import model_format from mt_run import HERE, find_blender, run_blender_script +from png_compress import compress_pngs def main(): @@ -38,6 +39,9 @@ def main(): [args.high, args.low, outdir, str(args.size), ray, str(args.samples)], blender_args=("-t", "1")) + compress_pngs( + os.path.join(outdir, fname) for fname in (s.get("outputs") or {}).values() + ) print("== %s(高 %d 面 / 低 %d 面,射线距离 %.4f)-> %s" % (s["stem"], s["high_tris"], s["low_tris"], s["ray_distance"], outdir)) for name, fname in s["outputs"].items(): diff --git a/Tools/model_tools/model_lowpoly_bake.py b/Tools/model_tools/model_lowpoly_bake.py index 1e62cba..714397f 100644 --- a/Tools/model_tools/model_lowpoly_bake.py +++ b/Tools/model_tools/model_lowpoly_bake.py @@ -28,6 +28,7 @@ if str(_HERE) not in sys.path: from bl_bake import output_stem # noqa: E402 from bl_decimate import model_format # noqa: E402 from mt_run import find_blender, run_blender_script # noqa: E402 +from png_compress import compress_pngs # noqa: E402 def _now_iso() -> str: @@ -211,6 +212,9 @@ def run_pipeline( ], blender_args=("-t", "1"), ) + compress_pngs( + str(bake_dir / fname) for fname in (bake.get("outputs") or {}).values() + ) xpbr_dir = None xpbr_summary = None diff --git a/Tools/model_tools/model_translator.py b/Tools/model_tools/model_translator.py index 636841d..b9a579e 100644 --- a/Tools/model_tools/model_translator.py +++ b/Tools/model_tools/model_translator.py @@ -8,6 +8,7 @@ import sys import unity_assets as ua from mt_run import HERE, find_blender, run_blender_script +from png_compress import compress_dir_pngs def write_unity_assets(outdir, summary, max_size): @@ -79,6 +80,7 @@ def translate_fbx(src, outdir, max_size=2048, blender=None): summary = run_blender_script( blender_exe, "bl_convert.py", [src, outdir, str(max_size)] ) + compress_dir_pngs(outdir, suffixes=("_base.png", "_mix.png")) unity = write_unity_assets(outdir, summary, max_size) return {**summary, "unity": unity} diff --git a/Tools/model_tools/png_compress.py b/Tools/model_tools/png_compress.py new file mode 100644 index 0000000..4194dd3 --- /dev/null +++ b/Tools/model_tools/png_compress.py @@ -0,0 +1,139 @@ +"""Lossless PNG size reduction for bake outputs. + +Blender's default PNG compression is low (~15/100). Final _base/_mix (and +bake maps) are rewritten with zlib level 9. Pillow `optimize=True` is used +when available (system Python); Blender's interpreter falls back to IDAT +recompress via stdlib only. Pixels are unchanged. +""" +from __future__ import annotations + +import os +import struct +import zlib +from typing import Dict, Iterable, List, Optional + +PNG_SIG = b"\x89PNG\r\n\x1a\n" + + +def prepare_blender_png(compression: int = 100) -> None: + """Blender Image.save() uses scene render PNG compression (0-100).""" + import bpy + + settings = bpy.context.scene.render.image_settings + settings.file_format = "PNG" + settings.color_depth = "8" + settings.compression = int(compression) + + +def compress_png(path: str, level: int = 9) -> Dict[str, int]: + """Rewrite `path` in place. Returns {before, after} byte sizes.""" + path = os.path.abspath(path) + before = os.path.getsize(path) + after = before + tmp = path + ".pngcompress.tmp" + try: + if _compress_with_pillow(path, tmp, level) or _compress_idat(path, tmp, level): + new_size = os.path.getsize(tmp) + if new_size < before: + os.replace(tmp, path) + after = new_size + elif os.path.isfile(tmp): + os.remove(tmp) + finally: + if os.path.isfile(tmp): + try: + os.remove(tmp) + except OSError: + pass + return {"before": before, "after": after} + + +def compress_pngs(paths: Iterable[str], level: int = 9) -> List[Dict[str, object]]: + reports = [] + for path in paths: + if not path or not os.path.isfile(path): + continue + if os.path.splitext(path)[1].lower() != ".png": + continue + sizes = compress_png(path, level=level) + reports.append({"path": os.path.abspath(path), **sizes}) + return reports + + +def compress_dir_pngs(directory: str, suffixes: Optional[Iterable[str]] = None) -> List[Dict[str, object]]: + """Compress PNGs in a directory. `suffixes` like ('_base.png', '_mix.png').""" + directory = os.path.abspath(directory) + names = sorted(os.listdir(directory)) if os.path.isdir(directory) else [] + suffix_tuple = tuple(suffixes) if suffixes else None + paths = [] + for name in names: + if not name.lower().endswith(".png"): + continue + if suffix_tuple and not name.endswith(suffix_tuple): + continue + paths.append(os.path.join(directory, name)) + return compress_pngs(paths) + + +def _compress_with_pillow(src: str, dst: str, level: int) -> bool: + try: + from PIL import Image + except ImportError: + return False + try: + with Image.open(src) as im: + im.load() + im.save(dst, format="PNG", optimize=True, compress_level=level) + except Exception: + return False + return os.path.isfile(dst) + + +def _write_chunk(buf: bytearray, ctype: bytes, data: bytes) -> None: + buf.extend(struct.pack(">I", len(data))) + buf.extend(ctype) + buf.extend(data) + buf.extend(struct.pack(">I", zlib.crc32(ctype + data) & 0xFFFFFFFF)) + + +def _compress_idat(src: str, dst: str, level: int) -> bool: + with open(src, "rb") as f: + data = f.read() + if len(data) < 8 or data[:8] != PNG_SIG: + return False + pos = 8 + before_idat: List[tuple] = [] + after_idat: List[tuple] = [] + idat_parts: List[bytes] = [] + seen_idat = False + while pos + 12 <= len(data): + length = struct.unpack(">I", data[pos : pos + 4])[0] + ctype = data[pos + 4 : pos + 8] + end = pos + 8 + length + if end + 4 > len(data): + return False + cdata = data[pos + 8 : end] + pos = end + 4 + if ctype == b"IDAT": + idat_parts.append(cdata) + seen_idat = True + continue + if seen_idat: + after_idat.append((ctype, cdata)) + else: + before_idat.append((ctype, cdata)) + if ctype == b"IEND": + break + if not idat_parts: + return False + raw = zlib.decompress(b"".join(idat_parts)) + packed = zlib.compress(raw, level) + out = bytearray(PNG_SIG) + for ctype, cdata in before_idat: + _write_chunk(out, ctype, cdata) + _write_chunk(out, b"IDAT", packed) + for ctype, cdata in after_idat: + _write_chunk(out, ctype, cdata) + with open(dst, "wb") as f: + f.write(out) + return True diff --git a/Tools/model_tools/tests/test_png_compress.py b/Tools/model_tools/tests/test_png_compress.py new file mode 100644 index 0000000..9a77243 --- /dev/null +++ b/Tools/model_tools/tests/test_png_compress.py @@ -0,0 +1,31 @@ +import os +import sys +import tempfile +import unittest + +sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +from png_compress import compress_png + + +class CompressPngTests(unittest.TestCase): + def test_pixels_unchanged_and_smaller(self): + from PIL import Image + + w = h = 64 + pixels = [(40, 80, 120, 255)] * (w * h) + with tempfile.TemporaryDirectory() as d: + path = os.path.join(d, "a.png") + im = Image.new("RGBA", (w, h)) + im.putdata(pixels) + im.save(path, format="PNG", compress_level=0, optimize=False) + before = os.path.getsize(path) + src_bytes = list(Image.open(path).getdata()) + sizes = compress_png(path) + after_im = Image.open(path) + self.assertEqual(list(after_im.getdata()), src_bytes) + self.assertLess(sizes["after"], before) + self.assertEqual(sizes["before"], before) + + +if __name__ == "__main__": + unittest.main()