glTF model loading
This commit is contained in:
parent
8636e766f8
commit
544c44ca31
8 changed files with 8601 additions and 9 deletions
240
tests/demo/screens/model_loading_demo.py
Normal file
240
tests/demo/screens/model_loading_demo.py
Normal file
|
|
@ -0,0 +1,240 @@
|
|||
# model_loading_demo.py - Visual demo of Model3D model loading
|
||||
# Shows both procedural primitives and loaded .glb models
|
||||
|
||||
import mcrfpy
|
||||
import sys
|
||||
import math
|
||||
import os
|
||||
|
||||
# Create demo scene
|
||||
scene = mcrfpy.Scene("model_loading_demo")
|
||||
|
||||
# Dark background frame
|
||||
bg = mcrfpy.Frame(pos=(0, 0), size=(1024, 768), fill_color=mcrfpy.Color(15, 15, 25))
|
||||
scene.children.append(bg)
|
||||
|
||||
# Title
|
||||
title = mcrfpy.Caption(text="Model3D Demo - Procedural & glTF Models", pos=(20, 10))
|
||||
title.fill_color = mcrfpy.Color(255, 255, 255)
|
||||
scene.children.append(title)
|
||||
|
||||
# Create the 3D viewport
|
||||
viewport = mcrfpy.Viewport3D(
|
||||
pos=(50, 60),
|
||||
size=(600, 450),
|
||||
# render_resolution=(320, 240), # PS1 resolution
|
||||
render_resolution=(600,450),
|
||||
fov=60.0,
|
||||
camera_pos=(0.0, 3.0, 8.0),
|
||||
camera_target=(0.0, 1.0, 0.0),
|
||||
bg_color=mcrfpy.Color(30, 30, 50)
|
||||
)
|
||||
scene.children.append(viewport)
|
||||
|
||||
# Set up navigation grid
|
||||
GRID_SIZE = 32
|
||||
viewport.set_grid_size(GRID_SIZE, GRID_SIZE)
|
||||
|
||||
# Build a simple flat floor
|
||||
hm = mcrfpy.HeightMap((GRID_SIZE, GRID_SIZE))
|
||||
hm.normalize(0.0, 0.0)
|
||||
viewport.apply_heightmap(hm, 0.0)
|
||||
vertex_count = viewport.build_terrain(
|
||||
layer_name="floor",
|
||||
heightmap=hm,
|
||||
y_scale=0.0,
|
||||
cell_size=1.0
|
||||
)
|
||||
|
||||
# Apply floor colors (checkerboard pattern)
|
||||
r_map = mcrfpy.HeightMap((GRID_SIZE, GRID_SIZE))
|
||||
g_map = mcrfpy.HeightMap((GRID_SIZE, GRID_SIZE))
|
||||
b_map = mcrfpy.HeightMap((GRID_SIZE, GRID_SIZE))
|
||||
|
||||
for y in range(GRID_SIZE):
|
||||
for x in range(GRID_SIZE):
|
||||
checker = ((x + y) % 2) * 0.1 + 0.15
|
||||
r_map[x, y] = checker
|
||||
g_map[x, y] = checker
|
||||
b_map[x, y] = checker + 0.05
|
||||
|
||||
viewport.apply_terrain_colors("floor", r_map, g_map, b_map)
|
||||
|
||||
# Create procedural models
|
||||
print("Creating procedural models...")
|
||||
cube_model = mcrfpy.Model3D.cube(1.0)
|
||||
sphere_model = mcrfpy.Model3D.sphere(0.5, 12, 8)
|
||||
|
||||
# Try to load glTF models
|
||||
loaded_models = {}
|
||||
models_dir = "../assets/models"
|
||||
if os.path.exists(models_dir):
|
||||
for filename in ["Duck.glb", "Box.glb", "Lantern.glb", "WaterBottle.glb"]:
|
||||
path = os.path.join(models_dir, filename)
|
||||
if os.path.exists(path):
|
||||
try:
|
||||
model = mcrfpy.Model3D(path)
|
||||
loaded_models[filename] = model
|
||||
print(f"Loaded {filename}: {model.vertex_count} verts, {model.triangle_count} tris")
|
||||
except Exception as e:
|
||||
print(f"Failed to load {filename}: {e}")
|
||||
|
||||
# Create entities with different models
|
||||
entities = []
|
||||
|
||||
# Row 1: Procedural primitives
|
||||
entity_configs = [
|
||||
((12, 16), cube_model, 1.0, mcrfpy.Color(255, 100, 100), "Cube"),
|
||||
((16, 16), sphere_model, 1.0, mcrfpy.Color(100, 255, 100), "Sphere"),
|
||||
((20, 16), None, 1.0, mcrfpy.Color(200, 200, 200), "Placeholder"),
|
||||
]
|
||||
|
||||
# Row 2: Loaded glTF models (if available)
|
||||
if "Duck.glb" in loaded_models:
|
||||
# Duck is huge (~160 units), scale it down significantly
|
||||
entity_configs.append(((14, 12), loaded_models["Duck.glb"], 0.006, mcrfpy.Color(255, 200, 50), "Duck"))
|
||||
|
||||
if "Box.glb" in loaded_models:
|
||||
entity_configs.append(((16, 12), loaded_models["Box.glb"], 1.5, mcrfpy.Color(150, 100, 50), "Box (glb)"))
|
||||
|
||||
if "Lantern.glb" in loaded_models:
|
||||
# Lantern is ~25 units tall
|
||||
entity_configs.append(((18, 12), loaded_models["Lantern.glb"], 0.08, mcrfpy.Color(255, 200, 100), "Lantern"))
|
||||
|
||||
if "WaterBottle.glb" in loaded_models:
|
||||
# WaterBottle is ~0.26 units tall
|
||||
entity_configs.append(((20, 12), loaded_models["WaterBottle.glb"], 4.0, mcrfpy.Color(100, 150, 255), "Bottle"))
|
||||
|
||||
for pos, model, scale, color, name in entity_configs:
|
||||
e = mcrfpy.Entity3D(pos=pos, scale=scale, color=color)
|
||||
if model:
|
||||
e.model = model
|
||||
viewport.entities.append(e)
|
||||
entities.append((e, name, model))
|
||||
|
||||
print(f"Created {len(entities)} entities")
|
||||
|
||||
# Info panel on the right
|
||||
info_panel = mcrfpy.Frame(pos=(670, 60), size=(330, 450),
|
||||
fill_color=mcrfpy.Color(30, 30, 40),
|
||||
outline_color=mcrfpy.Color(80, 80, 100),
|
||||
outline=2.0)
|
||||
scene.children.append(info_panel)
|
||||
|
||||
# Panel title
|
||||
panel_title = mcrfpy.Caption(text="Model Information", pos=(690, 70))
|
||||
panel_title.fill_color = mcrfpy.Color(200, 200, 255)
|
||||
scene.children.append(panel_title)
|
||||
|
||||
# Model info labels
|
||||
y_offset = 100
|
||||
for e, name, model in entities:
|
||||
if model:
|
||||
info = f"{name}: {model.vertex_count}v, {model.triangle_count}t"
|
||||
else:
|
||||
info = f"{name}: Placeholder (36v, 12t)"
|
||||
label = mcrfpy.Caption(text=info, pos=(690, y_offset))
|
||||
label.fill_color = e.color
|
||||
scene.children.append(label)
|
||||
y_offset += 22
|
||||
|
||||
# Separator
|
||||
y_offset += 10
|
||||
sep = mcrfpy.Caption(text="--- glTF Support ---", pos=(690, y_offset))
|
||||
sep.fill_color = mcrfpy.Color(150, 150, 150)
|
||||
scene.children.append(sep)
|
||||
y_offset += 22
|
||||
|
||||
# glTF info
|
||||
gltf_info = [
|
||||
"Format: glTF 2.0 (.glb, .gltf)",
|
||||
"Library: cgltf (C99)",
|
||||
f"Loaded models: {len(loaded_models)}",
|
||||
]
|
||||
for info in gltf_info:
|
||||
label = mcrfpy.Caption(text=info, pos=(690, y_offset))
|
||||
label.fill_color = mcrfpy.Color(150, 150, 170)
|
||||
scene.children.append(label)
|
||||
y_offset += 20
|
||||
|
||||
# Instructions at bottom
|
||||
instructions = mcrfpy.Caption(
|
||||
text="[Space] Toggle rotation | [1-3] Camera presets | [ESC] Quit",
|
||||
pos=(20, 530)
|
||||
)
|
||||
instructions.fill_color = mcrfpy.Color(150, 150, 150)
|
||||
scene.children.append(instructions)
|
||||
|
||||
# Status line
|
||||
status = mcrfpy.Caption(text="Status: Showing procedural and glTF models", pos=(20, 555))
|
||||
status.fill_color = mcrfpy.Color(100, 200, 100)
|
||||
scene.children.append(status)
|
||||
|
||||
# Animation state
|
||||
animation_time = [0.0]
|
||||
rotate_entities = [True]
|
||||
|
||||
# Camera presets
|
||||
camera_presets = [
|
||||
((0.0, 5.0, 12.0), (0.0, 1.0, 0.0), "Front view"),
|
||||
((12.0, 8.0, 0.0), (0.0, 1.0, 0.0), "Side view"),
|
||||
((0.0, 15.0, 0.1), (0.0, 0.0, 0.0), "Top-down view"),
|
||||
]
|
||||
current_preset = [0]
|
||||
|
||||
# Update function
|
||||
def update(timer, runtime):
|
||||
animation_time[0] += runtime / 1000.0
|
||||
|
||||
if rotate_entities[0]:
|
||||
for i, (e, name, model) in enumerate(entities):
|
||||
e.rotation = (animation_time[0] * 30.0 + i * 45.0) % 360.0
|
||||
|
||||
# Key handler
|
||||
def on_key(key, state):
|
||||
if state != mcrfpy.InputState.PRESSED:
|
||||
return
|
||||
|
||||
if key == mcrfpy.Key.SPACE:
|
||||
rotate_entities[0] = not rotate_entities[0]
|
||||
status.text = f"Rotation: {'ON' if rotate_entities[0] else 'OFF'}"
|
||||
|
||||
elif key == mcrfpy.Key.NUM_1:
|
||||
pos, target, name = camera_presets[0]
|
||||
viewport.camera_pos = pos
|
||||
viewport.camera_target = target
|
||||
status.text = f"Camera: {name}"
|
||||
|
||||
elif key == mcrfpy.Key.NUM_2:
|
||||
pos, target, name = camera_presets[1]
|
||||
viewport.camera_pos = pos
|
||||
viewport.camera_target = target
|
||||
status.text = f"Camera: {name}"
|
||||
|
||||
elif key == mcrfpy.Key.NUM_3:
|
||||
pos, target, name = camera_presets[2]
|
||||
viewport.camera_pos = pos
|
||||
viewport.camera_target = target
|
||||
status.text = f"Camera: {name}"
|
||||
|
||||
elif key == mcrfpy.Key.ESCAPE:
|
||||
mcrfpy.exit()
|
||||
|
||||
# Set up scene
|
||||
scene.on_key = on_key
|
||||
|
||||
# Create timer for updates
|
||||
timer = mcrfpy.Timer("model_update", update, 16)
|
||||
|
||||
# Activate scene
|
||||
mcrfpy.current_scene = scene
|
||||
|
||||
print()
|
||||
print("Model3D Demo loaded!")
|
||||
print(f"Procedural models: cube, sphere")
|
||||
print(f"glTF models loaded: {list(loaded_models.keys())}")
|
||||
print()
|
||||
print("Controls:")
|
||||
print(" [Space] Toggle rotation")
|
||||
print(" [1-3] Camera presets")
|
||||
print(" [ESC] Quit")
|
||||
Loading…
Add table
Add a link
Reference in a new issue