Skip to content

Commit b604d36

Browse files
authored
Add GLTF support. (#79)
1 parent be49db5 commit b604d36

File tree

12 files changed

+632
-8
lines changed

12 files changed

+632
-8
lines changed

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ path = "examples/pbr.rs"
8282
name = "midi"
8383
path = "examples/midi.rs"
8484

85+
[[example]]
86+
name = "gltf_load"
87+
path = "examples/gltf_load.rs"
88+
8589
[profile.wasm-release]
8690
inherits = "release"
8791
opt-level = "z"

assets/gltf/Duck.glb

118 KB
Binary file not shown.

crates/processing_ffi/src/lib.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -568,7 +568,16 @@ pub extern "C" fn processing_perspective(
568568
) {
569569
error::clear_error();
570570
let graphics_entity = Entity::from_bits(graphics_id);
571-
error::check(|| graphics_perspective(graphics_entity, fov, aspect, near, far));
571+
error::check(|| {
572+
graphics_perspective(
573+
graphics_entity,
574+
fov,
575+
aspect,
576+
near,
577+
far,
578+
bevy::math::Vec4::new(0.0, 0.0, -1.0, -near),
579+
)
580+
});
572581
}
573582

574583
#[unsafe(no_mangle)]
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import math
2+
from processing import *
3+
4+
gltf = None
5+
duck_geo = None
6+
duck_mat = None
7+
light = None
8+
frame = 0
9+
10+
def setup():
11+
global gltf, duck_geo, duck_mat, light
12+
size(800, 600)
13+
14+
gltf = load_gltf("gltf/Duck.glb")
15+
duck_geo = gltf.geometry("LOD3spShape")
16+
duck_mat = gltf.material("blinn3-fx")
17+
18+
mode_3d()
19+
gltf.camera(0)
20+
light = gltf.light(0)
21+
22+
def draw():
23+
global frame
24+
t = frame * 0.02
25+
26+
radius = 1.5
27+
lx = math.cos(t) * radius
28+
ly = 1.5
29+
lz = math.sin(t) * radius
30+
light.position(lx, ly, lz)
31+
light.look_at(0.0, 0.8, 0.0)
32+
33+
r = math.sin(t * 8.0) * 0.5 + 0.5
34+
g = math.sin(t * 8.0 + 2.0) * 0.5 + 0.5
35+
b = math.sin(t * 8.0 + 4.0) * 0.5 + 0.5
36+
duck_mat.set_float4("base_color", r, g, b, 1.0)
37+
38+
background(25)
39+
use_material(duck_mat)
40+
draw_geometry(duck_geo)
41+
42+
frame += 1
43+
44+
45+
# TODO: this should happen implicitly on module load somehow
46+
run()

crates/processing_pyo3/src/gltf.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
use bevy::prelude::Entity;
2+
use processing::prelude::*;
3+
use pyo3::{exceptions::PyRuntimeError, prelude::*};
4+
5+
use crate::graphics::{Geometry, Light, get_graphics};
6+
use crate::material::Material;
7+
8+
#[pyclass(unsendable)]
9+
pub struct Gltf {
10+
entity: Entity,
11+
}
12+
13+
#[pymethods]
14+
impl Gltf {
15+
pub fn geometry(&self, name: &str) -> PyResult<Geometry> {
16+
let entity = gltf_geometry(self.entity, name)
17+
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))?;
18+
Ok(Geometry { entity })
19+
}
20+
21+
pub fn material(&self, name: &str) -> PyResult<Material> {
22+
let entity = gltf_material(self.entity, name)
23+
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))?;
24+
Ok(Material { entity })
25+
}
26+
27+
pub fn mesh_names(&self) -> PyResult<Vec<String>> {
28+
gltf_mesh_names(self.entity).map_err(|e| PyRuntimeError::new_err(format!("{e}")))
29+
}
30+
31+
pub fn material_names(&self) -> PyResult<Vec<String>> {
32+
gltf_material_names(self.entity).map_err(|e| PyRuntimeError::new_err(format!("{e}")))
33+
}
34+
35+
pub fn camera(&self, index: usize) -> PyResult<()> {
36+
gltf_camera(self.entity, index).map_err(|e| PyRuntimeError::new_err(format!("{e}")))
37+
}
38+
39+
pub fn light(&self, index: usize) -> PyResult<Light> {
40+
let entity =
41+
gltf_light(self.entity, index).map_err(|e| PyRuntimeError::new_err(format!("{e}")))?;
42+
Ok(Light { entity })
43+
}
44+
}
45+
46+
#[pyfunction]
47+
#[pyo3(pass_module)]
48+
pub fn load_gltf(module: &Bound<'_, PyModule>, path: &str) -> PyResult<Gltf> {
49+
let graphics = get_graphics(module)?;
50+
let entity =
51+
gltf_load(graphics.entity, path).map_err(|e| PyRuntimeError::new_err(format!("{e}")))?;
52+
Ok(Gltf { entity })
53+
}

