Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/gltf-loader/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ animation = { path = "../animation" }
essential = { path = "../essential" }
ecs = { path = "../ecs" }
render = { path = "../render" }
gltf = { version = "1.4.1" }
gltf = { version = "1.4.1", features = ["KHR_lights_punctual"] }
anyhow = "1.0.97"
async-trait = "0.1.50"
glam = { version = "0.30.1" }
Expand Down
117 changes: 116 additions & 1 deletion crates/gltf-loader/src/loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@ use render::{
vertex::Vertex,
},
components::{
material_component::MaterialComponent, mesh_component::MeshComponent,
camera::Camera,
light::{Light, LightType, SpotLight},
material_component::MaterialComponent,
mesh_component::MeshComponent,
skeleton_component::SkeletonComponent,
},
};
Expand All @@ -54,6 +57,8 @@ pub struct GLTFScene {
pub(crate) animations: Vec<AssetHandle<AnimationClip>>,
pub(crate) target_id_to_node_idx: HashMap<Uuid, GLTFAnimationTargetInfo>,
pub(crate) animation_roots: HashSet<usize>,
pub(crate) cameras: Vec<GLTFCamera>,
pub(crate) lights: Vec<GLTFLight>,
}

impl GLTFScene {
Expand All @@ -72,6 +77,8 @@ pub struct GLTFNode {
pub(crate) mesh: Option<usize>,
pub(crate) skeleton: Option<usize>,
pub(crate) transform: Transform,
pub(crate) camera: Option<usize>,
pub(crate) light: Option<usize>,
}

pub struct GLTFSkeleton {
Expand All @@ -80,6 +87,34 @@ pub struct GLTFSkeleton {
pub(crate) root_bone: Option<usize>,
}

pub(crate) struct GLTFCamera {
pub(crate) fovy: f32,
pub(crate) znear: f32,
pub(crate) zfar: f32,
}

impl Default for GLTFCamera {
fn default() -> Self {
Self {
fovy: std::f32::consts::FRAC_PI_4,
znear: 0.1,
zfar: 100.0,
}
}
}

pub(crate) enum GLTFLightType {
Point,
Spot { cone_angle: f32 },
Directional,
}

pub(crate) struct GLTFLight {
pub(crate) color: Vec4,
pub(crate) intensity: f32,
pub(crate) light_type: GLTFLightType,
}

pub(crate) struct GLTFNodePathInfo {
pub(crate) root_node: usize,
pub(crate) node_path: Vec<Cow<'static, str>>,
Expand Down Expand Up @@ -337,6 +372,48 @@ impl AssetLoader for GLTFLoader {
animation_clips.push(load_context.asset_server().add(animation_clip));
}

let cameras: Vec<GLTFCamera> = document
.cameras()
.map(|cam| match cam.projection() {
gltf::camera::Projection::Perspective(p) => GLTFCamera {
fovy: p.yfov(),
znear: p.znear(),
zfar: p.zfar().unwrap_or(100.0),
},
gltf::camera::Projection::Orthographic(_) => {
warn!(
"Orthographic camera '{}' is not supported, using default perspective",
cam.name().unwrap_or("<unnamed>")
);
GLTFCamera::default()
}
})
.collect();

let lights: Vec<GLTFLight> = document
.lights()
.into_iter()
.flatten()
.map(|light| {
let [r, g, b] = light.color();
let color = Vec4::new(r, g, b, 1.0);
let light_type = match light.kind() {
gltf::khr_lights_punctual::Kind::Directional => GLTFLightType::Directional,
gltf::khr_lights_punctual::Kind::Point => GLTFLightType::Point,
gltf::khr_lights_punctual::Kind::Spot {
outer_cone_angle, ..
} => GLTFLightType::Spot {
cone_angle: outer_cone_angle,
},
};
GLTFLight {
color,
intensity: light.intensity(),
light_type,
}
})
.collect();

Ok(GLTFScene {
nodes,
meshes,
Expand All @@ -345,6 +422,8 @@ impl AssetLoader for GLTFLoader {
animations: animation_clips,
target_id_to_node_idx,
animation_roots,
cameras,
lights,
})
}
}
Expand Down Expand Up @@ -489,6 +568,8 @@ impl GLTFLoader {
mesh: gltf_node.mesh().map(|mesh| mesh.index()),
transform: Transform::from_matrix(&gltf_transform.matrix()),
skeleton: gltf_node.skin().map(|skin| skin.index()),
camera: gltf_node.camera().map(|c| c.index()),
light: gltf_node.light().map(|l| l.index()),
}
}
}
Expand Down Expand Up @@ -607,6 +688,40 @@ pub(crate) fn spawn_gltf_components(
if asset.animation_roots.contains(&node_index) {
cmd.insert(AnimationPlayer::default(), node_entities[node_index]);
}

if let Some(camera_index) = gltf_node.camera {
if let Some(gltf_camera) = asset.cameras.get(camera_index) {
cmd.insert(
Camera {
fovy: gltf_camera.fovy,
znear: gltf_camera.znear,
zfar: gltf_camera.zfar,
..Camera::default()
},
node_entities[node_index],
);
}
}

if let Some(light_index) = gltf_node.light {
if let Some(gltf_light) = asset.lights.get(light_index) {
let light_type = match &gltf_light.light_type {
GLTFLightType::Point => LightType::Point,
GLTFLightType::Spot { cone_angle } => LightType::Spot(SpotLight {
cone_angle: *cone_angle,
}),
GLTFLightType::Directional => LightType::Directional,
};
cmd.insert(
Light {
color: gltf_light.color,
intensity: gltf_light.intensity,
light_type,
},
node_entities[node_index],
);
}
}
}

// Insert animation target components
Expand Down
Loading