From b081b802cb3f16e0b0eb3d02a62d20470817c182 Mon Sep 17 00:00:00 2001 From: Robert Swain Date: Mon, 3 Jan 2022 03:28:17 +0000 Subject: [PATCH] bevy_gltf: Add support for loading lights (#3506) # Objective - Add support for loading lights from glTF 2.0 files ## Solution - This adds support for the KHR_punctual_lights extension which supports point, directional, and spot lights, though we don't yet support spot lights. - Inserting light bundles when creating scenes required registering some more light bundle component types. --- crates/bevy_gltf/Cargo.toml | 7 +++- crates/bevy_gltf/src/loader.rs | 41 +++++++++++++++++++++++- crates/bevy_pbr/src/bundle.rs | 7 ++-- crates/bevy_pbr/src/lib.rs | 5 ++- crates/bevy_pbr/src/light.rs | 7 ++-- crates/bevy_render/src/color/mod.rs | 6 ++++ crates/bevy_render/src/lib.rs | 5 +-- crates/bevy_render/src/primitives/mod.rs | 4 ++- 8 files changed, 72 insertions(+), 10 deletions(-) diff --git a/crates/bevy_gltf/Cargo.toml b/crates/bevy_gltf/Cargo.toml index f3941d045d722..bb79f962b2eb4 100644 --- a/crates/bevy_gltf/Cargo.toml +++ b/crates/bevy_gltf/Cargo.toml @@ -24,7 +24,12 @@ bevy_scene = { path = "../bevy_scene", version = "0.5.0" } bevy_log = { path = "../bevy_log", version = "0.5.0" } # other -gltf = { version = "0.16.0", default-features = false, features = ["utils", "names", "KHR_materials_unlit"] } +gltf = { version = "0.16.0", default-features = false, features = [ + "KHR_lights_punctual", + "KHR_materials_unlit", + "names", + "utils", +] } thiserror = "1.0" anyhow = "1.0.4" base64 = "0.13.0" diff --git a/crates/bevy_gltf/src/loader.rs b/crates/bevy_gltf/src/loader.rs index e8b4ffb5874b9..0669ca833a629 100644 --- a/crates/bevy_gltf/src/loader.rs +++ b/crates/bevy_gltf/src/loader.rs @@ -6,7 +6,10 @@ use bevy_core::Name; use bevy_ecs::world::World; use bevy_log::warn; use bevy_math::{Mat4, Vec3}; -use bevy_pbr::{AlphaMode, PbrBundle, StandardMaterial}; +use bevy_pbr::{ + AlphaMode, DirectionalLight, DirectionalLightBundle, PbrBundle, PointLight, PointLightBundle, + StandardMaterial, +}; use bevy_render::{ camera::{ Camera, CameraPlugin, CameraProjection, OrthographicProjection, PerspectiveProjection, @@ -550,6 +553,42 @@ fn load_node( } } + if let Some(light) = gltf_node.light() { + match light.kind() { + gltf::khr_lights_punctual::Kind::Directional => { + parent.spawn_bundle(DirectionalLightBundle { + directional_light: DirectionalLight { + color: Color::from(light.color()), + // NOTE: KHR_punctual_lights defines the intensity units for directional + // lights in lux (lm/m^2) which is what we need. + illuminance: light.intensity(), + ..Default::default() + }, + ..Default::default() + }); + } + gltf::khr_lights_punctual::Kind::Point => { + parent.spawn_bundle(PointLightBundle { + point_light: PointLight { + color: Color::from(light.color()), + // NOTE: KHR_punctual_lights defines the intensity units for point lights in + // candela (lm/sr) which is luminous intensity and we need luminous power. + // For a point light, luminous power = 4 * pi * luminous intensity + intensity: light.intensity() * std::f32::consts::PI * 4.0, + range: light.range().unwrap_or(20.0), + radius: light.range().unwrap_or(0.0), + ..Default::default() + }, + ..Default::default() + }); + } + gltf::khr_lights_punctual::Kind::Spot { + inner_cone_angle: _inner_cone_angle, + outer_cone_angle: _outer_cone_angle, + } => warn!("Spot lights are not yet supported."), + } + } + // append other nodes for child in gltf_node.children() { if let Err(err) = load_node(&child, parent, load_context, buffer_data) { diff --git a/crates/bevy_pbr/src/bundle.rs b/crates/bevy_pbr/src/bundle.rs index 32446cfa87d65..ba235c56b5791 100644 --- a/crates/bevy_pbr/src/bundle.rs +++ b/crates/bevy_pbr/src/bundle.rs @@ -1,6 +1,7 @@ use crate::{DirectionalLight, PointLight, SpecializedMaterial, StandardMaterial}; use bevy_asset::Handle; -use bevy_ecs::{bundle::Bundle, component::Component}; +use bevy_ecs::{bundle::Bundle, component::Component, reflect::ReflectComponent}; +use bevy_reflect::Reflect; use bevy_render::{ mesh::Mesh, primitives::{CubemapFrusta, Frustum}, @@ -37,8 +38,10 @@ impl Default for MaterialMeshBundle { } } -#[derive(Component, Clone, Debug, Default)] +#[derive(Component, Clone, Debug, Default, Reflect)] +#[reflect(Component)] pub struct CubemapVisibleEntities { + #[reflect(ignore)] data: [VisibleEntities; 6], } diff --git a/crates/bevy_pbr/src/lib.rs b/crates/bevy_pbr/src/lib.rs index 2e4fddbc821bd..78324f02bfbe7 100644 --- a/crates/bevy_pbr/src/lib.rs +++ b/crates/bevy_pbr/src/lib.rs @@ -67,7 +67,10 @@ impl Plugin for PbrPlugin { Shader::from_wgsl(include_str!("render/depth.wgsl")), ); - app.add_plugin(MeshRenderPlugin) + app.register_type::() + .register_type::() + .register_type::() + .add_plugin(MeshRenderPlugin) .add_plugin(MaterialPlugin::::default()) .init_resource::() .init_resource::() diff --git a/crates/bevy_pbr/src/light.rs b/crates/bevy_pbr/src/light.rs index f77501bb93cfb..ad36ee3423afc 100644 --- a/crates/bevy_pbr/src/light.rs +++ b/crates/bevy_pbr/src/light.rs @@ -2,6 +2,7 @@ use std::collections::HashSet; use bevy_ecs::prelude::*; use bevy_math::{Mat4, UVec2, UVec3, Vec2, Vec3, Vec3Swizzles, Vec4, Vec4Swizzles}; +use bevy_reflect::Reflect; use bevy_render::{ camera::{Camera, CameraProjection, OrthographicProjection}, color::Color, @@ -33,7 +34,8 @@ use crate::{ /// | 4000 | 300 | | 75-100 | 40.5 | /// /// Source: [Wikipedia](https://en.wikipedia.org/wiki/Lumen_(unit)#Lighting) -#[derive(Component, Debug, Clone, Copy)] +#[derive(Component, Debug, Clone, Copy, Reflect)] +#[reflect(Component)] pub struct PointLight { pub color: Color, pub intensity: f32, @@ -104,7 +106,8 @@ impl Default for PointLightShadowMap { /// | 32,000–100,000 | Direct sunlight | /// /// Source: [Wikipedia](https://en.wikipedia.org/wiki/Lux) -#[derive(Component, Debug, Clone)] +#[derive(Component, Debug, Clone, Reflect)] +#[reflect(Component)] pub struct DirectionalLight { pub color: Color, /// Illuminance in lux diff --git a/crates/bevy_render/src/color/mod.rs b/crates/bevy_render/src/color/mod.rs index f4e770d55f2a7..38ac48bce31f7 100644 --- a/crates/bevy_render/src/color/mod.rs +++ b/crates/bevy_render/src/color/mod.rs @@ -617,6 +617,12 @@ impl From<[f32; 4]> for Color { } } +impl From<[f32; 3]> for Color { + fn from([r, g, b]: [f32; 3]) -> Self { + Color::rgb(r, g, b) + } +} + impl From for Vec4 { fn from(color: Color) -> Self { let color: [f32; 4] = color.into(); diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index 74194ee9f393d..9e3b4a89a5a4a 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -33,7 +33,7 @@ use crate::{ camera::CameraPlugin, color::Color, mesh::MeshPlugin, - primitives::Frustum, + primitives::{CubemapFrusta, Frustum}, render_graph::RenderGraph, render_resource::{RenderPipelineCache, Shader, ShaderLoader}, renderer::render_system, @@ -141,7 +141,8 @@ impl Plugin for RenderPlugin { .init_asset_loader::() .init_resource::() .register_type::() - .register_type::(); + .register_type::() + .register_type::(); let render_pipeline_cache = RenderPipelineCache::new(device.clone()); let asset_server = app.world.get_resource::().unwrap().clone(); diff --git a/crates/bevy_render/src/primitives/mod.rs b/crates/bevy_render/src/primitives/mod.rs index deb38d3278670..623abd0d1801c 100644 --- a/crates/bevy_render/src/primitives/mod.rs +++ b/crates/bevy_render/src/primitives/mod.rs @@ -144,8 +144,10 @@ impl Frustum { } } -#[derive(Component, Debug, Default)] +#[derive(Component, Debug, Default, Reflect)] +#[reflect(Component)] pub struct CubemapFrusta { + #[reflect(ignore)] pub frusta: [Frustum; 6], }