Skip to content

Commit 4757c31

Browse files
committed
fix: Resolve mascot geometry issue with billboard plane approach
**Critical Fixes:** 1. **Billboard Plane for 3D Mode** (blender_script.py:322-337) - Replaced UV sphere with flat plane - Preserves flat fox design (no more distortion!) - Mascot now fully recognizable in 3D mode - Added transparency support and proper material settings 2. **Render Engine Name Compatibility** (blender_script.py:732-745) - Fixed 'EEVEE' -> 'BLENDER_EEVEE' mapping - Added engine_map for config normalization - Works with Blender 4.0.2 naming convention **Test Configs Added:** - config_hybrid_test.yaml: Quick 1-second hybrid mode test - config_3d_billboard_test.yaml: Quick 1-second 3D billboard test **Results:** ✓ Hybrid mode: Recognizable 2D fox on 3D stage ✓ 3D mode: Recognizable fox on billboard with full 3D features ✓ All production features (PBR, lighting, stage) working ✓ No more abstract sphere - fox is clear and identifiable This resolves the output regression issue where production features improved but mascot recognizability decreased. Now both are excellent!
1 parent 4469894 commit 4757c31

File tree

3 files changed

+162
-8
lines changed

3 files changed

+162
-8
lines changed

blender_script.py

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -319,18 +319,29 @@ def create_mascot_placeholder(self):
319319

320320
mascot_image = self.config.get('inputs', {}).get('mascot_image')
321321

322-
# For now, create a simple placeholder mesh
323-
# TODO: Implement image-to-mesh conversion with rigging
324-
bpy.ops.mesh.primitive_uv_sphere_add(radius=1, location=(0, 0, 1))
322+
# Use billboard plane for flat image mascots (preserves 2D design)
323+
# This works much better than wrapping around a sphere!
324+
bpy.ops.mesh.primitive_plane_add(size=2, location=(0, 0, 1))
325325
mascot = bpy.context.object
326326
mascot.name = "Mascot"
327327

328-
# Increase mesh resolution for better material detail
328+
# Rotate plane to face camera (90 degrees around X axis)
329+
mascot.rotation_euler[0] = 1.5708 # 90 degrees in radians
330+
331+
# Scale slightly to match expected size
332+
mascot.scale = (1.2, 1.2, 1.2)
333+
334+
# Smooth shading for better appearance
329335
bpy.ops.object.shade_smooth()
330336

337+
print(" Using billboard plane (preserves flat design)")
338+
331339
# Create production-quality PBR material
332340
mat = bpy.data.materials.new(name="MascotMaterial_PBR")
333341
mat.use_nodes = True
342+
mat.blend_method = 'BLEND' # Enable alpha transparency
343+
mat.shadow_method = 'CLIP' # Proper shadows with transparency
344+
mat.use_backface_culling = False # Render both sides
334345
nodes = mat.node_tree.nodes
335346
links = mat.node_tree.links
336347
mascot.data.materials.append(mat)
@@ -729,22 +740,28 @@ def setup_render_settings(self):
729740

730741
video_config = self.config.get('video', {})
731742

732-
# Render engine
733-
engine = video_config.get('render_engine', 'EEVEE')
743+
# Render engine - normalize config names to Blender names
744+
engine_config = video_config.get('render_engine', 'EEVEE')
745+
engine_map = {
746+
'EEVEE': 'BLENDER_EEVEE',
747+
'BLENDER_EEVEE': 'BLENDER_EEVEE',
748+
'CYCLES': 'CYCLES'
749+
}
750+
engine = engine_map.get(engine_config, 'BLENDER_EEVEE')
734751
self.scene.render.engine = engine
735752
print(f" Engine: {engine}")
736753