crates/processing_pyo3/src/graphics.rs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use bevy::math::Vec4;
12
use bevy::prelude::Entity;
23
use processing::prelude::*;
34
use pyo3::{exceptions::PyRuntimeError, prelude::*, types::PyDict};
@@ -26,7 +27,7 @@ impl Drop for Surface {
2627
#[pyclass]
2728
#[derive(Debug)]
2829
pub struct Light {
29-
entity: Entity,
30+
pub(crate) entity: Entity,
3031
}
3132

3233
#[pymethods]
@@ -62,7 +63,7 @@ impl Drop for Image {
6263

6364
#[pyclass(unsendable)]
6465
pub struct Geometry {
65-
entity: Entity,
66+
pub(crate) entity: Entity,
6667
}
6768

6869
#[pyclass]
@@ -132,7 +133,7 @@ impl Geometry {
132133

133134
#[pyclass(unsendable)]
134135
pub struct Graphics {
135-
entity: Entity,
136+
pub(crate) entity: Entity,
136137
pub surface: Surface,
137138
}
138139

@@ -357,8 +358,15 @@ impl Graphics {
357358
}
358359

359360
pub fn perspective(&self, fov: f32, aspect: f32, near: f32, far: f32) -> PyResult<()> {
360-
graphics_perspective(self.entity, fov, aspect, near, far)
361-
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
361+
graphics_perspective(
362+
self.entity,
363+
fov,
364+
aspect,
365+
near,
366+
far,
367+
Vec4::new(0.0, 0.0, -1.0, -near),
368+
)
369+
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
362370
}
363371

364372
#[allow(clippy::too_many_arguments)]

crates/processing_pyo3/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
//! To allow Python users to create a similar experience, we provide module-level
1010
//! functions that forward to a singleton Graphics object pub(crate) behind the scenes.
1111
mod glfw;
12+
mod gltf;
1213
mod graphics;
1314
pub(crate) mod material;
1415

@@ -21,6 +22,7 @@ use pyo3::{
2122
};
2223
use std::ffi::{CStr, CString};
2324

25+
use gltf::Gltf;
2426
use std::env;
2527

2628
#[pymodule]
@@ -30,6 +32,8 @@ fn processing(m: &Bound<'_, PyModule>) -> PyResult<()> {
3032
m.add_class::<Light>()?;
3133
m.add_class::<Topology>()?;
3234
m.add_class::<Material>()?;
35+
m.add_class::<Gltf>()?;
36+
m.add_function(wrap_pyfunction!(gltf::load_gltf, m)?)?;
3337
m.add_function(wrap_pyfunction!(size, m)?)?;
3438
m.add_function(wrap_pyfunction!(run, m)?)?;
3539
m.add_function(wrap_pyfunction!(mode_3d, m)?)?;

crates/processing_render/src/error.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,6 @@ pub enum ProcessingError {
3434
MaterialNotFound,
3535
#[error("Unknown material property: {0}")]
3636
UnknownMaterialProperty(String),
37+
#[error("GLTF load error: {0}")]
38+
GltfLoadError(String),
3739
}

0 commit comments

Comments
 (0)