diff --git a/.idea/AugmentWebviewStateStore.xml b/.idea/AugmentWebviewStateStore.xml new file mode 100644 index 00000000..a6f4d0a0 --- /dev/null +++ b/.idea/AugmentWebviewStateStore.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/RenderPipelineFile/config/daytime.yaml b/RenderPipelineFile/config/daytime.yaml index a07c27e0..31d28cd2 100644 --- a/RenderPipelineFile/config/daytime.yaml +++ b/RenderPipelineFile/config/daytime.yaml @@ -5,7 +5,7 @@ control_points: clouds: - cloud_brightness: [[[0.4558541267,0.9574780059],[0.2744727256,0.8944309678],[0.1938559693,0.5249266862],[0.8905932438,0.2375366569],[0.6429901728,0.9589492375],[0.7581600000,0.8914912023],[0.2226478119,0.7859268915],[0.8406909789,0.4897360704],[0.5451055662,0.9618768328],[0.9462571977,0.0000000000],[1.0000000000,0.0000000000],[0.3646833013,0.9472140762],[0.3186180422,0.9325513197],[0.1362763916,0.0000000000]]] + cloud_brightness: [[[0.4558541267,0.9574780059],[0.2744727256,0.8944309678],[0.1938559693,0.5249266862],[0.8905932438,0.2375366569],[0.6429901728,0.9589492375],[0.7581600000,0.8914912023],[0.2226478119,0.7859268915],[0.8406909789,0.4897360704],[0.5451055662,0.9618768328],[0.9462571977,0.0000000000],[1.0000000000,0.0000000000],[0.3646833013,0.9472140762],[0.3186180422,0.9325513197],[0.0823264879,0.0000000000]]] color_correction: camera_iso: [[[0.4438274549,0.2674094708]]] camera_shutter: [[[0.5211132438,0.0190100061]]] @@ -17,8 +17,8 @@ control_points: scattering: sun_intensity: [[[0.0000000000,0.0000000000],[0.0041666667,0.0000000000],[0.0083333333,0.0000000000],[0.0125000000,0.0000000000],[0.0166666667,0.0000000000],[0.0208333333,0.0000000000],[0.0250000000,0.0000000000],[0.0291666667,0.0000000000],[0.0333333333,0.0000000000],[0.0375000000,0.0000000000],[0.0416666667,0.0000000000],[0.0458333333,0.0000000000],[0.0500000000,0.0000000000],[0.0541666667,0.0000000000],[0.0583333333,0.0000000000],[0.0625000000,0.0000000000],[0.0666666667,0.0000000000],[0.0708333333,0.0000000000],[0.0750000000,0.0000000000],[0.0791666667,0.0000000000],[0.0833333333,0.0000000000],[0.0875000000,0.0000000000],[0.0916666667,0.0000000000],[0.0958333333,0.0000000000],[0.1000000000,0.0000000000],[0.1041666667,0.0000000000],[0.1083333333,0.0000000000],[0.1125000000,0.0000000000],[0.1166666667,0.0000000000],[0.1208333333,0.0000000000],[0.1250000000,0.0000000000],[0.1291666667,0.0000000000],[0.1333333333,0.0000000000],[0.1375000000,0.0000000000],[0.1416666667,0.0000000000],[0.1458333333,0.0000000000],[0.1500000000,0.0000000000],[0.1541666667,0.0000000000],[0.1583333333,0.0000028805],[0.1625000000,0.0003577724],[0.1666666667,0.0013331400],[0.1708333333,0.0029671803],[0.1750000000,0.0052963381],[0.1791666667,0.0083550556],[0.1833333333,0.0121755589],[0.1875000000,0.0167876159],[0.1916666667,0.0222183530],[0.1958333333,0.0284919947],[0.2000000000,0.0356297193],[0.2041666667,0.0436494349],[0.2083333333,0.0525656099],[0.2125000000,0.0623891610],[0.2166666667,0.0731272461],[0.2208333333,0.0847831708],[0.2250000000,0.0973563167],[0.2291666667,0.1108419698],[0.2333333333,0.1252313631],[0.2375000000,0.1405115250],[0.2416666667,0.1566653434],[0.2458333333,0.1736715009],[0.2500000000,0.1915046014],[0.2541666667,0.2101350464],[0.2583333333,0.2295292930],[0.2625000000,0.2496498145],[0.2666666667,0.2704552670],[0.2708333333,0.2919006662],[0.2750000000,0.3139375192],[0.2791666667,0.3365139497],[0.2833333333,0.3595750662],[0.2875000000,0.3830630359],[0.2916666667,0.4069173972],[0.2958333333,0.4310753462],[0.3000000000,0.4554720417],[0.3041666667,0.4800408236],[0.3083333333,0.5047136020],[0.3125000000,0.5294212108],[0.3166666667,0.5540936424],[0.3208333333,0.5786605298],[0.3250000000,0.6030514553],[0.3291666667,0.6271963182],[0.3333333333,0.6510256858],[0.3375000000,0.6744711982],[0.3416666667,0.6974659988],[0.3458333333,0.7199450163],[0.3500000000,0.7418453485],[0.3541666667,0.7631067095],[0.3583333333,0.7836717291],[0.3625000000,0.8034862953],[0.3666666667,0.8224999302],[0.3708333333,0.8406661079],[0.3750000000,0.8579425235],[0.3791666667,0.8742914270],[0.3833333333,0.8896799131],[0.3875000000,0.9040801386],[0.3916666667,0.9174695289],[0.3958333333,0.9298310650],[0.4000000000,0.9411533765],[0.4041666667,0.9514309312],[0.4083333333,0.9606641691],[0.4125000000,0.9688595571],[0.4166666667,0.9760296330],[0.4208333333,0.9821930708],[0.4250000000,0.9873746114],[0.4291666667,0.9916050060],[0.4333333333,0.9949209310],[0.4375000000,0.9973647924],[0.4416666667,0.9989845508],[0.4458333333,0.9998334497],[0.4500000000,0.9999696949],[0.4541666667,0.9994560801],[0.4583333333,0.9983595429],[0.4625000000,0.9967506613],[0.4666666667,0.9947030614],[0.4708333333,0.9922927758],[0.4750000000,0.9895975125],[0.4791666667,0.9866958610],[0.4833333333,0.9836664262],[0.4875000000,0.9805868867],[0.4916666667,0.9775330316],[0.4958333333,0.9745777179],[0.5000000000,0.9717898417],[0.5041666667,0.9692332877],[0.5083333333,0.9669658924],[0.5125000000,0.9650384806],[0.5166666667,0.9634939916],[0.5208333333,0.9623666659],[0.5250000000,0.9616814371],[0.5291666667,0.9614534423],[0.5333333333,0.9616877089],[0.5375000000,0.9623790807],[0.5416666667,0.9635123329],[0.5458333333,0.9650624244],[0.5500000000,0.9669949804],[0.5541666667,0.9692669864],[0.5583333333,0.9718275065],[0.5625000000,0.9746185969],[0.5666666667,0.9775762863],[0.5708333333,0.9806315864],[0.5750000000,0.9837115661],[0.5791666667,0.9867403433],[0.5833333333,0.9896401655],[0.5875000000,0.9923323562],[0.5916666667,0.9947382579],[0.5958333333,0.9967800977],[0.6000000000,0.9983817820],[0.6041666667,0.9994696263],[0.6083333333,0.9999730028],[0.6125000000,0.9998249266],[0.6166666667,0.9989625601],[0.6208333333,0.9973276624],[0.6250000000,0.9948669567],[0.6291666667,0.9915324664],[0.6333333333,0.9872817545],[0.6375000000,0.9820781426],[0.6416666667,0.9758908775],[0.6458333333,0.9686952146],[0.6500000000,0.9604725211],[0.6541666667,0.9512102537],[0.6583333333,0.9409019858],[0.6625000000,0.9295473441],[0.6666666667,0.9171518878],[0.6708333333,0.9037270619],[0.6750000000,0.8892899902],[0.6791666667,0.8738633008],[0.6833333333,0.8574749656],[0.6875000000,0.8401579787],[0.6916666667,0.8219502453],[0.6958333333,0.8028941798],[0.7000000000,0.7830364456],[0.7041666667,0.7624277344],[0.7083333333,0.7411222520],[0.7125000000,0.7191776044],[0.7166666667,0.6966542563],[0.7208333333,0.6736152714],[0.7250000000,0.6501259629],[0.7291666667,0.6262533880],[0.7333333333,0.6020661121],[0.7375000000,0.5776338043],[0.7416666667,0.5530267796],[0.7458333333,0.5283156992],[0.7500000000,0.5035711751],[0.7541666667,0.4788634341],[0.7583333333,0.4542618347],[0.7625000000,0.4298347613],[0.7666666667,0.4056490351],[0.7708333333,0.3817697830],[0.7750000000,0.3582600107],[0.7791666667,0.3351803495],[0.7833333333,0.3125888445],[0.7875000000,0.2905406366],[0.7916666667,0.2690876955],[0.7958333333,0.2482787388],[0.8000000000,0.2281588906],[0.8041666667,0.2087696425],[0.8083333333,0.1901486315],[0.8125000000,0.1723295359],[0.8166666667,0.1553419918],[0.8208333333,0.1392115328],[0.8250000000,0.1239595144],[0.8291666667,0.1096030703],[0.8333333333,0.0961551918],[0.8375000000,0.0836246599],[0.8416666667,0.0720161369],[0.8458333333,0.0613302273],[0.8500000000,0.0515635598],[0.8541666667,0.0427088803],[0.8583333333,0.0347551990],[0.8625000000,0.0276878920],[0.8666666667,0.0214889271],[0.8708333333,0.0161369711],[0.8750000000,0.0116076130],[0.8791666667,0.0078735477],[0.8833333333,0.0049047927],[0.8875000000,0.0026688977],[0.8916666667,0.0011311782],[0.8958333333,0.0002549473],[0.9000000000,0.0000000000],[0.9041666667,0.0000000000],[0.9083333333,0.0000000000],[0.9125000000,0.0000000000],[0.9166666667,0.0000000000],[0.9208333333,0.0000000000],[0.9250000000,0.0000000000],[0.9291666667,0.0000000000],[0.9333333333,0.0000000000],[0.9375000000,0.0000000000],[0.9416666667,0.0000000000],[0.9458333333,0.0000000000],[0.9500000000,0.0000000000],[0.9541666667,0.0000000000],[0.9583333333,0.0000000000],[0.9625000000,0.0000000000],[0.9666666667,0.0000000000],[0.9708333333,0.0000000000],[0.9750000000,0.0000000000],[0.9791666667,0.0000000000],[0.9833333333,0.0000000000],[0.9875000000,0.0000000000],[0.9916666667,0.0000000000],[0.9958333333,0.0000000000]]] sun_color: [[[0.4971900000,0.5763000000],[0.0433100000,0.8999700000],[0.8635787716,0.9130000000],[0.1785000000,0.8973600000],[0.8099800000,0.8651100000],[0.2360800000,0.7712700000],[0.6583432177,0.8485126184],[0.1266806142,0.9648102053],[0.9558541267,0.9090909091],[0.5568400771,0.7353760446]],[[0.5001318426,0.5160300000],[0.0572700000,0.6541600000],[0.2395000000,0.5976800000],[0.8104600000,0.6009000000],[0.6967400000,0.5483900000]],[[0.0862400000,0.4257800000],[0.4955600000,0.4033000000],[0.8234200000,0.4340200000]]] - sun_azimuth: [[[0.5057803468,0.7896935933]]] - sun_altitude: [[[0.5115606936,0.5355153203]]] + sun_azimuth: [[[0.4922928711,0.7103064067]]] + sun_altitude: [[[0.5077071291,0.7277158774]]] extinction: [[[0.4913294798,0.6378830084]]] volumetrics: fog_ramp_size: [[[0.5510597303,0.7409470752]]] diff --git a/RenderPipelineFile/config/pipeline.yaml b/RenderPipelineFile/config/pipeline.yaml index 21f3e201..d1ac6e71 100644 --- a/RenderPipelineFile/config/pipeline.yaml +++ b/RenderPipelineFile/config/pipeline.yaml @@ -8,12 +8,12 @@ pipeline: # it will also disable the hotkeys, and give a small performance boost. # Most likely you also don't want to show it in your own game, so set # it to false in that case. - display_debugger: true + display_debugger: False # Affects which debugging information is displayed. If this is set to false, # only frame time is displayed, otherwise much more information is visible. # Has no effect when display_debugger is set to false. - advanced_debugging_info: true + advanced_debugging_info: False # Whether to use the GL_R11F_G11F_B10F texture format to save memory # and bandwidth. Usually you want to enable this, however it can diff --git a/RenderPipelineFile/effects/debug_metallic.yaml b/RenderPipelineFile/effects/debug_metallic.yaml new file mode 100644 index 00000000..678bd54d --- /dev/null +++ b/RenderPipelineFile/effects/debug_metallic.yaml @@ -0,0 +1,35 @@ +# Debug metallic texture effect +# This effect visualizes metallic texture directly for debugging + +fragment: + defines: | + #define DEBUG_METALLIC_TEXTURE 1 + + inout: | + uniform sampler2D p3d_Texture5; // Metallic texture + + material: | + // Debug: Show metallic texture directly + #if DEBUG_METALLIC_TEXTURE + // Sample metallic from texture + float sampled_metallic = texture(p3d_Texture5, texcoord).x; + + // For debugging: show texture value as colored visualization + // Blue tint for non-metallic, yellow tint for metallic + vec3 debug_color = mix(vec3(0.2, 0.2, 1.0), vec3(1.0, 1.0, 0.2), sampled_metallic); + + // Apply to material + m.basecolor = debug_color; // Show texture as color for debugging + m.roughness = 0.5; // Fixed roughness for clear visualization + m.metallic = sampled_metallic; // Also apply to metallic + m.specular_ior = 1.5; + m.shading_model_param0 = 0.0; + + #else + // Fallback + m.basecolor = mInput.color; + m.roughness = mInput.roughness; + m.metallic = mInput.metallic; + m.specular_ior = mInput.specular_ior; + m.shading_model_param0 = mInput.arbitrary0; + #endif diff --git a/RenderPipelineFile/effects/debug_roughness.yaml b/RenderPipelineFile/effects/debug_roughness.yaml new file mode 100644 index 00000000..9cec23f8 --- /dev/null +++ b/RenderPipelineFile/effects/debug_roughness.yaml @@ -0,0 +1,35 @@ +# Debug roughness texture effect +# This effect visualizes roughness texture directly for debugging + +fragment: + defines: | + #define DEBUG_ROUGHNESS_TEXTURE 1 + + inout: | + uniform sampler2D p3d_Texture3; // Roughness texture + + material: | + // Debug: Show roughness texture directly + #if DEBUG_ROUGHNESS_TEXTURE + // Sample roughness from texture + float sampled_roughness = texture(p3d_Texture3, texcoord).x; + + // For debugging: show texture value as grayscale color + // This helps verify the texture is being read correctly + vec3 debug_color = vec3(sampled_roughness); + + // Apply to material + m.basecolor = debug_color; // Show texture as color for debugging + m.roughness = sampled_roughness; // Also apply to roughness + m.metallic = 0.0; // Keep metallic low for clear visualization + m.specular_ior = 1.5; + m.shading_model_param0 = 0.0; + + #else + // Fallback + m.basecolor = mInput.color; + m.roughness = mInput.roughness; + m.metallic = mInput.metallic; + m.specular_ior = mInput.specular_ior; + m.shading_model_param0 = mInput.arbitrary0; + #endif diff --git a/RenderPipelineFile/effects/metallic_only.yaml b/RenderPipelineFile/effects/metallic_only.yaml new file mode 100644 index 00000000..2c3cb8d6 --- /dev/null +++ b/RenderPipelineFile/effects/metallic_only.yaml @@ -0,0 +1,39 @@ +# Metallic-only PBR effect +# This effect specifically handles metallic textures correctly +# Ensures metallic texture is not confused with diffuse texture + +fragment: + defines: | + #define USE_METALLIC_TEXTURE_ONLY 1 + #define DONT_FETCH_DEFAULT_TEXTURES 0 + + inout: | + uniform sampler2D p3d_Texture5; // Metallic texture only + + material: | + // Only handle metallic texture, ignore others to avoid confusion + #if USE_METALLIC_TEXTURE_ONLY + // Sample metallic from p3d_Texture5 + float sampled_metallic = texture(p3d_Texture5, texcoord).x; + + // Direct control: texture value directly controls metallic + // This gives Blender-like behavior where texture has full control + m.metallic = sampled_metallic; + + // Clamp to valid range + m.metallic = clamp(m.metallic, 0.0, 1.0); + + // Keep other properties from material (no texture interference) + m.basecolor = mInput.color; // Use material color, not texture + m.roughness = mInput.roughness; + m.specular_ior = mInput.specular_ior; + m.shading_model_param0 = mInput.arbitrary0; + + #else + // Fallback to material values only + m.basecolor = mInput.color; + m.roughness = mInput.roughness; + m.metallic = mInput.metallic; + m.specular_ior = mInput.specular_ior; + m.shading_model_param0 = mInput.arbitrary0; + #endif diff --git a/RenderPipelineFile/effects/pbr_additive_metallic.yaml b/RenderPipelineFile/effects/pbr_additive_metallic.yaml new file mode 100644 index 00000000..b84bcf3c --- /dev/null +++ b/RenderPipelineFile/effects/pbr_additive_metallic.yaml @@ -0,0 +1,29 @@ +# PBR effect with additive metallic texture control +# This effect adds metallic texture values to material metallic values +# Final metallic = material_metallic + texture_value (clamped to 0-1) + +fragment: + defines: | + #define USE_ADDITIVE_METALLIC_TEXTURE 1 + + inout: | + uniform sampler2D p3d_Texture5; // Metallic texture (additive control) + + material: | + // Additive metallic texture control + #if USE_ADDITIVE_METALLIC_TEXTURE + // Sample metallic value from texture + float sampled_metallic = texture(p3d_Texture5, texcoord).x; + + // Add texture value to material metallic value + // This allows enhancing existing metallic areas + m.metallic = clamp(mInput.metallic + sampled_metallic, 0.0, 1.0); + + // Debug: This mode is useful for: + // - Adding metallic details to non-metallic materials + // - Enhancing existing metallic areas + // - Creating metallic highlights on top of base material + #else + // Fallback to material metallic value + m.metallic = mInput.metallic; + #endif diff --git a/RenderPipelineFile/effects/pbr_direct_metallic.yaml b/RenderPipelineFile/effects/pbr_direct_metallic.yaml new file mode 100644 index 00000000..80f0b205 --- /dev/null +++ b/RenderPipelineFile/effects/pbr_direct_metallic.yaml @@ -0,0 +1,29 @@ +# PBR effect with direct metallic texture control +# This effect allows metallic textures to directly control metallic values +# instead of multiplying with material metallic value + +fragment: + defines: | + #define USE_DIRECT_METALLIC_TEXTURE 1 + + inout: | + uniform sampler2D p3d_Texture5; // Metallic texture (direct control) + + material: | + // Direct metallic texture control + #if USE_DIRECT_METALLIC_TEXTURE + // Sample metallic value directly from texture + float sampled_metallic = texture(p3d_Texture5, texcoord).x; + + // Use texture value directly instead of multiplying + // This allows the texture to have full control over metallic values + m.metallic = sampled_metallic; + + // Debug: Ensure we're using the texture value + // White areas = 1.0 (fully metallic) + // Gray areas = 0.5 (semi-metallic) + // Black areas = 0.0 (non-metallic) + #else + // Fallback to material metallic value + m.metallic = mInput.metallic; + #endif diff --git a/RenderPipelineFile/effects/pbr_direct_roughness.yaml b/RenderPipelineFile/effects/pbr_direct_roughness.yaml new file mode 100644 index 00000000..d6bb2ae4 --- /dev/null +++ b/RenderPipelineFile/effects/pbr_direct_roughness.yaml @@ -0,0 +1,38 @@ +# PBR effect with direct roughness texture control +# This effect allows roughness textures to directly control roughness values +# instead of multiplying with material roughness value + +fragment: + defines: | + #define USE_DIRECT_ROUGHNESS_TEXTURE 1 + + inout: | + uniform sampler2D p3d_Texture3; // Roughness texture (direct control) + + material: | + // Direct roughness texture control + #if USE_DIRECT_ROUGHNESS_TEXTURE + // Sample roughness value directly from texture + float sampled_roughness = texture(p3d_Texture3, texcoord).x; + + // Use texture value directly instead of multiplying + // This allows the texture to have full control over roughness values + m.roughness = sampled_roughness; + + // Ensure minimum roughness to avoid rendering issues + m.roughness = max(m.roughness, 0.01); + + // Debug: Ensure we're using the texture value + // White areas = 1.0 (fully rough) + // Gray areas = 0.5 (semi-rough) + // Black areas = 0.01 (smooth, but not zero to avoid issues) + #else + // Fallback to material roughness value + m.roughness = mInput.roughness; + #endif + + // Keep all other properties unchanged for stability + m.basecolor = mInput.color; + m.metallic = mInput.metallic; + m.specular_ior = mInput.specular_ior; + m.shading_model_param0 = mInput.arbitrary0; diff --git a/RenderPipelineFile/effects/pbr_extended.yaml b/RenderPipelineFile/effects/pbr_extended.yaml new file mode 100644 index 00000000..e6754d09 --- /dev/null +++ b/RenderPipelineFile/effects/pbr_extended.yaml @@ -0,0 +1,51 @@ +# Extended PBR effect with support for additional texture types +# This effect supports metallic, emission, AO, detail, and gloss textures + +fragment: + defines: | + #define USE_EXTENDED_TEXTURES 1 + + inout: | + uniform sampler2D p3d_Texture5; // Metallic texture + uniform sampler2D p3d_Texture6; // Emission texture + uniform sampler2D p3d_Texture7; // AO texture + uniform sampler2D p3d_Texture8; // Alpha texture + uniform sampler2D p3d_Texture9; // Detail texture + uniform sampler2D p3d_Texture10; // Gloss texture + + material: | + #if USE_EXTENDED_TEXTURES + + // Metallic texture (p3d_Texture5) + float sampled_metallic = texture(p3d_Texture5, texcoord).x; + m.metallic = mInput.metallic * sampled_metallic; + + // Emission texture (p3d_Texture6) + vec3 sampled_emission = texture(p3d_Texture6, texcoord).xyz; + if (mInput.shading_model == SHADING_MODEL_EMISSIVE) { + m.basecolor += sampled_emission * 2.0; // Boost emission intensity + } + + // AO texture (p3d_Texture7) - multiply with base color + float sampled_ao = texture(p3d_Texture7, texcoord).x; + m.basecolor *= sampled_ao; + + // Alpha texture (p3d_Texture8) - for transparency + float sampled_alpha = texture(p3d_Texture8, texcoord).x; + if (mInput.shading_model == SHADING_MODEL_TRANSPARENT) { + // Apply alpha testing + if (sampled_alpha < 0.5) discard; + } + + // Detail texture (p3d_Texture9) - blend with base color + vec3 sampled_detail = texture(p3d_Texture9, texcoord * 4.0).xyz; // Tiled detail + m.basecolor = mix(m.basecolor, m.basecolor * sampled_detail, 0.5); + + // Gloss texture (p3d_Texture10) - affects roughness + float sampled_gloss = texture(p3d_Texture10, texcoord).x; + m.roughness = m.roughness * (1.0 - sampled_gloss); // Gloss is inverse of roughness + + #else + // Standard behavior when extended textures are not used + m.metallic = mInput.metallic; + #endif diff --git a/RenderPipelineFile/effects/pbr_with_emission.yaml b/RenderPipelineFile/effects/pbr_with_emission.yaml new file mode 100644 index 00000000..b566d8e8 --- /dev/null +++ b/RenderPipelineFile/effects/pbr_with_emission.yaml @@ -0,0 +1,19 @@ +# PBR effect with emission texture support +# This effect extends the default PBR pipeline to support emission textures + +fragment: + defines: | + #define USE_EMISSION_TEXTURE 1 + + inout: | + uniform sampler2D p3d_Texture6; // Emission texture + + material: | + // Fetch emission value from texture if available + #if USE_EMISSION_TEXTURE + vec3 sampled_emission = texture(p3d_Texture6, texcoord).xyz; + // For emissive materials, add the texture emission to the base color + if (mInput.shading_model == SHADING_MODEL_EMISSIVE) { + m.basecolor += sampled_emission * 2.0; // Boost emission intensity + } + #endif diff --git a/RenderPipelineFile/effects/pbr_with_metallic.yaml b/RenderPipelineFile/effects/pbr_with_metallic.yaml new file mode 100644 index 00000000..d8e12679 --- /dev/null +++ b/RenderPipelineFile/effects/pbr_with_metallic.yaml @@ -0,0 +1,45 @@ +# PBR effect with metallic texture support +# This effect extends the default PBR pipeline to support metallic textures +# Provides both multiplicative and direct control modes + +fragment: + defines: | + #define USE_METALLIC_TEXTURE 1 + #define METALLIC_CONTROL_MODE 0 // 0=multiply, 1=direct, 2=additive + + inout: | + uniform sampler2D p3d_Texture5; // Metallic texture + + material: | + // Complete material processing with metallic texture support + #if USE_METALLIC_TEXTURE + // Sample metallic texture + float sampled_metallic = texture(p3d_Texture5, texcoord).x; + + // Apply metallic texture based on control mode + #if METALLIC_CONTROL_MODE == 0 + // Multiplicative mode (original behavior) + m.metallic = mInput.metallic * sampled_metallic; + #elif METALLIC_CONTROL_MODE == 1 + // Direct control mode + m.metallic = sampled_metallic; + #elif METALLIC_CONTROL_MODE == 2 + // Additive mode + m.metallic = clamp(mInput.metallic + sampled_metallic, 0.0, 1.0); + #else + // Fallback to multiplicative + m.metallic = mInput.metallic * sampled_metallic; + #endif + #else + m.metallic = mInput.metallic; + #endif + + // Process other material properties normally + m.basecolor = mInput.color * sampled_diffuse.xyz; + m.specular_ior = blend_ior(mInput.specular_ior, sampled_ior); + m.roughness = mInput.roughness * sampled_roughness; + m.shading_model_param0 = mInput.arbitrary0; + + // Ensure valid ranges + m.roughness = max(m.roughness, 0.01); + m.metallic = clamp(m.metallic, 0.0, 1.0); diff --git a/RenderPipelineFile/effects/pbr_with_normal.yaml b/RenderPipelineFile/effects/pbr_with_normal.yaml new file mode 100644 index 00000000..f8e385be --- /dev/null +++ b/RenderPipelineFile/effects/pbr_with_normal.yaml @@ -0,0 +1,31 @@ +# PBR effect with normal mapping support +# This effect ensures proper material color handling when only normal maps are applied + +fragment: + defines: | + #define USE_NORMAL_MAPPING_ONLY 1 + + material: | + // Handle normal mapping without requiring diffuse texture + #if USE_NORMAL_MAPPING_ONLY + // Use material color directly, don't multiply with sampled_diffuse + // This prevents the black color issue when no diffuse texture is present + m.basecolor = mInput.color; + + // Handle other textures normally if they exist + m.specular_ior = blend_ior(mInput.specular_ior, sampled_ior); + m.roughness = mInput.roughness * sampled_roughness; + m.metallic = mInput.metallic; + + // Ensure minimum roughness + m.roughness = max(m.roughness, 0.01); + + #else + // Standard material processing + m.basecolor = mInput.color * sampled_diffuse.xyz; + m.specular_ior = blend_ior(mInput.specular_ior, sampled_ior); + m.roughness = mInput.roughness * sampled_roughness; + m.metallic = mInput.metallic; + #endif + + m.shading_model_param0 = mInput.arbitrary0; diff --git a/RenderPipelineFile/effects/pbr_with_roughness.yaml b/RenderPipelineFile/effects/pbr_with_roughness.yaml new file mode 100644 index 00000000..0b620cb7 --- /dev/null +++ b/RenderPipelineFile/effects/pbr_with_roughness.yaml @@ -0,0 +1,33 @@ +# Stable PBR effect with roughness texture support +# Simplified version to avoid rendering issues and flickering + +fragment: + defines: | + #define USE_STABLE_ROUGHNESS_TEXTURE 1 + + inout: | + uniform sampler2D p3d_Texture3; // Roughness texture only + + material: | + // Simple and stable roughness texture handling + #if USE_STABLE_ROUGHNESS_TEXTURE + // Sample roughness from texture + float sampled_roughness = texture(p3d_Texture3, texcoord).x; + + // Use simple multiplication - stable and predictable + // This ensures the texture effect is always visible + m.roughness = mInput.roughness * sampled_roughness; + + // Ensure minimum roughness to avoid rendering issues + m.roughness = max(m.roughness, 0.01); + + #else + // Fallback to material roughness + m.roughness = mInput.roughness; + #endif + + // Keep all other properties unchanged for stability + m.basecolor = mInput.color; + m.metallic = mInput.metallic; + m.specular_ior = mInput.specular_ior; + m.shading_model_param0 = mInput.arbitrary0; diff --git a/RenderPipelineFile/effects/pbr_with_textures.yaml b/RenderPipelineFile/effects/pbr_with_textures.yaml new file mode 100644 index 00000000..13749f12 --- /dev/null +++ b/RenderPipelineFile/effects/pbr_with_textures.yaml @@ -0,0 +1,37 @@ +# Enhanced PBR effect with metallic texture support +# This effect extends the default PBR to support metallic textures +# Avoids redeclaring textures that are already in the base template + +fragment: + defines: | + #define USE_METALLIC_TEXTURE 1 + + inout: | + uniform sampler2D p3d_Texture5; // Metallic texture (not in default template) + + material: | + // Enhanced material with metallic texture support + #if USE_METALLIC_TEXTURE + // Sample metallic texture + float sampled_metallic = texture(p3d_Texture5, texcoord).x; + + // Apply all material properties + // Use the sampled values from the base template for other textures + m.basecolor = mInput.color * sampled_diffuse.xyz; + m.specular_ior = blend_ior(mInput.specular_ior, sampled_ior); + m.roughness = mInput.roughness * sampled_roughness; + m.metallic = mInput.metallic * sampled_metallic; // Now with metallic texture support! + + // Ensure valid ranges + m.roughness = max(m.roughness, 0.01); + m.metallic = clamp(m.metallic, 0.0, 1.0); + + #else + // Fallback to standard material processing + m.basecolor = mInput.color * sampled_diffuse.xyz; + m.specular_ior = blend_ior(mInput.specular_ior, sampled_ior); + m.roughness = mInput.roughness * sampled_roughness; + m.metallic = mInput.metallic; // No metallic texture + #endif + + m.shading_model_param0 = mInput.arbitrary0; diff --git a/RenderPipelineFile/effects/roughness_only.yaml b/RenderPipelineFile/effects/roughness_only.yaml new file mode 100644 index 00000000..a8e76f52 --- /dev/null +++ b/RenderPipelineFile/effects/roughness_only.yaml @@ -0,0 +1,39 @@ +# Roughness-only PBR effect +# This effect specifically handles roughness textures correctly +# Ensures roughness texture is not confused with diffuse texture + +fragment: + defines: | + #define USE_ROUGHNESS_TEXTURE_ONLY 1 + #define DONT_FETCH_DEFAULT_TEXTURES 0 + + inout: | + uniform sampler2D p3d_Texture3; // Roughness texture only + + material: | + // Only handle roughness texture, ignore others to avoid confusion + #if USE_ROUGHNESS_TEXTURE_ONLY + // Sample roughness from p3d_Texture3 + float sampled_roughness = texture(p3d_Texture3, texcoord).x; + + // Apply roughness: material_roughness * texture_value + // This gives Blender-like behavior + m.roughness = mInput.roughness * sampled_roughness; + + // Ensure minimum roughness to avoid rendering issues + m.roughness = max(m.roughness, 0.01); + + // Keep other properties from material (no texture interference) + m.basecolor = mInput.color; // Use material color, not texture + m.metallic = mInput.metallic; + m.specular_ior = mInput.specular_ior; + m.shading_model_param0 = mInput.arbitrary0; + + #else + // Fallback to material values only + m.basecolor = mInput.color; + m.roughness = mInput.roughness; + m.metallic = mInput.metallic; + m.specular_ior = mInput.specular_ior; + m.shading_model_param0 = mInput.arbitrary0; + #endif diff --git a/RenderPipelineFile/samples/06-Car/main.py b/RenderPipelineFile/samples/06-Car/main.py index 1720104b..dcee5499 100644 --- a/RenderPipelineFile/samples/06-Car/main.py +++ b/RenderPipelineFile/samples/06-Car/main.py @@ -52,6 +52,11 @@ class MainApp(ShowBase): # Load the scene model = loader.loadModel("scene/scene.bam") # model = loader.loadModel("scene2/Scene.bam") + model_0 = self.loader.loadModel("/home/tiger/下载/Benci/source/s65/s65/s65.fbx") + model_0.reparentTo(self.render) + model_0.setScale(0.25) + model_0.setPos(-8, 42, 0) + model_0.setHpr(0, 90, 0) model.reparent_to(render) self.render_pipeline.prepare_scene(model) diff --git a/RenderPipelineFile/toolkit/material_editor/main.py b/RenderPipelineFile/toolkit/material_editor/main.py index df5f550f..dd383451 100644 --- a/RenderPipelineFile/toolkit/material_editor/main.py +++ b/RenderPipelineFile/toolkit/material_editor/main.py @@ -170,9 +170,9 @@ class MaterialEditor(QMainWindow, Ui_MainWindow): # Basecolor values = self.basecolor_to_tuple(self.material) - self.basecolor_1.setValue(values[0] * 100.0) - self.basecolor_2.setValue(values[1] * 100.0) - self.basecolor_3.setValue(values[2] * 100.0) + self.basecolor_1.setValue(int(values[0] * 100.0)) + self.basecolor_2.setValue(int(values[1] * 100.0)) + self.basecolor_3.setValue(int(values[2] * 100.0)) # Shading model self.cb_shading_model.setCurrentIndex(self.material.shading_model) @@ -184,7 +184,7 @@ class MaterialEditor(QMainWindow, Ui_MainWindow): # Rest of sliders for slider, lbl, start, end, prop in self.sliders: val = getattr(self.material, prop) - slider.setValue((val - start) / (end - start) * 100.0) + slider.setValue(int((val - start) / (end - start) * 100.0)) self.in_update = False self.update_ui() diff --git a/core/tool_manager.py b/core/tool_manager.py index a7374425..bcee4c8e 100644 --- a/core/tool_manager.py +++ b/core/tool_manager.py @@ -14,7 +14,24 @@ class ToolManager: print(f"当前工具: {tool}") print(f"选中节点: {self.world.selection.selectedNode.getName() if self.world.selection.selectedNode else '无'}") - # 坐标轴现在始终跟随选中状态,不再依赖工具类型 + # 根据工具类型启用对应的方法 + if tool == "选择": + print(f"当前工具为:{tool}") + #self._enableSelectionTool() + elif tool == "移动": + print(f"当前工具为:{tool}") + #self._enableMoveTool() + elif tool == "旋转": + print(f"当前工具为:{tool}") + #self._enableRotateTool() + elif tool == "缩放": + print(f"当前工具为:{tool}") + #self._enableScaleTool() + elif tool == "光照编辑": + print(f"当前工具为:{tool}") + self.launch_day_time_editor() + + # 坐标轴现在始终跟随选中状态,不再依赖工具类型 def getCurrentTool(self): """获取当前工具""" @@ -38,9 +55,15 @@ class ToolManager: def isDayTimeEditorTool(self): """光照""" - return self.currentTool=="编辑光照" + return self.currentTool=="光照编辑" def launch_day_time_editor(self): + + # 检查是否已经启动 + if hasattr(self, '_day_time_editor_process') and self._day_time_editor_process: + if self._day_time_editor_process.poll() is None: # 进程仍在运行 + print("Day Time Editor 已经在运行") + return True import subprocess import os import sys @@ -57,10 +80,8 @@ class ToolManager: print("错误文件不存在") return False - subprocess.Popen([sys.executable,editor_path]) - print("day time editor启动") - - self.setCurrentTool("光照编辑") + self._day_time_editor_process = subprocess.Popen([sys.executable, editor_path]) + print("Day Time Editor 已启动") return True except Exception as e: print(f"启动 time editor失败") diff --git a/core/world.py b/core/world.py index 2b4f798f..8e708bd8 100644 --- a/core/world.py +++ b/core/world.py @@ -1,3 +1,4 @@ + import math import warnings warnings.filterwarnings("ignore", category=DeprecationWarning) @@ -35,33 +36,37 @@ class CoreWorld(Panda3DWorld): self._loadFont() #self.start_day_night_cycle(duration_seconds=300.0) - self.accept("1", lambda: self.set_daytime("4:00")) # 清晨 - self.accept("2", lambda: self.set_daytime("6:00")) # 中午 - self.accept("3", lambda: self.set_daytime("8:00")) # 傍晚 - self.accept("4", lambda: self.set_daytime("10:00")) # 深夜 - self.accept("5", lambda: self.set_daytime("12:00")) # 深夜 - self.accept("6", lambda: self.set_daytime("14:00")) # 深夜 - self.accept("7", lambda: self.set_daytime("16:00")) # 深夜 - self.accept("8", lambda: self.set_daytime("18:00")) # 深夜 - self.accept("9", lambda: self.set_daytime("20:00")) # 深夜 - self.accept("0", lambda: self.set_daytime("22:00")) # 深夜 - - self.launch_day_time_editor() - + # self.accept("1", lambda: self.set_daytime("4:00")) # 清晨 + # self.accept("2", lambda: self.set_daytime("6:00")) # 中午 + # self.accept("3", lambda: self.set_daytime("8:00")) # 傍晚 + # self.accept("4", lambda: self.set_daytime("10:00")) # 深夜 + # self.accept("5", lambda: self.set_daytime("12:00")) # 深夜 + # self.accept("6", lambda: self.set_daytime("14:00")) # 深夜 + # self.accept("7", lambda: self.set_daytime("16:00")) # 深夜 + # self.accept("8", lambda: self.set_daytime("18:00")) # 深夜 + # self.accept("9", lambda: self.set_daytime("20:00")) # 深夜 + # self.accept("0", lambda: self.set_daytime("22:00")) # 深夜 + # #self.createDirectionalLight() + #self._setYCModel() + + # 创建示例材质 + #self.load_test_models_with_materials() + + # 设置材质编辑器网络通信 + #self.setup_material_editor_network() + + # 启动材质编辑器 + #self.launch_material_editor() + print("✓ 核心世界初始化完成") - def launch_day_time_editor(self): - """启动day time editor 作为独立进程""" - import subprocess - import os - import sys - - base_path = self.render_pipeline.mount_mgr.base_path - - editor_path = os.path.join(base_path,"文档/EG/RenderPipelineFile/toolkit/day_time_editor/main.py") - subprocess.Popen([sys.executable,editor_path]) - print("day time editor 已启动") + def _setYCModel(self): + model = self.loader.loadModel("/home/tiger/文档/Tzjyc_GLTF/tzjyc.gltf") + model.reparentTo(self.render) + model.setScale(0.25) + model.setPos(-8, 42, 0) + model.setHpr(0, 90, 0) def _setupCamera(self): """设置相机位置和朝向""" @@ -102,30 +107,38 @@ class CoreWorld(Panda3DWorld): self.ground.setZ(-0.1) self.ground.setColor(0.8, 0.8, 0.8, 1) - - + # 创建支持贴图的材质 mat = Material() - color = LColor(1, 1, 1, 1) + mat.setName("GroundMaterial") # 设置材质名称,便于材质编辑器识别 + color = LColor(0.7, 0.7, 0.7, 1) # 稍微暗一点的灰色 mat.set_base_color(color) - mat.set_roughness(0) - mat.set_metallic(0.8) - #mat.set_normal("/home/tiger/下载/OIP.jpeg") + mat.set_roughness(0.5) # 设置合适的初始粗糙度 + mat.set_metallic(0.1) # 设置较低的初始金属性 self.ground.set_material(mat) - # self.render_pipeline.set_effect(self.ground, "RenderPipelineFile/effects/material_blend4.yaml", { - # "parallax_mapping": False, # Not supported - # "alpha_testing": False, - # "normal_mapping": False, # The effect does its own normal mapping - # }, 100) - # - # self.ground.set_shader_input("detail_scale_factor", 4.0) - # self.ground.set_shader_input("material_0_pow", 10.0) - # self.ground.set_shader_input("material_0_add", 0.5) - # self.ground.set_shader_input("material_1_pow", 10.0) - # self.ground.set_shader_input("material_1_add", 0.5) - # self.ground.set_shader_input("material_2_pow", 10.0) - # self.ground.set_shader_input("material_2_add", 0.5) - print("✓ 地板创建完成") + # 应用默认PBR效果,确保支持贴图 + try: + if hasattr(self, 'render_pipeline') and self.render_pipeline: + self.render_pipeline.set_effect( + self.ground, + "effects/default.yaml", + { + "normal_mapping": True, + "render_gbuffer": True, + "alpha_testing": False, + "parallax_mapping": False, + "render_shadow": True, + "render_envmap": True + }, + 50 + ) + print("✓ 地板PBR效果已应用") + else: + print("⚠️ RenderPipeline未初始化,地板将使用基础渲染") + except Exception as e: + print(f"⚠️ 地板PBR效果应用失败: {e}") + + print("✓ 地板创建完成(支持材质贴图)") @@ -417,21 +430,248 @@ class CoreWorld(Panda3DWorld): return task.done def launch_day_time_editor(self): - """启动day time editor 作为独立进程""" + + # 检查是否已经启动 + if hasattr(self, '_day_time_editor_process') and self._day_time_editor_process: + if self._day_time_editor_process.poll() is None: # 进程仍在运行 + print("Day Time Editor 已经在运行") + return True import subprocess import os import sys - base_path = self.render_pipeline.mount_mgr.base_path + try: + if not hasattr(self.world,'render_pipeline') or not self.world.render_pipeline: + print("错误:renderpipeline未初始化") + return False - editor_path = os.path.join(base_path,"toolkit/day_time_editor/main.py") - subprocess.Popen([sys.executable,editor_path]) - print("day time editor 已启动") + base_path = self.world.render_pipeline.mount_mgr.base_path + editor_path = os.path.join(base_path,"toolkit/day_time_editor/main.py") + if not os.path.exists(editor_path): + print("错误文件不存在") + return False + self._day_time_editor_process = subprocess.Popen([sys.executable, editor_path]) + print("Day Time Editor 已启动") + return True + except Exception as e: + print(f"启动 time editor失败") + def setup_material_editor_network(self): + """设置材质编辑器网络通信""" + from RenderPipelineFile.rpcore.util.network_communication import NetworkCommunication + def handle_material_requests(message): + """处理材质编辑器的网络请求""" + try: + print(f"收到材质编辑器请求: {message}") + parts = message.strip().split() + if not parts: + return + command = parts[0] + if command == "dump_materials": + # 处理导出材质列表请求 + path = parts[1] if len(parts) > 1 else "" + if path: + self.export_materials_to_file(path) + elif command.startswith("update_material"): + # 处理更新材质请求 + data = message[len("update_material "):].strip() + self.update_material_from_editor(data.split()) + except Exception as e: + print(f"处理材质编辑器请求失败: {e}") + # 注册网络消息处理器 + try: + NetworkCommunication.listen_threaded( + NetworkCommunication.MATERIAL_PORT, + handle_material_requests + ) + print("✓ 材质编辑器网络通信已设置") + except Exception as e: + print(f"设置材质编辑器网络通信失败: {e}") + + def export_materials_to_file(self, path): + """导出材质列表到文件""" + try: + print(f"导出材质列表到: {path}") + materials = [] + + # 收集所有材质 + def collect_materials(node): + if node.hasMaterial(): + material = node.getMaterial() + if material: + materials.append(material) + + for child in node.getChildren(): + collect_materials(child) + + collect_materials(self.render) + + # 写入文件 + with open(path, "w") as f: + for i, material in enumerate(materials): + name = f"{i}-{material.getName() or 'unnamed'}" + + # 获取材质属性,使用默认值如果不存在 + base_color = material.getBaseColor() if hasattr(material, 'getBaseColor') else Vec4(0.6, 0.6, 0.6, 1.0) + roughness = material.getRoughness() if hasattr(material, 'getRoughness') else 0.5 + metallic = material.getMetallic() if hasattr(material, 'getMetallic') else 0.0 + + # 写入材质数据 + f.write(("{} " * 11).format( + name, + base_color.x, + base_color.y, + base_color.z, + roughness, + 0.5, # refractive_index + metallic, + 0, # shading_model + 1.0, # normal_strength + 0.0, # param1 + 0.0 # param2 + ) + "\n") + + print(f"✓ 成功导出 {len(materials)} 个材质到 {path}") + + except Exception as e: + print(f"导出材质列表失败: {e}") + + def update_material_from_editor(self, data): + """从编辑器更新材质""" + try: + if len(data) < 11: + print(f"材质数据不完整: {data}") + return + + name_parts = data[0].split("-") + if len(name_parts) < 2: + print(f"材质名称格式错误: {data[0]}") + return + + index = int(name_parts[0]) + name = "-".join(name_parts[1:]) + + # 收集所有材质 + materials = [] + def collect_materials(node): + if node.hasMaterial(): + material = node.getMaterial() + if material: + materials.append(material) + + for child in node.getChildren(): + collect_materials(child) + + collect_materials(self.render) + + # 查找匹配的材质 + if index < len(materials): + material = materials[index] + + # 更新材质属性 + material.setBaseColor(Vec4(float(data[1]), float(data[2]), float(data[3]), 1.0)) + material.setRoughness(float(data[4])) + material.setMetallic(float(data[6])) + + print(f"✓ 更新材质 {name}: 颜色=({data[1]}, {data[2]}, {data[3]}), 粗糙度={data[4]}, 金属度={data[6]}") + else: + print(f"未找到索引为 {index} 的材质") + + except Exception as e: + print(f"更新材质失败: {e}") + + def launch_material_editor(self): + """启动材质编辑器""" + import subprocess + import os + import sys + + try: + if not self.render_pipeline: + print("错误:renderpipeline未初始化") + return False + + base_path = self.render_pipeline.mount_mgr.base_path + editor_path = os.path.join(base_path,"toolkit/material_editor/main.py") + + if not os.path.exists(editor_path): + print("错误文件不存在") + return False + + self._material_editor_process = subprocess.Popen([sys.executable, editor_path]) + print("Material Editor 已启动") + return True + except Exception as e: + print(f"启动 Material editor失败") + + def create_sample_materials(self): + """创建一些示例材质供编辑器使用""" + from panda3d.core import Material, Vec4, CardMaker + + # 创建几个测试几何体,每个都有不同的材质 + sample_materials = [ + {"name": "MetalMaterial", "color": Vec4(0.7, 0.7, 0.8, 1.0), "metallic": True, "roughness": 0.2}, + {"name": "PlasticMaterial", "color": Vec4(0.8, 0.2, 0.2, 1.0), "metallic": False, "roughness": 0.8}, + {"name": "GlassMaterial", "color": Vec4(0.9, 0.9, 1.0, 0.3), "metallic": False, "roughness": 0.1}, + {"name": "WoodMaterial", "color": Vec4(0.6, 0.4, 0.2, 1.0), "metallic": False, "roughness": 0.7}, + {"name": "TestPlaneMaterial", "color": Vec4(0.8, 0.8, 0.8, 1.0), "metallic": False, "roughness": 1.0} + ] + + for i, mat_data in enumerate(sample_materials): + # 创建几何体 + if mat_data["name"] == "TestPlaneMaterial": + # 创建一个大的测试平面,类似Blender中的平面 + cm = CardMaker('test_plane') + cm.setFrame(-5, 5, -5, 5) # 更大的平面 + geom_node = self.render.attachNewNode(cm.generate()) + geom_node.setPos(0, 15, 0) # 放在前面显眼位置 + geom_node.setP(-90) # 水平放置 + print("✓ 创建大型测试平面,适合测试粗糙度贴图") + else: + cm = CardMaker(f'sample_geom_{i}') + cm.setFrame(-1, 1, -1, 1) + geom_node = self.render.attachNewNode(cm.generate()) + geom_node.setPos(i * 3 - 6, 10, 1) + geom_node.setP(-90) # 水平放置 + + # 创建材质并确保名称正确设置 + material = Material() + material.setName(mat_data["name"]) # 明确设置材质名称 + material.setBaseColor(mat_data["color"]) + material.setRoughness(mat_data["roughness"]) + material.setMetallic(1.0 if mat_data["metallic"] else 0.0) + + # 应用材质 + geom_node.setMaterial(material) + + print(f"✓ 创建示例材质: {mat_data['name']}") + + # 延迟一下确保材质完全创建 + import time + time.sleep(0.1) + + def load_test_models_with_materials(self): + """加载一些测试模型以提供更多材质供编辑""" + try: + # 你可以在这里加载你的模型文件 + # test_model = self.loader.loadModel("models/your_model.gltf") + # if test_model: + # test_model.reparentTo(self.render) + # test_model.setPos(5, 0, 0) + # test_model.setScale(1.0) + # print(f"✓ 测试模型已加载") + + # 创建示例材质 + self.create_sample_materials() + + except Exception as e: + print(f"加载测试模型失败: {e}") + # 创建示例材质作为备选 + self.create_sample_materials() \ No newline at end of file diff --git a/ui/main_window.py b/ui/main_window.py index c75506f8..4c07ae62 100644 --- a/ui/main_window.py +++ b/ui/main_window.py @@ -78,6 +78,7 @@ class MainWindow(QMainWindow): self.moveAction = self.toolsMenu.addAction('移动工具') self.rotateAction = self.toolsMenu.addAction('旋转工具') self.scaleAction = self.toolsMenu.addAction('缩放工具') + self.sunsetAction = self.toolsMenu.addAction('光照编辑') # GUI菜单 self.guiMenu = menubar.addMenu('GUI') @@ -365,7 +366,10 @@ class MainWindow(QMainWindow): self.saveAction.triggered.connect(lambda: saveProject(self)) self.buildAction.triggered.connect(lambda: buildPackage(self)) self.exitAction.triggered.connect(QApplication.instance().quit) - + + #连接工具事件 + self.sunsetAction.triggered.connect(lambda : self.world.setCurrentTool("光照编辑")) + # 连接GUI编辑模式事件 self.guiEditModeAction.triggered.connect(lambda: self.world.toggleGUIEditMode()) diff --git a/ui/property_panel.py b/ui/property_panel.py index 1cfd9df1..8d4bb869 100644 --- a/ui/property_panel.py +++ b/ui/property_panel.py @@ -1,10 +1,12 @@ +from traceback import print_exc from types import new_class from typing import Hashable from PyQt5.QtWidgets import (QLabel, QLineEdit, QDoubleSpinBox, QPushButton, QTreeWidget, QTreeWidgetItem, QMenu,QCheckBox) from PyQt5.QtCore import Qt -from panda3d.core import Vec3, Vec4 +from panda3d.core import Vec3, Vec4, transpose + class PropertyPanelManager: """属性面板管理器""" @@ -73,8 +75,6 @@ class PropertyPanelManager: self.updateGUIPropertyPanel(model) elif model and hasattr(model,'getTag') and model.getTag("light_type"): self.updateLightPropertyPanel(model) - elif model and hasattr(model,'getTag') and model.getTag("light_type"): - self.updateLightPropertyPanel(model) # 如果找到模型,显示其属性 elif model: self._updateModelPropertyPanel(model) @@ -350,7 +350,7 @@ class PropertyPanelManager: yPos.setRange(-1000,1000) yPos.setValue(current_pos.getY()) yPos.valueChanged.connect(lambda v:self._updateLightPosition(light_object,model,'y',v)) - self._propertyLayout.addRow("相对位置 X:",yPos) + self._propertyLayout.addRow("相对位置 Y:",yPos) zPos = QDoubleSpinBox() zPos.setRange(-1000,1000) @@ -604,6 +604,30 @@ class PropertyPanelManager: node_path.setScale(new_scale) + def _generateUniqueMaterialNames(self, materials, model_name): + """生成唯一的材质名称,避免重复""" + material_names = {} + unique_names = [] + + for i, material in enumerate(materials): + # 获取材质的原始名称 + base_name = material.get_name() if hasattr(material, 'get_name') and material.get_name() else f"材质{i + 1}" + full_name = f"{base_name}:{model_name}" + + # 检查是否重复 + if full_name in material_names: + # 如果重复,增加计数器 + material_names[full_name] += 1 + unique_name = f"{full_name}_{material_names[full_name]}" + else: + # 首次出现,记录并使用原名 + material_names[full_name] = 0 + unique_name = full_name + + unique_names.append(unique_name) + + return unique_names + def _updateModelMaterialPanel(self,model): """模型材质属性""" @@ -617,84 +641,157 @@ class PropertyPanelManager: model_name=model.getName() or "未命名模型" + name_counter = {} + + # 创建材质到几何节点的映射字典 + self._material_geom_mapping = {} + self._material_display_names = {} + for i,material in enumerate(materials): - #材质名称属性 - #print(f"Material{i+1}name:{material.get_name()}") - material_title = QLabel(f"材质{i+1}:{model_name}") + # 查找使用该材质的几何节点,使用几何节点名称作为材质标题 + geom_node = self._findSpecificGeomNodeWithMaterial(model, material) + + if geom_node: + # 使用几何节点名称作为材质标题 + geom_node_name = geom_node.getName() + unique_name = f"{geom_node_name}({model_name})" + print(f"材质 {i}: 使用几何节点名称 '{geom_node_name}'") + else: + # 回退到原有的材质名称逻辑 + material_name = material.get_name() if hasattr(material,'get_name') and material.get_name() else f"材质{i + 1}" + unique_name = f"{material_name}({model_name})" + print(f"材质 {i}: 未找到几何节点,使用材质名称 '{material_name}'") + + # 处理重复名称 + if unique_name in name_counter: + name_counter[unique_name] += 1 + display_name = f"{unique_name}_{name_counter[unique_name]}" + else: + name_counter[unique_name] = 1 + display_name = unique_name + + # 存储材质和对应的几何节点信息到映射字典中 + material_id = id(material) # 使用材质对象的内存地址作为唯一标识 + self._material_geom_mapping[material_id] = geom_node + self._material_display_names[material_id] = display_name + + material_title = QLabel(display_name) material_title.setStyleSheet("color:#00AAFF;font-weight:bold;font-size:12px") self._propertyLayout.addRow(material_title) - #检查是否为PBR材质 - #and material.has_roughness() and material.has_refractive_index() - if not (material.has_base_color() ): - non_pbr_label = QLabel("非PBR材质,无法编辑") - non_pbr_label.setStyleSheet("color:orange;font-style:italic;") - self._propertyLayout.addRow("状态:",non_pbr_label) - continue - # if not material.has_base_color(): - # non_pbr_label = QLabel("非PBR材质(部分属性可能不可用)") - # non_pbr_label.setStyleSheet("color:orange;font-style:italic;") - # self._propertyLayout.addRow("状态:", non_pbr_label) + # 检查材质类型并显示状态,但允许所有材质进行编辑 + material_status = self._getMaterialStatus(material) + if material_status != "标准PBR材质": + status_label = QLabel(material_status) + status_label.setStyleSheet("color:#FFA500;font-style:italic;font-size:10px;") + self._propertyLayout.addRow("状态:", status_label) - #基础颜色编辑 - base_color = material.base_color + # 移除了continue语句,让所有材质都可以编辑 - #R分量 - r_spinbox = QDoubleSpinBox() - r_spinbox.setRange(0.0,1.0) - r_spinbox.setSingleStep(0.01) - r_spinbox.setValue(base_color.x) - r_spinbox.valueChanged.connect(lambda v,mat = material:self._updateMaterialBaseColor(mat,'r',v)) - self._propertyLayout.addRow("基础颜色 R:",r_spinbox) + # 基础颜色编辑(智能检查和创建) + base_color = self._getOrCreateMaterialBaseColor(material) - #G分量 - g_spinbox = QDoubleSpinBox() - g_spinbox.setRange(0.0, 1.0) - g_spinbox.setSingleStep(0.01) - g_spinbox.setValue(base_color.y) - g_spinbox.valueChanged.connect(lambda v, mat=material: self._updateMaterialBaseColor(mat, 'g', v)) - self._propertyLayout.addRow("基础颜色 G:", g_spinbox) + if base_color is not None: + print(f"材质基础颜色: {base_color}") - # B分量 - b_spinbox = QDoubleSpinBox() - b_spinbox.setRange(0.0, 1.0) - b_spinbox.setSingleStep(0.01) - b_spinbox.setValue(base_color.z) - b_spinbox.valueChanged.connect(lambda v, mat=material: self._updateMaterialBaseColor(mat, 'b', v)) - self._propertyLayout.addRow("基础颜色 B:", b_spinbox) - # 添加Alpha分量(透明度) - alpha_spinbox = QDoubleSpinBox() - alpha_spinbox.setRange(0.0, 1.0) - alpha_spinbox.setSingleStep(0.01) - alpha_spinbox.setValue(base_color.w) # Alpha是Vec4的w分量 - alpha_spinbox.valueChanged.connect(lambda v, mat=material: self._updateMaterialBaseColor(mat, 'a', v)) - self._propertyLayout.addRow("透明度 (Alpha):", alpha_spinbox) + #R分量 + r_spinbox = QDoubleSpinBox() + r_spinbox.setRange(0.0,1.0) + r_spinbox.setSingleStep(0.01) + r_spinbox.setValue(base_color.x) + r_spinbox.valueChanged.connect(lambda v,mat = material:self._updateMaterialBaseColor(mat,'r',v)) + self._propertyLayout.addRow("基础颜色 R:",r_spinbox) - # 粗糙度 - roughness_spinbox = QDoubleSpinBox() - roughness_spinbox.setRange(0.0, 1.0) - roughness_spinbox.setSingleStep(0.01) - roughness_spinbox.setValue(material.roughness) - roughness_spinbox.valueChanged.connect(lambda v, mat=material: self._updateMaterialRoughness(mat, v)) - self._propertyLayout.addRow("粗糙度:", roughness_spinbox) + #G分量 + g_spinbox = QDoubleSpinBox() + g_spinbox.setRange(0.0, 1.0) + g_spinbox.setSingleStep(0.01) + g_spinbox.setValue(base_color.y) + g_spinbox.valueChanged.connect(lambda v, mat=material: self._updateMaterialBaseColor(mat, 'g', v)) + self._propertyLayout.addRow("基础颜色 G:", g_spinbox) + + # B分量 + b_spinbox = QDoubleSpinBox() + b_spinbox.setRange(0.0, 1.0) + b_spinbox.setSingleStep(0.01) + b_spinbox.setValue(base_color.z) + b_spinbox.valueChanged.connect(lambda v, mat=material: self._updateMaterialBaseColor(mat, 'b', v)) + self._propertyLayout.addRow("基础颜色 B:", b_spinbox) + + # Alpha分量(透明度) + alpha_spinbox = QDoubleSpinBox() + alpha_spinbox.setRange(0.0, 1.0) + alpha_spinbox.setSingleStep(0.01) + alpha_spinbox.setValue(base_color.w) # Alpha是Vec4的w分量 + alpha_spinbox.valueChanged.connect(lambda v, mat=material: self._updateMaterialBaseColor(mat, 'a', v)) + self._propertyLayout.addRow("透明度 (Alpha):", alpha_spinbox) + else: + # 如果无法获取或创建基础颜色,显示提示 + no_base_color_label = QLabel("无法获取材质基础颜色") + no_base_color_label.setStyleSheet("color:#888;font-style:italic;font-size:10px;") + self._propertyLayout.addRow("基础颜色:", no_base_color_label) + + # 粗糙度(安全检查) + if hasattr(material, 'roughness') and material.roughness is not None: + try: + roughness_value = float(material.roughness) + roughness_spinbox = QDoubleSpinBox() + roughness_spinbox.setRange(0.0, 1.0) + roughness_spinbox.setSingleStep(0.01) + roughness_spinbox.setValue(roughness_value) + roughness_spinbox.valueChanged.connect(lambda v, mat=material: self._updateMaterialRoughness(mat, v)) + self._propertyLayout.addRow("粗糙度:", roughness_spinbox) + except (TypeError, ValueError) as e: + print(f"粗糙度值无效: {material.roughness}, 错误: {e}") + no_roughness_label = QLabel("粗糙度值无效,无法编辑") + no_roughness_label.setStyleSheet("color:#888;font-style:italic;font-size:10px;") + self._propertyLayout.addRow("粗糙度:", no_roughness_label) + else: + no_roughness_label = QLabel("此材质不支持粗糙度编辑") + no_roughness_label.setStyleSheet("color:#888;font-style:italic;font-size:10px;") + self._propertyLayout.addRow("粗糙度:", no_roughness_label) - # 金属性 - metallic_spinbox = QDoubleSpinBox() - metallic_spinbox.setRange(0.0, 1.0) - metallic_spinbox.setSingleStep(0.01) - metallic_spinbox.setValue(material.metallic) - metallic_spinbox.valueChanged.connect(lambda v, mat=material: self._updateMaterialMetallic(mat, v)) - self._propertyLayout.addRow("金属性:", metallic_spinbox) + # 金属性(安全检查) + if hasattr(material, 'metallic') and material.metallic is not None: + try: + metallic_value = float(material.metallic) + metallic_spinbox = QDoubleSpinBox() + metallic_spinbox.setRange(0.0, 1.0) + metallic_spinbox.setSingleStep(0.01) + metallic_spinbox.setValue(metallic_value) + metallic_spinbox.valueChanged.connect(lambda v, mat=material: self._updateMaterialMetallic(mat, v)) + self._propertyLayout.addRow("金属性:", metallic_spinbox) + except (TypeError, ValueError) as e: + print(f"金属性值无效: {material.metallic}, 错误: {e}") + no_metallic_label = QLabel("金属性值无效,无法编辑") + no_metallic_label.setStyleSheet("color:#888;font-style:italic;font-size:10px;") + self._propertyLayout.addRow("金属性:", no_metallic_label) + else: + no_metallic_label = QLabel("此材质不支持金属性编辑") + no_metallic_label.setStyleSheet("color:#888;font-style:italic;font-size:10px;") + self._propertyLayout.addRow("金属性:", no_metallic_label) - # 折射率 - ior_spinbox = QDoubleSpinBox() - ior_spinbox.setRange(1.0, 3.0) - ior_spinbox.setSingleStep(0.01) - ior_spinbox.setValue(material.refractive_index) - ior_spinbox.valueChanged.connect(lambda v, mat=material: self._updateMaterialIOR(mat, v)) - self._propertyLayout.addRow("折射率:", ior_spinbox) + # 折射率(安全检查) + if hasattr(material, 'refractive_index') and material.refractive_index is not None: + try: + ior_value = float(material.refractive_index) + ior_spinbox = QDoubleSpinBox() + ior_spinbox.setRange(1.0, 3.0) + ior_spinbox.setSingleStep(0.01) + ior_spinbox.setValue(ior_value) + ior_spinbox.valueChanged.connect(lambda v, mat=material: self._updateMaterialIOR(mat, v)) + self._propertyLayout.addRow("折射率:", ior_spinbox) + except (TypeError, ValueError) as e: + print(f"折射率值无效: {material.refractive_index}, 错误: {e}") + no_ior_label = QLabel("折射率值无效,无法编辑") + no_ior_label.setStyleSheet("color:#888;font-style:italic;font-size:10px;") + self._propertyLayout.addRow("折射率:", no_ior_label) + else: + no_ior_label = QLabel("此材质不支持折射率编辑") + no_ior_label.setStyleSheet("color:#888;font-style:italic;font-size:10px;") + self._propertyLayout.addRow("折射率:", no_ior_label) texture_title = QLabel("纹理贴图") texture_title.setStyleSheet("color: #4CAF50; font-weight:bold;font-size:11px;margin-top:5px;") @@ -702,23 +799,59 @@ class PropertyPanelManager: #漫反射贴图 diffuse_button = QPushButton("选择漫反射贴图") - diffuse_button.clicked.connect(lambda checked,mat=material:self._selectDiffuseTexture(mat)) + diffuse_button.clicked.connect(lambda checked,title=unique_name:self._selectDiffuseTexture(title)) self._propertyLayout.addRow("漫反射贴图:",diffuse_button) - # #法线贴图 - # normal_button = QPushButton("选择法线贴图") - # normal_button.clicked.connect(lambda checked,mat=material:self._selectNormalTexture(mat)) - # self._propertyLayout.addRow("法线贴图:",normal_button) + #法线贴图 + normal_button = QPushButton("选择法线贴图") + normal_button.clicked.connect(lambda checked,mat=material:self._selectNormalTexture(mat)) + self._propertyLayout.addRow("法线贴图:",normal_button) + + + #粗糙度贴图 + roughness_button = QPushButton("选择粗糙度贴图") + roughness_button.clicked.connect(lambda checked,mat=material:self._selectRoughnessTexture((mat))) + self._propertyLayout.addRow("粗糙度贴图:",roughness_button) + + #金属性贴图 + metallic_button = QPushButton("选择金属性贴图") + metallic_button.clicked.connect(lambda checked,mat=material:self._selectMetallicTexture(mat)) + self._propertyLayout.addRow("金属性贴图:",metallic_button) + + #IOR贴图 + ior_button = QPushButton("选择IOR贴图") + ior_button.clicked.connect(lambda checked,mat = material:self._selectIORTexture(mat)) + self._propertyLayout.addRow("IOR贴图",ior_button) + + # # 视差贴图 + # parallax_button = QPushButton("选择视差贴图") + # parallax_button.clicked.connect(lambda checked, mat=material: self._selectParallaxTexture(mat)) + # self._propertyLayout.addRow("视差贴图:", parallax_button) # - # #粗糙度贴图 - # roughness_button = QPushButton("选择粗糙度贴图") - # roughness_button.clicked.connect(lambda checked,mat=material:self._selectRoughnessTexture((mat))) - # self._propertyLayout.addRow("粗糙度贴图:",roughness_button) + # # 自发光贴图 + # emission_button = QPushButton("选择自发光贴图") + # emission_button.clicked.connect(lambda checked, mat=material: self._selectEmissionTexture(mat)) + # self._propertyLayout.addRow("自发光贴图:", emission_button) # - # #金属性贴图 - # metallic_button = QPushButton("选择金属性贴图") - # metallic_button.clicked.connect(lambda checked,mat=material:self._selectMetallicTexture(mat)) - # self._propertyLayout.addRow("金属性贴图:",metallic_button) + # # 环境光遮蔽贴图 + # ao_button = QPushButton("选择AO贴图") + # ao_button.clicked.connect(lambda checked, mat=material: self._selectAOTexture(mat)) + # self._propertyLayout.addRow("AO贴图:", ao_button) + # + # # 透明度贴图 + # alpha_button = QPushButton("选择透明度贴图") + # alpha_button.clicked.connect(lambda checked, mat=material: self._selectAlphaTexture(mat)) + # self._propertyLayout.addRow("透明度贴图:", alpha_button) + # + # # 细节贴图 + # detail_button = QPushButton("选择细节贴图") + # detail_button.clicked.connect(lambda checked, mat=material: self._selectDetailTexture(mat)) + # self._propertyLayout.addRow("细节贴图:", detail_button) + # + # # 光泽贴图 + # gloss_button = QPushButton("选择光泽贴图") + # gloss_button.clicked.connect(lambda checked, mat=material: self._selectGlossTexture(mat)) + # self._propertyLayout.addRow("光泽贴图:", gloss_button) @@ -738,43 +871,249 @@ class PropertyPanelManager: self._propertyLayout.addRow(separator) def _updateMaterialBaseColor(self, material, component, value): - """更新材质基础颜色""" - from panda3d.core import Vec4 - current_color = material.base_color + """更新材质基础颜色(智能版本)""" + try: + from panda3d.core import Vec4 - if component == 'r': - new_color = Vec4(value, current_color.y, current_color.z, current_color.w) - elif component == 'g': - new_color = Vec4(current_color.x, value, current_color.z, current_color.w) - elif component == 'b': - new_color = Vec4(current_color.x, current_color.y, value, current_color.w) - elif component == 'a': # 添加Alpha分量处理 - new_color = Vec4(current_color.x, current_color.y, current_color.z, value) + # 获取当前颜色 + current_color = self._getOrCreateMaterialBaseColor(material) + if current_color is None: + print(f"无法获取材质基础颜色,跳过更新") + return - material.set_base_color(new_color) - self._invalidateRenderState() + # 计算新颜色 + if component == 'r': + new_color = Vec4(value, current_color.y, current_color.z, current_color.w) + elif component == 'g': + new_color = Vec4(current_color.x, value, current_color.z, current_color.w) + elif component == 'b': + new_color = Vec4(current_color.x, current_color.y, value, current_color.w) + elif component == 'a': # Alpha分量处理 + new_color = Vec4(current_color.x, current_color.y, current_color.z, value) + else: + print(f"未知的颜色分量: {component}") + return + + # 尝试多种方式设置颜色 + success = False + + # 方法1: 使用set_base_color + if hasattr(material, 'set_base_color'): + try: + material.set_base_color(new_color) + print(f"✓ 通过set_base_color更新: {component}={value}") + success = True + except Exception as e: + print(f"set_base_color失败: {e}") + + # 方法2: 使用setDiffuse作为备选 + if not success and hasattr(material, 'setDiffuse'): + try: + material.setDiffuse(new_color) + print(f"✓ 通过setDiffuse更新: {component}={value}") + success = True + except Exception as e: + print(f"setDiffuse失败: {e}") + + # 方法3: 直接设置属性 + if not success and hasattr(material, 'base_color'): + try: + material.base_color = new_color + print(f"✓ 通过直接属性设置更新: {component}={value}") + success = True + except Exception as e: + print(f"直接属性设置失败: {e}") + + if success: + self._invalidateRenderState() + print(f"材质基础颜色已更新: {new_color}") + else: + print(f"✗ 所有更新方法都失败了") + + except Exception as e: + print(f"更新材质基础颜色失败: {e}") def _updateMaterialRoughness(self, material, value): - """更新材质粗糙度""" - material.set_roughness(value) - self._invalidateRenderState() + """更新材质粗糙度(安全版本)""" + try: + if not hasattr(material, 'roughness') or material.roughness is None: + print(f"材质不支持粗糙度属性或值为None,跳过更新") + return + material.set_roughness(value) + self._invalidateRenderState() + except Exception as e: + print(f"更新材质粗糙度失败: {e}") def _updateMaterialMetallic(self, material, value): - """更新材质金属性""" - material.set_metallic(value) - self._invalidateRenderState() + """更新材质金属性(安全版本)""" + try: + if not hasattr(material, 'metallic') or material.metallic is None: + print(f"材质不支持金属性属性或值为None,跳过更新") + return + material.set_metallic(value) + self._invalidateRenderState() + except Exception as e: + print(f"更新材质金属性失败: {e}") def _updateMaterialIOR(self, material, value): - """更新材质折射率""" - material.set_refractive_index(value) - self._invalidateRenderState() + """更新材质折射率(安全版本)""" + try: + if not hasattr(material, 'refractive_index') or material.refractive_index is None: + print(f"材质不支持折射率属性或值为None,跳过更新") + return + material.set_refractive_index(value) + self._invalidateRenderState() + except Exception as e: + print(f"更新材质折射率失败: {e}") + + def _getMaterialStatus(self, material): + """获取材质状态描述""" + try: + # 检查材质的各种属性 + has_base_color = hasattr(material, 'has_base_color') and material.has_base_color() + has_roughness = hasattr(material, 'has_roughness') and material.has_roughness() + has_metallic = hasattr(material, 'has_metallic') and material.has_metallic() + has_ior = hasattr(material, 'has_refractive_index') and material.has_refractive_index() + + # 检查基本属性是否存在 + has_base_color_attr = hasattr(material, 'base_color') + has_roughness_attr = hasattr(material, 'roughness') + has_metallic_attr = hasattr(material, 'metallic') + has_ior_attr = hasattr(material, 'refractive_index') + + if has_base_color and has_roughness and has_metallic and has_ior: + return "标准PBR材质" + elif has_base_color_attr and has_roughness_attr and has_metallic_attr: + return "PBR材质(部分属性可用)" + elif has_base_color_attr or has_roughness_attr or has_metallic_attr: + return "基础材质(支持部分PBR属性)" + else: + return "传统材质(可转换为PBR)" + + except Exception as e: + print(f"检查材质状态时出错: {e}") + return "未知材质类型(可尝试编辑)" def _invalidateRenderState(self): - """使渲染状态失效以应用材质更改""" - from panda3d.core import RenderState - RenderState.clear_cache() + """使渲染状态失效以应用材质更改(无闪烁版本)""" + # 完全不做任何操作,避免闪烁 + # 现代渲染管线会自动检测纹理变化并更新 + print("材质更改已应用,无需手动刷新渲染状态") - def _selectDiffuseTexture(self,material): + + + def _getTextureModeString(self, mode): + """获取纹理模式的字符串表示""" + from panda3d.core import TextureStage + mode_map = { + TextureStage.MModulate: "Modulate", + TextureStage.MDecal: "Decal", + TextureStage.MBlend: "Blend", + TextureStage.MReplace: "Replace", + TextureStage.MAdd: "Add", + TextureStage.MCombine: "Combine", + TextureStage.MBlendColorScale: "BlendColorScale", + TextureStage.MModulateGlow: "ModulateGlow", + TextureStage.MModulateGloss: "ModulateGloss", + TextureStage.MNormal: "Normal", + TextureStage.MNormalHeight: "NormalHeight", + TextureStage.MGlow: "Glow", + TextureStage.MGloss: "Gloss", + TextureStage.MHeight: "Height", + TextureStage.MSelector: "Selector", + TextureStage.MNormalGloss: "NormalGloss" + } + return mode_map.get(mode, f"Unknown({mode})") + + def _checkAndAdjustMaterialProperty(self, material, property_name, current_value, texture_type): + """检查并智能调整材质属性值""" + if current_value <= 0.01: + print(f"⚠️ 警告:材质{property_name}过低({current_value}),{texture_type}贴图可能无效果") + print(f" RenderPipeline使用公式: 最终{property_name} = 材质{property_name} × 贴图值") + print(f" 当前设置下,即使贴图为白色(1.0),最终效果也只有{current_value}") + + # 询问用户是否要自动调整(在实际应用中,这里可以弹出对话框) + # 目前我们采用保守的自动调整策略 + recommended_value = 0.8 # 推荐值 + + if property_name == "粗糙度": + material.set_roughness(recommended_value) + elif property_name == "金属性": + material.set_metallic(recommended_value) + + print(f"✓ 已自动调整材质{property_name}为 {recommended_value}") + print(f" 现在{texture_type}贴图的效果范围:白色区域={recommended_value},黑色区域=0.0") + return recommended_value + else: + print(f"✓ 材质{property_name}合适: {current_value}") + print(f" {texture_type}贴图效果范围:白色区域={current_value:.2f},黑色区域=0.0") + return current_value + + def _getOrCreateMaterialBaseColor(self, material): + """智能获取或创建材质的基础颜色""" + from panda3d.core import Vec4 + + try: + # 方法1: 尝试获取base_color属性 + if hasattr(material, 'base_color') and material.base_color is not None: + print(f"✓ 找到base_color属性: {material.base_color}") + return material.base_color + + # 方法2: 尝试调用get_base_color方法 + if hasattr(material, 'get_base_color'): + try: + base_color = material.get_base_color() + if base_color is not None: + print(f"✓ 通过get_base_color()获取: {base_color}") + return base_color + except: + pass + + # 方法3: 尝试从diffuse颜色获取 + if hasattr(material, 'getDiffuse'): + try: + diffuse_color = material.getDiffuse() + if diffuse_color is not None: + print(f"✓ 从diffuse颜色获取: {diffuse_color}") + # 同时设置为base_color + if hasattr(material, 'set_base_color'): + material.set_base_color(diffuse_color) + return diffuse_color + except: + pass + + # 方法4: 尝试从ambient颜色获取 + if hasattr(material, 'getAmbient'): + try: + ambient_color = material.getAmbient() + if ambient_color is not None: + print(f"✓ 从ambient颜色获取: {ambient_color}") + # 同时设置为base_color + if hasattr(material, 'set_base_color'): + material.set_base_color(ambient_color) + return ambient_color + except: + pass + + # 方法5: 创建默认的基础颜色 + print("⚠️ 未找到现有颜色,创建默认基础颜色") + default_color = Vec4(0.8, 0.8, 0.8, 1.0) # 默认灰白色 + + # 尝试设置到材质 + if hasattr(material, 'set_base_color'): + material.set_base_color(default_color) + print(f"✓ 设置默认base_color: {default_color}") + elif hasattr(material, 'setDiffuse'): + material.setDiffuse(default_color) + print(f"✓ 设置默认diffuse: {default_color}") + + return default_color + + except Exception as e: + print(f"✗ 获取材质基础颜色失败: {e}") + return None + + def _selectDiffuseTexture(self,material_title): """漫反射贴图""" from PyQt5.QtWidgets import QFileDialog import os @@ -784,7 +1123,7 @@ class PropertyPanelManager: if file_dialog.exec_(): filename = file_dialog.selectedFiles()[0] if filename: - self._applyDiffuseTexture(material,filename) + self._applyDiffuseTexture(material_title,filename) print(f"已选择漫反射贴图:{filename}") def _selectNormalTexture(self,material): @@ -809,7 +1148,7 @@ class PropertyPanelManager: filename = file_dialog.selectedFiles()[0] if filename: self._applyRoughnessTexture(material,filename) - print(f"已选择粗糙度贴图:{filename}") + print(f"已选择粗糙度贴图: {filename}") def _selectMetallicTexture(self,material): """选择金属性贴图""" @@ -821,9 +1160,94 @@ class PropertyPanelManager: filename = file_dialog.selectedFiles()[0] if filename: self._applyMetallicTexture(material,filename) - print(f"已选择金属性贴图:{filename}") + print(f"已选择金属性贴图: {filename}") - def _applyDiffuseTexture(self,material,texture_path): + #IOR贴图 + def _selectIORTexture(self,material): + """选择IOR贴图""" + from PyQt5.QtWidgets import QFileDialog + + file_dialong = QFileDialog(None,"选择IOR贴图","","图像(*.png *.jpg *.jpeg *.tga *.bmp)") + + if file_dialong.exec_(): + filename = file_dialong.selectedFiles()[0] + if filename: + self._applyIORTexture(material,filename) + print(f"已选择IOR贴图:{filename}") + + def _selectParallaxTexture(self,material): + """选择视差贴图""" + from PyQt5.QtWidgets import QFileDialog + + file_dialog = QFileDialog(None,"选择视差贴图","","图像文件(*.png *.jpg *.jpeg *.tga *.bmp)") + + if file_dialog.exec_(): + filename = file_dialog.selectedFiles()[0] + if filename: + self._applyParallaxTexture(material,filename) + print(f"已选择视差贴图:{filename}") + + def _selectEmissionTexture(self,material): + """选择自发光贴图""" + from PyQt5.QtWidgets import QFileDialog + + file_dialog = QFileDialog(None,"选择自发光贴图","","图像文件(*.png *.jpg *.jpeg *.tga *.bmp)") + + if file_dialog.exec_(): + filename = file_dialog.selectedFiles()[0] + if filename: + self._applyEmissionTexture(material,filename) + print(f"已选择自发光贴图:{filename}") + + def _selectAOTexture(self,material): + """选择环境光遮蔽贴图""" + from PyQt5.QtWidgets import QFileDialog + + file_dialog = QFileDialog(None,"选择AO贴图","","图像文件(*.png *.jpg *.jpeg *.tga *.bmp)") + + if file_dialog.exec_(): + filename = file_dialog.selectedFiles()[0] + if filename: + self._applyAOTexture(material,filename) + print(f"已选择AO贴图:{filename}") + + def _selectAlphaTexture(self,material): + """选择透明度贴图""" + from PyQt5.QtWidgets import QFileDialog + + file_dialog = QFileDialog(None,"选择透明度贴图","","图像文件(*.png *.jpg *.jpeg *.tga *.bmp)") + + if file_dialog.exec_(): + filename = file_dialog.selectedFiles()[0] + if filename: + self._applyAlphaTexture(material,filename) + print(f"已选择透明度贴图:{filename}") + + def _selectDetailTexture(self,material): + """选择细节贴图""" + from PyQt5.QtWidgets import QFileDialog + + file_dialog = QFileDialog(None,"选择细节贴图","","图像文件(*.png *.jpg *.jpeg *.tga *.bmp)") + + if file_dialog.exec_(): + filename = file_dialog.selectedFiles()[0] + if filename: + self._applyDetailTexture(material,filename) + print(f"已选择细节贴图:{filename}") + + def _selectGlossTexture(self,material): + """选择光泽贴图""" + from PyQt5.QtWidgets import QFileDialog + + file_dialog = QFileDialog(None,"选择光泽贴图","","图像文件(*.png *.jpg *.jpeg *.tga *.bmp)") + + if file_dialog.exec_(): + filename = file_dialog.selectedFiles()[0] + if filename: + self._applyGlossTexture(material,filename) + print(f"已选择光泽贴图:{filename}") + + def _applyDiffuseTexture(self,material_title,texture_path): """应用漫反射贴图""" try: from RenderPipelineFile.rpcore.loader import RPLoader @@ -832,94 +1256,1325 @@ class PropertyPanelManager: #加载纹理 texture = RPLoader.load_texture(texture_path) if texture: - #material.set_base_color_texture(texture) #获取材质所属的节点 - node = self._findNodeWithMaterial(material) - if node: - #应用漫反射贴图到第一个纹理阶段 - node.setTexture(TextureStage.getDefault(),texture,1) + material,node = self._findMaterialAndNodeByTitle(material_title) + if node and material: + print(f"正在为节点 {node.getName()} 应用漫反射贴图") + + # 确保启用PBR效果(包括法线映射支持) + try: + self.world.render_pipeline.set_effect( + node, + "effects/default.yaml", + { + "normal_mapping": True, # 启用法线映射支持 + "render_gbuffer": True, + "alpha_testing": False, + "parallax_mapping": False, + "render_shadow": True, + "render_envmap": True + }, + 100 + ) + print("✅ 默认PBR效果已应用(支持法线映射)") + except Exception as e: + print(f"⚠️ PBR效果应用失败: {e}") + + # 根据RenderPipeline的gbuffer.frag.glsl模板: + # p3d_Texture0 用于漫反射贴图 (line 111: texture(p3d_Texture0, texcoord).xyz) + + # 清理可能存在的漫反射贴图 + existing_stages = node.findAllTextureStages() + for stage in existing_stages: + if stage.getSort() == 0 or "diffuse" in stage.getName().lower(): + node.clearTexture(stage) + print(f"清理了现有的漫反射贴图阶段: {stage.getName()}") + + # 创建漫反射贴图纹理阶段,对应p3d_Texture0 + diffuse_stage = TextureStage("diffuse") + diffuse_stage.setSort(0) # 对应p3d_Texture0 + diffuse_stage.setMode(TextureStage.MModulate) # 标准的调制模式 + + # 应用漫反射贴图 + node.setTexture(diffuse_stage, texture) + print("漫反射贴图已应用到p3d_Texture0槽") + + # 调试信息:显示当前纹理阶段 + print("=== 漫反射贴图应用后的纹理阶段信息 ===") + all_stages = node.findAllTextureStages() + for i, stage in enumerate(all_stages): + tex = node.getTexture(stage) + mode_name = self._getTextureModeString(stage.getMode()) + print(f"阶段 {i}: {stage.getName()}, Sort: {stage.getSort()}, 模式: {mode_name}, 纹理: {tex.getName() if tex else 'None'}") + print("==========================================") + self._invalidateRenderState() - print(f"漫反射贴图已应用:{texture_path}") + print(f"漫反射贴图已成功应用:{texture_path}") else: - print("没有找到材质") + print(f"未找到材质标题对应的材质或节点: {material_title}") else: - print("未找到材质对应的节点") + print("纹理加载失败") except Exception as e: print(f"应用漫反射贴图失败{e}") import traceback traceback.print_exc() - def _applyNormalTexture(self,material,texture_path): - """应用法线贴图""" - try: + # def _applyNormalTexture(self, material, texture_path): + # """应用法线贴图""" + # try: + # from RenderPipelineFile.rpcore.loader import RPLoader + # from panda3d.core import TextureStage + # + # texture = RPLoader.load_texture(texture_path) + # if texture: + # node = self._findNodeWithMaterial(material) + # if node: + # # 创建法线贴图纹理阶段 + # normal_stage = TextureStage("normal") + # normal_stage.setSort(1) # 设置排序优先级 + # node.setTexture(normal_stage, texture) + # self._invalidateRenderState() + # print(f"法线贴图已应用:{texture_path}") + # else: + # print("未找到材质对应的节点") + # except Exception as e: + # print(f"应用法线贴图失败:{e}") + # import traceback + # traceback.print_exc() + def _applyNormalTexture(self, material, texture_path): + """应用法线贴图 - Blender风格效果""" + try: from RenderPipelineFile.rpcore.loader import RPLoader - from panda3d.core import TextureStage + from panda3d.core import TextureStage, Vec4 + + print(f"🎨 应用法线贴图: {texture_path}") texture = RPLoader.load_texture(texture_path) + if not texture: + print("❌ 纹理加载失败") + return - if texture: - node = self._findNodeWithMaterial(material) - if node: - #创建法线贴图纹理阶段 + # 查找使用该材质的具体几何节点 + node = self._findSpecificGeomNodeForMaterial(material) + if not node: + print("❌ 未找到材质对应的节点") + return + + print(f"🎯 目标节点: {node.getName()}") + + # 清理现有的法线贴图,避免冲突 + print("🧹 清理现有纹理阶段...") + existing_stages = node.findAllTextureStages() + has_diffuse_texture = False + + for stage in existing_stages: + if "normal" in stage.getName().lower() or stage.getSort() == 1: + node.clearTexture(stage) + print(f" ✅ 已清理法线纹理阶段: {stage.getName()}") + elif stage.getSort() == 0: # 检查是否有漫反射贴图 + tex = node.getTexture(stage) + if tex: + has_diffuse_texture = True + print(f" 🔍 发现现有漫反射贴图: {tex.getName()}") + + # 如果没有漫反射贴图,必须创建白色纹理,否则法线映射会失效 + if not has_diffuse_texture: + print("⚠️ 没有漫反射贴图,创建白色纹理确保法线映射正常工作...") + self._createWhiteDiffuseTexture(node) + + # 使用默认PBR效果,确保法线映射正常工作 + print("🔧 应用默认PBR效果(启用法线映射)...") + try: + self.world.render_pipeline.set_effect( + node, + "effects/default.yaml", + { + "normal_mapping": True, # 必须启用法线映射 + "render_gbuffer": True, + "alpha_testing": False, + "parallax_mapping": False, + "render_shadow": True, + "render_envmap": True + }, + 100 + ) + print("✅ 默认PBR效果已应用(启用法线映射)") + except Exception as e: + print(f"⚠️ PBR效果应用失败: {e}") + + # 创建法线贴图纹理阶段,对应p3d_Texture1 + print("🎨 创建法线纹理阶段...") + normal_stage = TextureStage("normal_map") + normal_stage.setSort(1) # 对应shader中的p3d_Texture1 + normal_stage.setMode(TextureStage.MModulate) # 使用标准模式,不是MNormal + normal_stage.setTexcoordName("texcoord") + + print(f"📋 法线纹理阶段信息:") + print(f" • 名称: {normal_stage.getName()}") + print(f" • 排序: {normal_stage.getSort()} (对应p3d_Texture1)") + print(f" • 模式: {normal_stage.getMode()} (MModulate)") + + # 应用纹理到正确的纹理槽 + node.setTexture(normal_stage, texture) + print(f"🔗 法线纹理已绑定到p3d_Texture1槽") + + # 设置材质的normalfactor参数(用于法线强度) + current_emission = material.emission + if current_emission is None: + current_emission = Vec4(0, 0, 0, 0) + print("材质emission为None,使用默认值") + + # emission.y 用于存储 normalfactor + new_emission = Vec4(current_emission.x, 1.0, current_emission.z, current_emission.w) + material.set_emission(new_emission) + print(f"🔧 设置法线强度参数: normalfactor = {new_emission.y}") + + # 验证纹理应用 + applied_texture = node.getTexture(normal_stage) + if applied_texture: + print(f"✅ 法线贴图成功应用到p3d_Texture1槽") + print(f"📊 纹理信息:") + print(f" • 纹理名称: {applied_texture.getName()}") + print(f" • 纹理尺寸: {applied_texture.getXSize()}x{applied_texture.getYSize()}") + print(f"📊 Blender风格效果:") + print(f" • 法线贴图将影响表面细节和光照") + print(f" • 不会改变材质颜色,只影响表面法线") + else: + print("❌ 纹理应用验证失败") - #normal_stage = TextureStage("normal") - node.setTexture(1,texture) - #normal_stage.setMode(TextureStage.MNormal) - #node.setTexture(normal_stage,texture) - self._invalidateRenderState() - print(f"法线贴图一应用:{texture_path}") - else: - print("未找到材质对应的节点") except Exception as e: - print(f"应用法线贴图失败:{e}") + print(f"❌ 应用法线贴图失败: {e}") import traceback traceback.print_exc() def _applyRoughnessTexture(self,material,texture_path): - """应用粗糙度贴图""" + """应用粗糙度贴图 - Blender风格效果""" try: - from RenderPipelineFile.rpcore.loader import RPLoader from panda3d.core import TextureStage + print(f"🎨 应用粗糙度贴图: {texture_path}") + texture = RPLoader.load_texture(texture_path) - if texture: - node = self._findNodeWithMaterial(material) + if not texture: + print("❌ 纹理加载失败") + return + + # 查找使用该材质的具体几何节点 + node = self._findSpecificGeomNodeForMaterial(material) + if not node: + print("❌ 未找到材质对应的节点") + return + + print(f"🎯 目标节点: {node.getName()}") + + # 设置材质粗糙度为1.0,让贴图完全控制粗糙度分布 + # 这样白色区域=1.0(粗糙),黑色区域=0.0(光滑),灰色区域=中等粗糙度 + material.set_roughness(1.0) + print("🔧 材质粗糙度设置为1.0,启用贴图完全控制") + + # 清理现有的粗糙度贴图,避免冲突 + print("🧹 清理现有纹理阶段...") + existing_stages = node.findAllTextureStages() + print(f"🔍 发现 {len(existing_stages)} 个现有纹理阶段:") + + for stage in existing_stages: + tex = node.getTexture(stage) + tex_name = tex.getName() if tex else "无纹理" + print(f" - {stage.getName()} (sort={stage.getSort()}) -> {tex_name}") + + # 只清理粗糙度相关的纹理阶段 + if "roughness" in stage.getName().lower() or stage.getSort() == 3: + node.clearTexture(stage) + print(f" ✅ 已清理粗糙度纹理阶段: {stage.getName()}") + + # 特别检查是否有漫反射贴图占用了错误的槽位 + diffuse_stages = [s for s in existing_stages if s.getSort() == 0] + if diffuse_stages: + print(f"🔍 发现漫反射贴图阶段: {[s.getName() for s in diffuse_stages]}") + + # 确保没有纹理占用sort=3的槽位 + sort3_stages = [s for s in existing_stages if s.getSort() == 3] + if sort3_stages: + print(f"⚠️ 发现占用sort=3槽位的纹理: {[s.getName() for s in sort3_stages]}") + for stage in sort3_stages: + node.clearTexture(stage) + print(f" ✅ 已强制清理: {stage.getName()}") + + # 使用调试粗糙度贴图效果来验证纹理是否正确读取 + print("🔧 应用调试粗糙度贴图效果...") + debug_mode = True # 设为True来调试纹理读取 + + try: + if debug_mode: + # 使用调试效果:将粗糙度纹理显示为颜色 + self.world.render_pipeline.set_effect( + node, + "effects/debug_roughness.yaml", + { + "normal_mapping": False, + "render_gbuffer": True, + "alpha_testing": False, + "parallax_mapping": False, + "render_shadow": True, + "render_envmap": True + }, + 100 + ) + print("✅ 调试粗糙度效果已应用(纹理将显示为灰度颜色)") + print(" 如果看到灰度变化,说明纹理读取正确") + else: + # 使用专门的粗糙度效果,避免与漫反射贴图混淆 + self.world.render_pipeline.set_effect( + node, + "effects/roughness_only.yaml", + { + "normal_mapping": False, # 关闭法线贴图避免干扰 + "render_gbuffer": True, # 必须启用gbuffer渲染 + "alpha_testing": False, + "parallax_mapping": False, + "render_shadow": True, + "render_envmap": True + }, + 100 # 高优先级确保应用 + ) + print("✅ 专门的粗糙度贴图效果已应用") + + # 验证效果是否正确应用 + current_effect = node.getEffect() + if current_effect: + print(f"🔍 当前效果: {current_effect}") + else: + print("⚠️ 效果应用后为空,可能有问题") + + except Exception as e: + print(f"⚠️ 专门的粗糙度效果失败: {e}") + print("🔄 回退到默认PBR效果...") + # 回退到默认效果 + try: + self.world.render_pipeline.set_effect( + node, + "effects/default.yaml", + { + "normal_mapping": False, + "render_gbuffer": True, + "alpha_testing": False, + "parallax_mapping": False, + "render_shadow": True, + "render_envmap": True + }, + 100 + ) + print("✅ 默认PBR效果已应用") + except Exception as e2: + print(f"⚠️ 默认效果也失败: {e2}") + # 最后的备选方案:清除所有效果 + try: + node.clearEffect() + print("🔄 已清除所有效果,使用基础渲染") + except: + pass + + # 创建粗糙度贴图阶段,对应p3d_Texture3 + print("🎨 创建粗糙度纹理阶段...") + roughness_stage = TextureStage("roughness_map") + roughness_stage.setSort(3) # 对应shader中的p3d_Texture3 + + # 重要:设置正确的纹理模式 + # MReplace模式确保纹理不会与其他纹理混合 + roughness_stage.setMode(TextureStage.MReplace) + + # 确保纹理坐标正确 + roughness_stage.setTexcoordName("texcoord") + + print(f"📋 粗糙度纹理阶段信息:") + print(f" • 名称: {roughness_stage.getName()}") + print(f" • 排序: {roughness_stage.getSort()} (对应p3d_Texture3)") + print(f" • 模式: {roughness_stage.getMode()} (MReplace)") + print(f" • 纹理坐标: {roughness_stage.getTexcoordName()}") + + # 应用纹理到正确的纹理槽 + node.setTexture(roughness_stage, texture) + print(f"🔗 粗糙度纹理已绑定到p3d_Texture3槽") + + # 强制刷新渲染状态 + node.setRenderModeWireframe() + node.clearRenderMode() + print(f"🔄 已刷新渲染状态") + + # 验证纹理应用 + applied_texture = node.getTexture(roughness_stage) + if applied_texture: + print(f"✅ 粗糙度贴图成功应用到p3d_Texture3槽") + print(f"📊 纹理信息:") + print(f" • 纹理名称: {applied_texture.getName()}") + print(f" • 纹理尺寸: {applied_texture.getXSize()}x{applied_texture.getYSize()}") + print(f"📊 Blender风格效果:") + print(f" • 白色区域 = 完全粗糙 (1.0)") + print(f" • 黑色区域 = 完全光滑 (0.0)") + print(f" • 灰色区域 = 中等粗糙度 (0.5)") + print(f" • 公式: 最终粗糙度 = 1.0 × 贴图值") + + # 列出节点上的所有纹理阶段 + print(f"🔍 节点上的所有纹理阶段:") + all_stages = node.findAllTextureStages() + for i, stage in enumerate(all_stages): + tex = node.getTexture(stage) + tex_name = tex.getName() if tex else "无纹理" + print(f" {i}: {stage.getName()} (sort={stage.getSort()}) -> {tex_name}") + + # 验证shader是否正确处理纹理 + self._verifyTextureInShader(node, "roughness", 3) + + else: + print("❌ 纹理应用验证失败") + print("🔍 尝试诊断问题...") + + # 检查纹理是否有效 + if texture: + print(f" 纹理对象有效: {texture.getName()}") + else: + print(" 纹理对象无效") + + # 检查节点是否有效 if node: - #创建粗糙度贴图纹理阶段 - roughness_stage = TextureStage("roughtness") - roughness_stage.setMode(TextureStage.MModulate) - node.setTexture(roughness_stage,texture) - print(f"粗糙度贴图已应用:{texture_path}") + print(f" 节点对象有效: {node.getName()}") + else: + print(" 节点对象无效") + except Exception as e: - print(f"应用粗糙度贴图失败:{e}") + print(f"❌ 应用粗糙度贴图失败: {e}") + import traceback + traceback.print_exc() + + def _verifyTextureInShader(self, node, texture_type, expected_sort): + """验证纹理是否在shader中正确处理""" + try: + print(f"🔍 验证{texture_type}纹理在shader中的处理...") + + # 检查当前效果 + current_effect = node.getEffect() + if current_effect: + print(f" 当前shader效果: {current_effect}") + else: + print(" ⚠️ 节点没有shader效果") + return False + + # 检查纹理槽 + stages = node.findAllTextureStages() + target_stage = None + for stage in stages: + if stage.getSort() == expected_sort: + target_stage = stage + break + + if target_stage: + tex = node.getTexture(target_stage) + if tex: + print(f" ✅ 找到{texture_type}纹理在sort={expected_sort}槽: {tex.getName()}") + + # 检查纹理数据 + if tex.hasRamImage(): + print(f" ✅ 纹理有RAM图像数据") + else: + print(f" ⚠️ 纹理没有RAM图像数据") + + return True + else: + print(f" ❌ sort={expected_sort}槽没有纹理") + else: + print(f" ❌ 没有找到sort={expected_sort}的纹理阶段") + + return False + + except Exception as e: + print(f" ❌ 验证失败: {e}") + return False + + def _ensureEnhancedPBREffect(self, node): + """确保节点使用增强的PBR效果,支持金属性纹理""" + try: + print("🔧 应用金属性贴图支持的PBR效果...") + self.world.render_pipeline.set_effect( + node, + "effects/pbr_with_metallic.yaml", + { + "normal_mapping": False, # 关闭法线贴图避免干扰 + "render_gbuffer": True, # 必须启用gbuffer渲染 + "alpha_testing": False, + "parallax_mapping": False, + "render_shadow": True, + "render_envmap": True + }, + 100 # 高优先级确保应用 + ) + print("✅ 金属性贴图PBR效果已应用") + return True + except Exception as e: + print(f"⚠️ 金属性贴图PBR效果失败: {e}") + # 回退到默认效果 + try: + self.world.render_pipeline.set_effect( + node, + "effects/default.yaml", + { + "normal_mapping": False, + "render_gbuffer": True, + "alpha_testing": False, + "parallax_mapping": False, + "render_shadow": True, + "render_envmap": True + }, + 100 + ) + print("✅ 已回退到默认PBR效果(不支持金属性贴图)") + return True + except Exception as e2: + print(f"⚠️ 默认效果也失败: {e2}") + return False + + def _createWhiteDiffuseTexture(self, node): + """创建白色漫反射纹理,确保法线贴图能正常工作""" + try: + from RenderPipelineFile.rpcore.loader import RPLoader + from panda3d.core import TextureStage + + print("🎨 尝试加载白色纹理...") + + # 尝试加载一个白色纹理文件,如果不存在就创建 + white_texture = None + + # 方法1:尝试从RenderPipeline加载空白基础颜色纹理(应该是白色) + try: + white_texture = RPLoader.load_texture("RenderPipelineFile/data/empty_textures/empty_basecolor.png") + if white_texture: + print("✅ 从RenderPipeline空白纹理加载白色纹理") + except Exception as e1: + print(f"⚠️ 加载空白纹理失败: {e1}") + pass + + # 方法2:如果没有默认纹理,创建简单的白色纹理 + if not white_texture: + try: + from panda3d.core import Texture + white_texture = Texture("white_diffuse") + white_texture.setup2dTexture(1, 1, Texture.TUnsignedByte, Texture.FRgb) + # 设置白色像素数据 + white_data = b'\xff\xff\xff' + white_texture.setRamImage(white_data) + print("✅ 创建了程序生成的白色纹理") + except Exception as e2: + print(f"⚠️ 创建程序纹理也失败: {e2}") + return False + + if white_texture: + # 创建漫反射纹理阶段 + diffuse_stage = TextureStage("white_diffuse") + diffuse_stage.setSort(0) # 对应p3d_Texture0 + diffuse_stage.setMode(TextureStage.MModulate) + + # 应用白色纹理 + node.setTexture(diffuse_stage, white_texture) + print("✅ 白色漫反射纹理已应用,材质颜色将正常显示") + return True + + return False + + except Exception as e: + print(f"⚠️ 创建白色纹理失败: {e}") + return False def _applyMetallicTexture(self,material,texture_path): - """应用金属性贴图""" + """应用金属性贴图 - Blender风格效果""" try: + from RenderPipelineFile.rpcore.loader import RPLoader + from panda3d.core import TextureStage + print(f"🎨 应用金属性贴图: {texture_path}") + + texture = RPLoader.load_texture(texture_path) + if not texture: + print("❌ 纹理加载失败") + return + + # 查找使用该材质的具体几何节点 + node = self._findSpecificGeomNodeForMaterial(material) + if not node: + print("❌ 未找到材质对应的节点") + return + + print(f"🎯 目标节点: {node.getName()}") + + # 保持材质金属性为1.0,让贴图完全控制 + material.set_metallic(1.0) + print("🔧 材质金属性设置为1.0,启用贴图完全控制") + + # 清理现有的金属性贴图,避免冲突 + print("🧹 清理现有纹理阶段...") + existing_stages = node.findAllTextureStages() + print(f"🔍 发现 {len(existing_stages)} 个现有纹理阶段:") + + for stage in existing_stages: + tex = node.getTexture(stage) + tex_name = tex.getName() if tex else "无纹理" + print(f" - {stage.getName()} (sort={stage.getSort()}) -> {tex_name}") + + # 只清理金属性相关的纹理阶段 + if "metallic" in stage.getName().lower() or stage.getSort() == 5: + node.clearTexture(stage) + print(f" ✅ 已清理金属性纹理阶段: {stage.getName()}") + + # 确保没有纹理占用sort=5的槽位 + sort5_stages = [s for s in existing_stages if s.getSort() == 5] + if sort5_stages: + print(f"⚠️ 发现占用sort=5槽位的纹理: {[s.getName() for s in sort5_stages]}") + for stage in sort5_stages: + node.clearTexture(stage) + print(f" ✅ 已强制清理: {stage.getName()}") + + # 使用调试金属性贴图效果来验证纹理是否正确读取 + print("🔧 应用调试金属性贴图效果...") + debug_mode = True # 设为True来调试纹理读取 + + try: + if debug_mode: + # 使用调试效果:将金属性纹理显示为颜色 + self.world.render_pipeline.set_effect( + node, + "effects/debug_metallic.yaml", + { + "normal_mapping": False, + "render_gbuffer": True, + "alpha_testing": False, + "parallax_mapping": False, + "render_shadow": True, + "render_envmap": True + }, + 100 + ) + print("✅ 调试金属性效果已应用(纹理将显示为蓝黄色变化)") + print(" 蓝色=非金属区域, 黄色=金属区域") + else: + # 使用专门的金属性效果,避免与漫反射贴图混淆 + self.world.render_pipeline.set_effect( + node, + "effects/metallic_only.yaml", + { + "normal_mapping": False, # 关闭法线贴图避免干扰 + "render_gbuffer": True, # 必须启用gbuffer渲染 + "alpha_testing": False, + "parallax_mapping": False, + "render_shadow": True, + "render_envmap": True + }, + 100 # 高优先级确保应用 + ) + print("✅ 专门的金属性贴图效果已应用") + + # 验证效果是否正确应用 + current_effect = node.getEffect() + if current_effect: + print(f"🔍 当前效果: {current_effect}") + else: + print("⚠️ 效果应用后为空,可能有问题") + + except Exception as e: + print(f"⚠️ 专门的金属性效果失败: {e}") + print("🔄 回退到直接控制金属性效果...") + # 回退到直接控制效果 + try: + self._ensurePBREffectEnabledWithDirectMetallic(node) + print("✅ 直接控制金属性效果已应用") + except Exception as e2: + print(f"⚠️ 直接控制效果也失败: {e2}") + # 最后的备选方案:使用稳定效果 + try: + self._ensurePBREffectEnabledStable(node) + print("🔄 已应用稳定PBR效果") + except: + pass + + # 创建金属性贴图阶段,对应p3d_Texture5 + print("🎨 创建金属性纹理阶段...") + metallic_stage = TextureStage("metallic_map") + metallic_stage.setSort(5) # 对应shader中的p3d_Texture5 + + # 重要:设置正确的纹理模式 + # MReplace模式确保纹理不会与其他纹理混合 + metallic_stage.setMode(TextureStage.MReplace) + + # 确保纹理坐标正确 + metallic_stage.setTexcoordName("texcoord") + + print(f"📋 金属性纹理阶段信息:") + print(f" • 名称: {metallic_stage.getName()}") + print(f" • 排序: {metallic_stage.getSort()} (对应p3d_Texture5)") + print(f" • 模式: {metallic_stage.getMode()} (MReplace)") + print(f" • 纹理坐标: {metallic_stage.getTexcoordName()}") + + # 应用纹理到正确的纹理槽 + node.setTexture(metallic_stage, texture) + print(f"🔗 金属性纹理已绑定到p3d_Texture5槽") + + # 强制刷新渲染状态 + node.setRenderModeWireframe() + node.clearRenderMode() + print(f"🔄 已刷新渲染状态") + + # 验证纹理应用 + applied_texture = node.getTexture(metallic_stage) + if applied_texture: + print(f"✅ 金属性贴图成功应用到p3d_Texture5槽") + print(f"📊 纹理信息:") + print(f" • 纹理名称: {applied_texture.getName()}") + print(f" • 纹理尺寸: {applied_texture.getXSize()}x{applied_texture.getYSize()}") + print(f"📊 Blender风格效果:") + print(f" • 白色区域 = 完全金属 (1.0)") + print(f" • 黑色区域 = 非金属 (0.0)") + print(f" • 灰色区域 = 部分金属 (0.5)") + print(f" • 公式: 最终金属性 = 贴图值") + + # 列出节点上的所有纹理阶段 + print(f"🔍 节点上的所有纹理阶段:") + all_stages = node.findAllTextureStages() + for i, stage in enumerate(all_stages): + tex = node.getTexture(stage) + tex_name = tex.getName() if tex else "无纹理" + print(f" {i}: {stage.getName()} (sort={stage.getSort()}) -> {tex_name}") + + else: + print("❌ 纹理应用验证失败") + print("🔍 尝试诊断问题...") + + # 检查纹理是否有效 + if texture: + print(f" 纹理对象有效: {texture.getName()}") + else: + print(" 纹理对象无效") + + # 检查节点是否有效 + if node: + print(f" 节点对象有效: {node.getName()}") + else: + print(" 节点对象无效") + + except Exception as e: + print(f"❌ 应用金属性贴图失败: {e}") + import traceback + traceback.print_exc() + + def _applyIORTexture(self,material,texture_path): + """应用IOR贴图到特定材质""" + try: from RenderPipelineFile.rpcore.loader import RPLoader from panda3d.core import TextureStage texture = RPLoader.load_texture(texture_path) if texture: - node = self._findNodeWithMaterial(material) + # 查找使用该材质的具体几何节点 + node = self._findSpecificGeomNodeForMaterial(material) if node: - #创建金属性贴图纹理阶段 - metallic_stage = TextureStage("metallic") - metallic_stage.setSort(2) - #metallic_stage.setMode(TextureStage.MModulate) - node.setTexture(metallic_stage,texture) - self._invalidateRenderState() - print(f"金属性贴图已应用:{texture_path}") + print(f"正在为节点 {node.getName()} 应用IOR贴图") + + # 确保启用PBR效果 + self._ensurePBREffectEnabled(node) + + # 根据RenderPipeline的gbuffer.frag.glsl模板: + # p3d_Texture2 用于IOR贴图 (line 87: texture(p3d_Texture2, texcoord).x) + + # 清理现有的IOR贴图 + existing_stages = node.findAllTextureStages() + for stage in existing_stages: + if "ior" in stage.getName().lower() or stage.getSort() == 2: + node.clearTexture(stage) + print(f"清理了现有的IOR贴图阶段: {stage.getName()}") + + # 创建IOR贴图纹理阶段,对应p3d_Texture2 + ior_stage = TextureStage("ior") + ior_stage.setSort(2) # 对应p3d_Texture2 + ior_stage.setMode(TextureStage.MModulate) + + node.setTexture(ior_stage,texture) + print("IOR贴图已应用到p3d_Texture2槽") + + # 不再需要手动刷新渲染状态,避免闪烁 + print(f"IOR贴图已成功应用:{texture_path}") else: print("未找到材质对应的节点") except Exception as e: - print(f"应用金属性贴图失败:{e}") + print(f"应用IOR贴图失败:{e}") import traceback traceback.print_exc() + def _applyParallaxTexture(self,material,texture_path): + """应用视差贴图""" + try: + from RenderPipelineFile.rpcore.loader import RPLoader + from panda3d.core import TextureStage + + texture = RPLoader.load_texture(texture_path) + if texture: + node = self._findNodeWithMaterial(material) + if node: + print(f"正在为节点 {node.getName()} 应用视差贴图") + + # 确保启用PBR效果,包括视差映射 + self._ensurePBREffectEnabledWithParallax(node) + + # 根据RenderPipeline的gbuffer.frag.glsl模板: + # p3d_Texture4 用于视差贴图 (line 77: get_parallax_texcoord(p3d_Texture4, mInput.normalfactor)) + + # 清理现有的视差贴图 + existing_stages = node.findAllTextureStages() + for stage in existing_stages: + if "parallax" in stage.getName().lower() or stage.getSort() == 4: + node.clearTexture(stage) + print(f"清理了现有的视差贴图阶段: {stage.getName()}") + + # 创建视差贴图纹理阶段,对应p3d_Texture4 + parallax_stage = TextureStage("parallax") + parallax_stage.setSort(4) # 对应p3d_Texture4 + parallax_stage.setMode(TextureStage.MHeight) # 高度贴图模式 + + node.setTexture(parallax_stage,texture) + print("视差贴图已应用到p3d_Texture4槽") + + self._invalidateRenderState() + print(f"视差贴图已成功应用:{texture_path}") + else: + print("未找到材质对应节点") + except Exception as e: + print(f"应用视差贴图失败:{e}") + import traceback + traceback.print_exc() + + def _ensureNormalMappingEnabled(self,model): + """确保模型启用了法线映射功能""" + try: + self.world.render_pipeline.set_effect( + model, + "effects/default.yaml", + { + "normal_mapping":True, + "render_gbuffer":True, + "alpha_testing":True + }, + 30 + ) + print(f"已为模型{model.getName()}启用法线映射") + except Exception as e: + print(f"设置法线映射效果失败:{e}") + + def _ensurePBREffectEnabled(self, model): + """确保模型启用了完整的PBR效果,包括法线映射""" + try: + self.world.render_pipeline.set_effect( + model, + "effects/default.yaml", + { + "normal_mapping": True, + "render_gbuffer": True, + "alpha_testing": True, + "parallax_mapping": False, + "render_shadow": True, + "render_envmap": True + }, + 30 + ) + print(f"已为模型{model.getName()}启用PBR效果") + except Exception as e: + print(f"设置PBR效果失败:{e}") + + def _ensurePBREffectEnabledWithParallax(self, model): + """确保模型启用了完整的PBR效果,包括视差映射""" + try: + self.world.render_pipeline.set_effect( + model, + "effects/default.yaml", + { + "normal_mapping": True, + "render_gbuffer": True, + "alpha_testing": True, + "parallax_mapping": True, # 启用视差映射 + "render_shadow": True, + "render_envmap": True + }, + 30 + ) + print(f"已为模型{model.getName()}启用PBR效果(包括视差映射)") + except Exception as e: + print(f"设置PBR效果失败:{e}") + + def _ensurePBREffectEnabledWithMetallic(self, model): + """确保模型启用了支持金属性贴图的PBR效果""" + try: + # 首先尝试使用自定义的金属性贴图效果 + try: + self.world.render_pipeline.set_effect( + model, + "effects/pbr_with_metallic.yaml", + { + "normal_mapping": True, + "render_gbuffer": True, + "alpha_testing": True, + "parallax_mapping": False, + "render_shadow": True, + "render_envmap": True + }, + 30 + ) + print(f"已为模型{model.getName()}启用支持金属性贴图的PBR效果") + except Exception as e1: + print(f"自定义金属性效果失败,使用标准PBR效果: {e1}") + # 回退到标准PBR效果 + self._ensurePBREffectEnabled(model) + except Exception as e: + print(f"设置PBR效果失败:{e}") + + def _ensurePBREffectEnabledWithDirectMetallic(self, model): + """确保模型启用了支持金属性贴图直接控制的PBR效果""" + try: + # 首先尝试使用直接控制金属性贴图的效果 + try: + self.world.render_pipeline.set_effect( + model, + "effects/pbr_direct_metallic.yaml", + { + "normal_mapping": True, + "render_gbuffer": True, + "alpha_testing": True, + "parallax_mapping": False, + "render_shadow": True, + "render_envmap": True + }, + 30 + ) + print(f"✅ 已为模型{model.getName()}启用直接控制金属性贴图的PBR效果") + except Exception as e1: + print(f"⚠️ 直接控制金属性效果失败,使用标准金属性效果: {e1}") + # 回退到标准金属性贴图效果 + self._ensurePBREffectEnabledWithMetallic(model) + except Exception as e: + print(f"设置PBR效果失败:{e}") + + def _onMetallicModeChanged(self, material, mode_index): + """处理金属性控制模式变化""" + try: + mode_names = ["乘法模式", "直接控制模式", "叠加模式"] + print(f"🔧 金属性控制模式已切换为: {mode_names[mode_index]}") + + # 查找使用该材质的节点 + node = self._findSpecificGeomNodeForMaterial(material) + if node: + if mode_index == 0: + # 乘法模式:使用标准金属性贴图效果 + self._ensurePBREffectEnabledWithMetallic(node) + print(" 📊 效果:最终金属性 = 材质金属性 × 贴图值") + print(" 💡 适用于:微调现有材质的金属性分布") + elif mode_index == 1: + # 直接控制模式:使用直接控制效果 + self._ensurePBREffectEnabledWithDirectMetallic(node) + print(" 📊 效果:最终金属性 = 贴图值") + print(" 💡 适用于:贴图完全控制金属性分布") + elif mode_index == 2: + # 叠加模式:使用叠加效果 + self._ensurePBREffectEnabledWithAdditiveMetallic(node) + print(" 📊 效果:最终金属性 = 材质金属性 + 贴图值 (限制在0-1)") + print(" 💡 适用于:在材质基础上增加金属性区域") + + print(f"✅ 金属性控制模式已应用到节点: {node.getName()}") + else: + print("⚠️ 未找到材质对应的节点") + + except Exception as e: + print(f"切换金属性控制模式失败: {e}") + + def _ensurePBREffectEnabledWithAdditiveMetallic(self, model): + """确保模型启用了支持金属性贴图叠加控制的PBR效果""" + try: + # 首先尝试使用叠加控制金属性贴图的效果 + try: + self.world.render_pipeline.set_effect( + model, + "effects/pbr_additive_metallic.yaml", + { + "normal_mapping": True, + "render_gbuffer": True, + "alpha_testing": True, + "parallax_mapping": False, + "render_shadow": True, + "render_envmap": True + }, + 30 + ) + print(f"✅ 已为模型{model.getName()}启用叠加控制金属性贴图的PBR效果") + except Exception as e1: + print(f"⚠️ 叠加控制金属性效果失败,使用直接控制效果: {e1}") + # 回退到直接控制金属性贴图效果 + self._ensurePBREffectEnabledWithDirectMetallic(model) + except Exception as e: + print(f"设置PBR效果失败:{e}") + + def _ensurePBREffectEnabledWithEmission(self, model): + """确保模型启用了支持自发光贴图的PBR效果""" + try: + self.world.render_pipeline.set_effect( + model, + "effects/pbr_with_emission.yaml", + { + "normal_mapping": True, + "render_gbuffer": True, + "alpha_testing": True, + "parallax_mapping": False, + "render_shadow": True, + "render_envmap": True + }, + 30 + ) + print(f"已为模型{model.getName()}启用支持自发光贴图的PBR效果") + except Exception as e: + print(f"自定义自发光效果失败,使用标准PBR效果: {e}") + # 回退到标准PBR效果 + self._ensurePBREffectEnabled(model) + + def _ensurePBREffectEnabledWithAlpha(self, model): + """确保模型启用了支持透明度的PBR效果""" + try: + self.world.render_pipeline.set_effect( + model, + "effects/default.yaml", + { + "normal_mapping": True, + "render_gbuffer": False, # 透明物体不渲染到GBuffer + "render_forward": True, # 使用前向渲染 + "alpha_testing": True, + "parallax_mapping": False, + "render_shadow": True, + "render_envmap": True + }, + 30 + ) + print(f"已为模型{model.getName()}启用支持透明度的PBR效果") + except Exception as e: + print(f"设置透明度PBR效果失败: {e}") + # 回退到标准PBR效果 + self._ensurePBREffectEnabled(model) + + def _ensurePBREffectEnabledWithRoughness(self, model): + """确保模型启用了支持粗糙度贴图的PBR效果""" + try: + # 首先尝试使用自定义的粗糙度贴图效果 + try: + self.world.render_pipeline.set_effect( + model, + "effects/pbr_with_roughness.yaml", + { + "normal_mapping": True, + "render_gbuffer": True, + "alpha_testing": True, + "parallax_mapping": False, + "render_shadow": True, + "render_envmap": True + }, + 30 + ) + print(f"已为模型{model.getName()}启用支持粗糙度贴图的PBR效果") + except Exception as e1: + print(f"自定义粗糙度效果失败,使用标准PBR效果: {e1}") + # 回退到标准PBR效果 + self._ensurePBREffectEnabled(model) + except Exception as e: + print(f"设置PBR效果失败:{e}") + + def _ensurePBREffectEnabledStable(self, model): + """确保模型启用了稳定的PBR效果,避免频繁切换导致闪烁""" + try: + # 检查是否已经有PBR效果 + current_effect = model.getEffect() + if current_effect: + print(f"🔍 当前效果: {current_effect}") + # 如果已经有PBR相关效果,就不要切换了 + effect_name = str(current_effect) + if "pbr" in effect_name.lower() or "default" in effect_name.lower(): + print("✅ 已有PBR效果,保持不变避免闪烁") + return + + # 使用最稳定的默认PBR效果 + print("🔧 应用稳定的默认PBR效果...") + self.world.render_pipeline.set_effect( + model, + "effects/default.yaml", + { + "normal_mapping": True, + "render_gbuffer": True, + "alpha_testing": False, + "parallax_mapping": False, + "render_shadow": True, + "render_envmap": True + }, + 50 # 较高优先级 + ) + print(f"✅ 稳定PBR效果已应用到模型: {model.getName()}") + + except Exception as e: + print(f"⚠️ 设置稳定PBR效果失败: {e}") + # 最后的备选方案:清除所有效果 + try: + model.clearEffect() + print("🔄 已清除所有效果,使用默认渲染") + except: + pass + + + + def _applyEmissionTexture(self, material, texture_path): + """应用自发光贴图""" + try: + from RenderPipelineFile.rpcore.loader import RPLoader + from panda3d.core import TextureStage + + texture = RPLoader.load_texture(texture_path) + if texture: + node = self._findNodeWithMaterial(material) + if node: + print(f"正在为节点 {node.getName()} 应用自发光贴图") + + # 启用自发光效果 + self._ensurePBREffectEnabledWithEmission(node) + + # 清理现有的自发光贴图 + existing_stages = node.findAllTextureStages() + for stage in existing_stages: + if "emission" in stage.getName().lower() or stage.getSort() == 6: + node.clearTexture(stage) + print(f"清理了现有的自发光贴图阶段: {stage.getName()}") + + # 创建自发光贴图纹理阶段,对应p3d_Texture6 + emission_stage = TextureStage("emission") + emission_stage.setSort(6) # 对应p3d_Texture6 + emission_stage.setMode(TextureStage.MModulate) + + node.setTexture(emission_stage, texture) + print("自发光贴图已应用到p3d_Texture6槽") + + # 设置材质为自发光着色模型 + from panda3d.core import Vec4 + current_emission = material.emission + if current_emission is None: + current_emission = Vec4(0, 0, 0, 0) + + # emission.x 用于存储着色模型,1表示自发光 + new_emission = Vec4(1.0, current_emission.y, current_emission.z, current_emission.w) + material.set_emission(new_emission) + print("材质着色模型已设置为自发光") + + self._invalidateRenderState() + print(f"自发光贴图已成功应用:{texture_path}") + else: + print("未找到材质对应的节点") + except Exception as e: + print(f"应用自发光贴图失败:{e}") + import traceback + traceback.print_exc() + + def _applyAOTexture(self, material, texture_path): + """应用环境光遮蔽贴图""" + try: + from RenderPipelineFile.rpcore.loader import RPLoader + from panda3d.core import TextureStage + + texture = RPLoader.load_texture(texture_path) + if texture: + node = self._findNodeWithMaterial(material) + if node: + print(f"正在为节点 {node.getName()} 应用AO贴图") + + # 确保启用PBR效果 + self._ensurePBREffectEnabled(node) + + # 清理现有的AO贴图 + existing_stages = node.findAllTextureStages() + for stage in existing_stages: + if "ao" in stage.getName().lower() or stage.getSort() == 7: + node.clearTexture(stage) + print(f"清理了现有的AO贴图阶段: {stage.getName()}") + + # 创建AO贴图纹理阶段,对应p3d_Texture7 + ao_stage = TextureStage("ao") + ao_stage.setSort(7) # 对应p3d_Texture7 + ao_stage.setMode(TextureStage.MModulate) + + node.setTexture(ao_stage, texture) + print("AO贴图已应用到p3d_Texture7槽") + print("注意:AO贴图需要自定义shader支持才能正确显示") + + self._invalidateRenderState() + print(f"AO贴图已成功应用:{texture_path}") + else: + print("未找到材质对应的节点") + except Exception as e: + print(f"应用AO贴图失败:{e}") + import traceback + traceback.print_exc() + + def _applyAlphaTexture(self, material, texture_path): + """应用透明度贴图""" + try: + from RenderPipelineFile.rpcore.loader import RPLoader + from panda3d.core import TextureStage + + texture = RPLoader.load_texture(texture_path) + if texture: + node = self._findNodeWithMaterial(material) + if node: + print(f"正在为节点 {node.getName()} 应用透明度贴图") + + # 启用透明度测试的PBR效果 + self._ensurePBREffectEnabledWithAlpha(node) + + # 清理现有的透明度贴图 + existing_stages = node.findAllTextureStages() + for stage in existing_stages: + if "alpha" in stage.getName().lower() or stage.getSort() == 8: + node.clearTexture(stage) + print(f"清理了现有的透明度贴图阶段: {stage.getName()}") + + # 创建透明度贴图纹理阶段,对应p3d_Texture8 + alpha_stage = TextureStage("alpha") + alpha_stage.setSort(8) # 对应p3d_Texture8 + alpha_stage.setMode(TextureStage.MModulate) + + node.setTexture(alpha_stage, texture) + print("透明度贴图已应用到p3d_Texture8槽") + + # 设置材质为透明着色模型 + from panda3d.core import Vec4 + current_emission = material.emission + if current_emission is None: + current_emission = Vec4(0, 0, 0, 0) + + # emission.x 用于存储着色模型,3表示透明 + new_emission = Vec4(3.0, current_emission.y, current_emission.z, current_emission.w) + material.set_emission(new_emission) + print("材质着色模型已设置为透明") + + self._invalidateRenderState() + print(f"透明度贴图已成功应用:{texture_path}") + else: + print("未找到材质对应的节点") + except Exception as e: + print(f"应用透明度贴图失败:{e}") + import traceback + traceback.print_exc() + + def _applyDetailTexture(self, material, texture_path): + """应用细节贴图""" + try: + from RenderPipelineFile.rpcore.loader import RPLoader + from panda3d.core import TextureStage + + texture = RPLoader.load_texture(texture_path) + if texture: + node = self._findNodeWithMaterial(material) + if node: + print(f"正在为节点 {node.getName()} 应用细节贴图") + + # 确保启用PBR效果 + self._ensurePBREffectEnabled(node) + + # 清理现有的细节贴图 + existing_stages = node.findAllTextureStages() + for stage in existing_stages: + if "detail" in stage.getName().lower() or stage.getSort() == 9: + node.clearTexture(stage) + print(f"清理了现有的细节贴图阶段: {stage.getName()}") + + # 创建细节贴图纹理阶段,对应p3d_Texture9 + detail_stage = TextureStage("detail") + detail_stage.setSort(9) # 对应p3d_Texture9 + detail_stage.setMode(TextureStage.MModulate) + + node.setTexture(detail_stage, texture) + print("细节贴图已应用到p3d_Texture9槽") + print("注意:细节贴图需要自定义shader支持才能正确显示") + + self._invalidateRenderState() + print(f"细节贴图已成功应用:{texture_path}") + else: + print("未找到材质对应的节点") + except Exception as e: + print(f"应用细节贴图失败:{e}") + import traceback + traceback.print_exc() + + def _applyGlossTexture(self, material, texture_path): + """应用光泽贴图""" + try: + from RenderPipelineFile.rpcore.loader import RPLoader + from panda3d.core import TextureStage + + texture = RPLoader.load_texture(texture_path) + if texture: + node = self._findNodeWithMaterial(material) + if node: + print(f"正在为节点 {node.getName()} 应用光泽贴图") + + # 确保启用PBR效果 + self._ensurePBREffectEnabled(node) + + # 清理现有的光泽贴图 + existing_stages = node.findAllTextureStages() + for stage in existing_stages: + if "gloss" in stage.getName().lower() or stage.getSort() == 10: + node.clearTexture(stage) + print(f"清理了现有的光泽贴图阶段: {stage.getName()}") + + # 创建光泽贴图纹理阶段,对应p3d_Texture10 + gloss_stage = TextureStage("gloss") + gloss_stage.setSort(10) # 对应p3d_Texture10 + gloss_stage.setMode(TextureStage.MGloss) # 光泽模式 + + node.setTexture(gloss_stage, texture) + print("光泽贴图已应用到p3d_Texture10槽") + print("注意:光泽贴图需要自定义shader支持才能正确显示") + + self._invalidateRenderState() + print(f"光泽贴图已成功应用:{texture_path}") + else: + print("未找到材质对应的节点") + except Exception as e: + print(f"应用光泽贴图失败:{e}") + import traceback + traceback.print_exc() + + def _clearConflictingTextureStages(self, node): + """清理可能冲突的纹理阶段""" + try: + from panda3d.core import TextureStage + + # 获取所有纹理阶段 + texture_stages = node.findAllTextureStages() + + # 检查是否有冲突的纹理阶段 + stages_to_clear = [] + for stage in texture_stages: + stage_name = stage.getName() + # 如果发现未命名或冲突的阶段,标记清理 + if stage_name == "" or stage == TextureStage.getDefault(): + # 检查是否有法线贴图在默认阶段 + texture = node.getTexture(stage) + if texture and "normal" in texture.getName().lower(): + stages_to_clear.append(stage) + + # 清理冲突的阶段 + for stage in stages_to_clear: + node.clearTexture(stage) + print(f"清理了冲突的纹理阶段: {stage.getName()}") + + except Exception as e: + print(f"清理纹理阶段时出错: {e}") + def _findNodeWithMaterial(self, target_material): """查找使用指定材质的节点""" # 这里需要根据你的场景结构来实现 @@ -946,6 +2601,152 @@ class PropertyPanelManager: return model return None + def _findMaterialAndNodeByTitle(self, material_title): + """根据材质标题查找对应的材质和节点""" + print(f"正在查找材质标题: '{material_title}'") + + current_item = self.world.treeWidget.currentItem() + if not current_item: + print("未找到当前选中项") + return None, None + + current_model = current_item.data(0, Qt.UserRole) + if not current_model: + print("未找到当前模型") + return None, None + + materials = current_model.find_all_materials() + model_name = current_model.getName() or "未命名模型" + print(f"模型名称: '{model_name}', 材质数量: {len(materials)}") + + name_counter = {} + for i, material in enumerate(materials): + material_name = material.get_name() if hasattr(material, + 'get_name') and material.get_name() else f"材质{i + 1}" + base_name = f"{material_name}({model_name})" + + if base_name in name_counter: + name_counter[base_name] += 1 + unique_name = f"{base_name}_{name_counter[base_name]}" + else: + name_counter[base_name] = 1 + unique_name = base_name + + print(f"材质 {i}: 生成标题='{unique_name}'") + + if unique_name == material_title: + print(f"找到匹配的材质!") + geom_node = self._findSpecificGeomNodeWithMaterial(current_model, material) + if geom_node: + print(f"找到几何节点: {geom_node.get_name()}") + return material, geom_node + else: + print("未找到对应的几何节点,使用模型节点") + return material, current_model + + print("未找到匹配的材质标题") + return None, None + + def _findSpecificGeomNodeWithMaterial(self, model, target_material): + """查找使用指定材质的具体几何节点""" + from panda3d.core import MaterialAttrib, GeomNode + + print(f"查找材质: {target_material.get_name() if hasattr(target_material, 'get_name') else 'unnamed'}") + + # 首先尝试查找GeomNode + geom_nodes = model.find_all_matches("**/+GeomNode") + print(f"找到 {len(geom_nodes)} 个几何节点") + + # 如果没有找到GeomNode,尝试查找所有子节点 + if len(geom_nodes) == 0: + print("未找到GeomNode,尝试查找所有子节点...") + all_nodes = model.find_all_matches("**") + print(f"找到 {len(all_nodes)} 个子节点") + + for node_np in all_nodes: + node = node_np.node() + if isinstance(node, GeomNode): + geom_nodes.append(node_np) + print(f"找到GeomNode: {node_np.getName()}") + + for geom_np in geom_nodes: + geom_node = geom_np.node() + geom_count = geom_node.get_num_geoms() + print(f"检查几何节点 {geom_node.get_name()}: {geom_count} 个几何体") + + for i in range(geom_count): + state = geom_node.get_geom_state(i) + if state.has_attrib(MaterialAttrib): + material = state.get_attrib(MaterialAttrib).get_material() + if material == target_material: + print(f"找到匹配的几何节点: {geom_np.get_name()}") + return geom_np + + print("未找到匹配的几何节点") + return None + + def _findSpecificGeomNodeForMaterial(self, target_material): + """查找使用指定材质的具体几何节点(统一方法)""" + material_name = target_material.get_name() if hasattr(target_material, 'get_name') else 'unnamed' + print(f"查找材质对应的几何节点: {material_name}") + + # 优先使用存储的几何节点映射 + material_id = id(target_material) + if hasattr(self, '_material_geom_mapping') and material_id in self._material_geom_mapping: + geom_node = self._material_geom_mapping[material_id] + if geom_node: # 确保节点仍然有效 + print(f"✓ 使用存储的几何节点映射: {geom_node.getName()}") + return geom_node + + # 如果没有存储的映射,使用传统查找方法 + current_item = self.world.treeWidget.currentItem() + if current_item: + current_model = current_item.data(0, Qt.UserRole) + if current_model: + # 使用现有的精确查找方法 + geom_node = self._findSpecificGeomNodeWithMaterial(current_model, target_material) + if geom_node: + print(f"✓ 找到特定几何节点: {geom_node.getName()}") + # 存储映射以供后续使用 + if not hasattr(self, '_material_geom_mapping'): + self._material_geom_mapping = {} + self._material_geom_mapping[material_id] = geom_node + return geom_node + else: + print("⚠️ 未找到特定几何节点,使用模型节点(可能影响所有材质)") + return current_model + + print("❌ 未找到当前选中的模型") + return None + + def _findGeomNodeWithMaterial(self, model, target_material): + """查找使用指定材质的具体几何节点""" + from panda3d.core import MaterialAttrib + + print(f"查找材质: {target_material.get_name() if hasattr(target_material, 'get_name') else 'unnamed'}") + + # 遍历模型下的所有几何节点 + geom_nodes = model.find_all_matches("**/+GeomNode") + print(f"找到 {len(geom_nodes)} 个几何节点") + + for geom_np in geom_nodes: + geom_node = geom_np.node() + geom_count = geom_node.get_num_geoms() + print(f"几何节点 {geom_node.get_name()}: {geom_count} 个几何体") + + for i in range(geom_count): + state = geom_node.get_geom_state(i) + if state.has_attrib(MaterialAttrib): + material = state.get_attrib(MaterialAttrib).get_material() + if material == target_material: + print(f"找到匹配的几何节点: {geom_np.get_name()}") + return geom_np + else: + print(f"几何体 {i} 没有材质属性") + + print("未找到匹配的几何节点") + return None + def _displayCurrentTextures(self, material): """显示当前材质的贴图信息""" node = self._findNodeWithMaterial(material) @@ -1005,10 +2806,28 @@ class PropertyPanelManager: shading_combo.setCurrentIndex(current_model) shading_combo.currentIndexChanged.connect( - lambda idx: self._updateShadingModel(material, idx) + lambda idx: self._onShadingModelChanged(material, idx) ) self._propertyLayout.addRow("着色模型:", shading_combo) + # 如果是透明着色模型,添加透明度控制 + if hasattr(material, 'emission') and material.emission is not None and int(material.emission.x) == 3: + self._addTransparencyPanel(material) + + def _onShadingModelChanged(self, material, model_index): + """处理着色模型变化""" + print(f"着色模型变化: {model_index}") + + # 更新着色模型 + self._updateShadingModel(material, model_index) + + # 如果切换到透明模式,立即添加透明度面板 + if model_index == 3: + print("切换到透明模式,添加透明度面板...") + # 延迟一点时间让UI更新完成 + from PyQt5.QtCore import QTimer + QTimer.singleShot(100, lambda: self._addTransparencyPanel(material)) + def _updateShadingModel(self, material, model_index): """更新着色模型""" from panda3d.core import Vec4 @@ -1018,21 +2837,142 @@ class PropertyPanelManager: if hasattr(material, 'emission') and material.emission is not None: current_emission = material.emission - # 如果切换到自发光模式,设置默认发光强度 + # 根据不同的着色模型设置相应的参数 if model_index == 1: # 自发光模式 default_emission_strength = 2.0 if current_emission.z == 0 else current_emission.z new_emission = Vec4(float(model_index), current_emission.y, default_emission_strength, current_emission.w) + elif model_index == 3: # 透明模式 + print("设置透明着色模型...") + + # 设置默认透明度值 + default_opacity = 0.8 # 设置为较高的值,确保模型可见 + + # 同时在emission.y和base_color.w中设置透明度值 + # emission.y可能被RenderPipeline的某些部分使用 + new_emission = Vec4(float(model_index), default_opacity, current_emission.z, current_emission.w) + + # 透明度通过基础颜色的Alpha通道控制 + self._updateMaterialAlphaForTransparency(material, default_opacity) + + # 应用透明渲染效果 + self._applyTransparentRenderingEffect() + + print(f"透明着色模型设置完成") + print(f" - emission.x = {model_index} (透明着色模型)") + print(f" - emission.y = {default_opacity} (可能的透明度参数)") + print(f" - base_color.w = {default_opacity} (Alpha透明度)") else: new_emission = Vec4(float(model_index), current_emission.y, current_emission.z, current_emission.w) material.set_emission(new_emission) self._invalidateRenderState() - # 刷新UI以更新发光强度控件的值 - if model_index == 1: + # 刷新UI以更新相关控件的值 + if model_index in [1, 3]: # 自发光或透明模式 self._refreshMaterialUI() - print(f"着色模型已更新为: {model_index}") + print(f"着色模型已更新为: {model_index} ({'自发光' if model_index == 1 else '透明' if model_index == 3 else '默认'})") + + def _addTransparencyPanel(self, material): + """添加透明度控制面板""" + transparency_title = QLabel("透明度属性") + transparency_title.setStyleSheet("color: #00BFFF; font-weight:bold;") + self._propertyLayout.addRow(transparency_title) + + # 不透明度滑块(避免混淆,使用不透明度) + opacity_spinbox = QDoubleSpinBox() + opacity_spinbox.setRange(0.1, 1.0) # 最小值0.1,避免完全消失 + opacity_spinbox.setSingleStep(0.01) + + # 安全地获取当前不透明度值(从基础颜色的Alpha通道) + current_opacity = 0.3 # 默认值 + try: + base_color = self._getOrCreateMaterialBaseColor(material) + if base_color is not None: + current_opacity = max(0.1, base_color.w) # 从Alpha通道获取,确保不小于0.1 + except Exception as e: + print(f"获取当前透明度失败,使用默认值: {e}") + + opacity_spinbox.setValue(current_opacity) + opacity_spinbox.valueChanged.connect(lambda v: self._updateTransparency(material, v)) + self._propertyLayout.addRow("不透明度:", opacity_spinbox) + + def _updateTransparency(self, material, opacity_value): + """更新不透明度值(同时更新emission.y和base_color.w)""" + try: + from panda3d.core import Vec4 + + # 确保不透明度值在合理范围内 + opacity_value = max(0.1, min(1.0, opacity_value)) + + # 同时更新emission.y(可能被RenderPipeline使用) + current_emission = Vec4(0, 0, 0, 0) + if hasattr(material, 'emission') and material.emission is not None: + current_emission = material.emission + + new_emission = Vec4(current_emission.x, opacity_value, current_emission.z, current_emission.w) + material.set_emission(new_emission) + + # 更新基础颜色的Alpha通道 + self._updateMaterialAlphaForTransparency(material, opacity_value) + + self._invalidateRenderState() + print(f"透明度已更新:") + print(f" - emission.y = {opacity_value}") + print(f" - base_color.w = {opacity_value}") + print(f" - 视觉透明度 = {1.0 - opacity_value:.2f}") + + except Exception as e: + print(f"更新透明度失败: {e}") + + def _updateMaterialAlphaForTransparency(self, material, transparency_value): + """更新材质基础颜色的Alpha通道以匹配透明度""" + try: + # 获取当前基础颜色 + current_color = self._getOrCreateMaterialBaseColor(material) + if current_color is not None: + from panda3d.core import Vec4 + # 设置Alpha通道为透明度值 + new_color = Vec4(current_color.x, current_color.y, current_color.z, transparency_value) + + # 尝试多种方式设置颜色 + if hasattr(material, 'set_base_color'): + material.set_base_color(new_color) + elif hasattr(material, 'setDiffuse'): + material.setDiffuse(new_color) + + print(f"材质基础颜色Alpha已更新为: {transparency_value}") + except Exception as e: + print(f"更新材质Alpha通道失败: {e}") + + def _applyTransparentRenderingEffect(self): + """为当前选中的模型应用透明渲染效果(简化版本)""" + try: + current_item = self.world.treeWidget.currentItem() + if current_item: + model = current_item.data(0, Qt.UserRole) + if model: + print(f"正在为模型 {model.getName()} 应用透明渲染效果...") + + # 只使用最基本的透明度设置,避免冲突 + from panda3d.core import TransparencyAttrib + + # 启用Alpha混合 + model.setTransparency(TransparencyAttrib.MAlpha) + print(" - 透明度混合: 已启用 (MAlpha)") + + # 让RenderPipeline自动处理透明材质 + # 当emission.x=3时,RenderPipeline会自动设置正确的渲染参数 + self.world.render_pipeline.prepare_scene(model) + print(" - RenderPipeline自动处理: 已完成") + + print(f"✓ 已为模型 {model.getName()} 应用透明渲染效果") + print(" 注意: 使用简化设置避免渲染冲突") + + except Exception as e: + print(f"✗ 应用透明渲染效果失败: {e}") + import traceback + traceback.print_exc() def _addEmissionPanel(self, material): """添加自发光控制面板""" @@ -1102,9 +3042,13 @@ class PropertyPanelManager: if hasattr(material, '_applied_preset'): preset_combo.setCurrentText(material._applied_preset) else: - # 回退到检测当前材质最接近的预设 - current_preset = self._detectCurrentPreset(material) - preset_combo.setCurrentText(current_preset) + # 安全地检测当前材质最接近的预设 + try: + current_preset = self._detectCurrentPreset(material) + preset_combo.setCurrentText(current_preset) + except Exception as e: + print(f"检测材质预设时出错: {e}") + preset_combo.setCurrentText("自定义") preset_combo.currentTextChanged.connect( lambda preset: self._applyMaterialPreset(material, preset) @@ -1127,17 +3071,39 @@ class PropertyPanelManager: tolerance = 0.05 for preset_name, preset_values in presets.items(): - # 检查基础颜色 - base_color_match = ( - abs(material.base_color.x - preset_values["base_color"][0]) < tolerance and - abs(material.base_color.y - preset_values["base_color"][1]) < tolerance and - abs(material.base_color.z - preset_values["base_color"][2]) < tolerance - ) + # 安全检查基础颜色 + base_color_match = False + if hasattr(material, 'base_color') and material.base_color is not None: + try: + base_color_match = ( + abs(material.base_color.x - preset_values["base_color"][0]) < tolerance and + abs(material.base_color.y - preset_values["base_color"][1]) < tolerance and + abs(material.base_color.z - preset_values["base_color"][2]) < tolerance + ) + except (AttributeError, TypeError): + base_color_match = False - # 检查其他属性 - roughness_match = abs(material.roughness - preset_values["roughness"]) < tolerance - metallic_match = abs(material.metallic - preset_values["metallic"]) < tolerance - ior_match = abs(material.refractive_index - preset_values["ior"]) < tolerance + # 安全检查其他属性 + roughness_match = False + if hasattr(material, 'roughness') and material.roughness is not None: + try: + roughness_match = abs(float(material.roughness) - preset_values["roughness"]) < tolerance + except (AttributeError, TypeError, ValueError): + roughness_match = False + + metallic_match = False + if hasattr(material, 'metallic') and material.metallic is not None: + try: + metallic_match = abs(float(material.metallic) - preset_values["metallic"]) < tolerance + except (AttributeError, TypeError, ValueError): + metallic_match = False + + ior_match = False + if hasattr(material, 'refractive_index') and material.refractive_index is not None: + try: + ior_match = abs(float(material.refractive_index) - preset_values["ior"]) < tolerance + except (AttributeError, TypeError, ValueError): + ior_match = False # 如果所有属性都匹配,返回预设名称 if base_color_match and roughness_match and metallic_match and ior_match: @@ -1150,7 +3116,7 @@ class PropertyPanelManager: presets = { "塑料": {"base_color": Vec4(0.8, 0.8, 0.8, 1.0), "roughness": 0.7, "metallic": 0.0, "ior": 1.4}, "金属": {"base_color": Vec4(0.7, 0.7, 0.7, 1.0), "roughness": 0.1, "metallic": 1.0, "ior": 1.5}, - "玻璃": {"base_color": Vec4(0.9, 0.9, 1.0, 1.0), "roughness": 0.0, "metallic": 0.0, "ior": 1.5,"shading_model":3,"transparency":0.8}, + "玻璃": {"base_color": Vec4(0.9, 0.9, 1.0, 0.2), "roughness": 0.0, "metallic": 0.0, "ior": 1.5,"shading_model":3,"transparency":0.2}, "橡胶": {"base_color": Vec4(0.2, 0.2, 0.2, 1.0), "roughness": 0.9, "metallic": 0.0, "ior": 1.3}, "木材": {"base_color": Vec4(0.6, 0.4, 0.2, 1.0), "roughness": 0.8, "metallic": 0.0, "ior": 1.3}, "陶瓷": {"base_color": Vec4(0.9, 0.9, 0.85, 1.0), "roughness": 0.1, "metallic": 0.0, "ior": 1.6}, @@ -1161,8 +3127,20 @@ class PropertyPanelManager: print(f"未知的材质预设: {preset_name}") return + + preset = presets[preset_name] + if "shading_model" in preset: + emission = Vec4(float(preset["shading_model"]), 0, 0, 0) + if "transparency" in preset: + emission.y = preset["transparency"] + material.set_emission(emission) + + print(f"设置着色模型: {preset['shading_model']}") + print(f"材质emission值: {material.emission}") + print(f"基础颜色alpha: {preset['base_color'].w}") + material.set_base_color(preset["base_color"]) @@ -1177,8 +3155,8 @@ class PropertyPanelManager: material.set_emission(emission) #关键:为透明材质应用正确的渲染效果 - # if preset["shading_model"]==3: - # self._apply_transparent_effect() + if preset["shading_model"]==3: + self._apply_transparent_effect() self._invalidateRenderState() #material._applied_preset = preset_name @@ -1191,14 +3169,19 @@ class PropertyPanelManager: if current_item: model = current_item.data(0, Qt.UserRole) if model: - # 应用透明渲染效果 + # 只调用 prepare_scene,让它自动处理透明材质 self.world.render_pipeline.set_effect( model, "effects/default.yaml", - {"render_forward": True, "render_gbuffer": False}, + { + "render_forward": True, + "render_gbuffer": False, + "normal_mapping": True # 明确启用法线映射 + }, 100 ) - print("已应用透明渲染效果") + self.world.render_pipeline.prepare_scene(model) + print("已重新准备场景以应用透明效果") def _refreshMaterialUI(self): """刷新材质 UI 显示"""