737754
# Samples
738755
samples = video_config.get('samples', 128)
739-
if engine == 'EEVEE':
756+
if engine_config == 'EEVEE' or engine == 'BLENDER_EEVEE':
740757
self.scene.eevee.taa_render_samples = samples
741758
# EEVEE quality settings
742759
self.scene.eevee.use_gtao = True # Ambient occlusion
743760
self.scene.eevee.use_bloom = True # Bloom
744761
self.scene.eevee.use_ssr = True # Screen space reflections
745762
self.scene.eevee.use_ssr_refraction = True
746763
self.scene.eevee.use_volumetric_shadows = True
747-
elif engine == 'CYCLES':
764+
elif engine_config == 'CYCLES' or engine == 'CYCLES':
748765
self.scene.cycles.samples = samples
749766
# Cycles quality settings
750767
self.scene.cycles.use_adaptive_sampling = True
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# Quick test config for 3D billboard mode (24 frames = 1 second)
2+
inputs:
3+
mascot_image: demo_reel/assets/demo_fox.png
4+
song_file: demo_reel/assets/demo_song.wav
5+
lyrics_file: demo_reel/assets/demo_lyrics.txt
6+
output:
7+
output_dir: demo_reel/3d_billboard_test
8+
video_name: 3d_billboard_test.mp4
9+
frames_dir: demo_reel/3d_billboard_test/frames
10+
prep_json: demo_reel/3d_billboard_test/prep_data.json
11+
video:
12+
duration: 1 # Just 1 second for quick test
13+
resolution: [720, 480] # Smaller for speed
14+
fps: 24
15+
render_engine: EEVEE
16+
samples: 32 # Lower samples for speed
17+
codec: libx264
18+
quality: high
19+
style:
20+
lighting: jazzy
21+
mascot: fox
22+
stage: true # Enable stage floor
23+
colors:
24+
primary: [0.95, 0.4, 0.2] # Orange
25+
secondary: [0.2, 0.6, 0.9] # Blue
26+
accent: [0.95, 0.85, 0.3] # Yellow
27+
background: gradient
28+
animation:
29+
mode: 3d # 3D mode with billboard plane!
30+
enable_lipsync: true
31+
enable_gestures: true
32+
enable_lyrics: true
33+
enable_effects: true
34+
gesture_intensity: 0.8
35+
lyrics_style: bounce
36+
effects:
37+
lights:
38+
spotlight:
39+
enabled: true
40+
intensity: 800
41+
color: [1.0, 0.95, 0.9]
42+
flashes:
43+
enabled: true
44+
intensity_range: [10, 20]
45+
random_colors: true
46+
# Basic PBR materials (not full production to keep it fast)
47+
materials:
48+
mascot:
49+
type: pbr
50+
roughness: 0.3
51+
metallic: 0.0
52+
specular: 0.5
53+
stage:
54+
type: pbr
55+
color: [0.15, 0.15, 0.18]
56+
roughness: 0.7
57+
metallic: 0.0
58+
rhubarb:
59+
executable_path: null
60+
use_mock_fallback: true
61+
advanced:
62+
preview_mode: false
63+
preview_scale: 1.0
64+
keep_intermediate: true
65+
verbose: true
66+
threads: null
67+
blender:
68+
executable_path: null
69+
background: true
70+
script_path: blender_script.py

demo_reel/config_hybrid_test.yaml

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Quick test config for hybrid mode (24 frames = 1 second)
2+
gp_style:
3+
stroke_thickness: 4
4+
ink_type: sketchy
5+
enable_wobble: true
6+
wobble_intensity: 0.6
7+
inputs:
8+
mascot_image: demo_reel/assets/demo_fox.png
9+
song_file: demo_reel/assets/demo_song.wav
10+
lyrics_file: demo_reel/assets/demo_lyrics.txt
11+
output:
12+
output_dir: demo_reel/hybrid_test
13+
video_name: hybrid_test.mp4
14+
frames_dir: demo_reel/hybrid_test/frames
15+
prep_json: demo_reel/hybrid_test/prep_data.json
16+
video:
17+
duration: 1 # Just 1 second for quick test
18+
resolution: [720, 480] # Smaller for speed
19+
fps: 24
20+
render_engine: EEVEE
21+
samples: 32 # Lower samples for speed
22+
codec: libx264
23+
quality: high
24+
style:
25+
lighting: jazzy
26+
mascot: fox
27+
colors:
28+
primary: [0.9, 0.2, 0.7]
29+
secondary: [0.2, 0.9, 0.9]
30+
accent: [0.9, 0.9, 0.2]
31+
background: gradient
32+
animation:
33+
mode: hybrid # 2D mascot on 3D stage!
34+
enable_lipsync: true
35+
enable_gestures: true
36+
enable_lyrics: true
37+
enable_effects: true
38+
gesture_intensity: 0.8
39+
lyrics_style: bounce
40+
effects:
41+
fog:
42+
enabled: true
43+
density: 0.03
44+
particles:
45+
enabled: false # Disable for speed
46+
lights:
47+
spotlight:
48+
enabled: true
49+
intensity: 800
50+
color: [1.0, 0.95, 0.9]
51+
flashes:
52+
enabled: true
53+
intensity_range: [10, 20]
54+
random_colors: true
55+
rhubarb:
56+
executable_path: null
57+
use_mock_fallback: true
58+
advanced:
59+
preview_mode: false
60+
preview_scale: 1.0
61+
keep_intermediate: true
62+
verbose: true
63+
threads: null
64+
blender:
65+
executable_path: null
66+
background: true
67+
script_path: blender_script.py

0 commit comments

Comments
 (0)