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.
This commit is contained in:
Robert Swain 2022-01-03 07:59:25 +00:00
parent d44c3cd150
commit 85b7589388
8 changed files with 72 additions and 10 deletions

View File

@ -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"

View File

@ -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) {

View File

@ -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<M: SpecializedMaterial> Default for MaterialMeshBundle<M> {
}
}
#[derive(Component, Clone, Debug, Default)]
#[derive(Component, Clone, Debug, Default, Reflect)]
#[reflect(Component)]
pub struct CubemapVisibleEntities {
#[reflect(ignore)]
data: [VisibleEntities; 6],
}

View File

@ -67,7 +67,10 @@ impl Plugin for PbrPlugin {
Shader::from_wgsl(include_str!("render/depth.wgsl")),
);
app.add_plugin(MeshRenderPlugin)
app.register_type::<CubemapVisibleEntities>()
.register_type::<DirectionalLight>()
.register_type::<PointLight>()
.add_plugin(MeshRenderPlugin)
.add_plugin(MaterialPlugin::<StandardMaterial>::default())
.init_resource::<AmbientLight>()
.init_resource::<DirectionalLightShadowMap>()

View File

@ -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,000100,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

View File

@ -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<Color> for Vec4 {
fn from(color: Color) -> Self {
let color: [f32; 4] = color.into();

View File

@ -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::<ShaderLoader>()
.init_resource::<ScratchRenderWorld>()
.register_type::<Color>()
.register_type::<Frustum>();
.register_type::<Frustum>()
.register_type::<CubemapFrusta>();
let render_pipeline_cache = RenderPipelineCache::new(device.clone());
let asset_server = app.world.get_resource::<AssetServer>().unwrap().clone();

View File

@ -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],
}