Skip to content

Commit 2794d13

Browse files
tychedeliacatilac
andauthored
PBR Materials (#75)
Co-authored-by: Moon Davé <moon@softmoon.world>
1 parent c215696 commit 2794d13

File tree

21 files changed

+958
-58
lines changed

21 files changed

+958
-58
lines changed

Cargo.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,14 @@ path = "examples/custom_attribute.rs"
6868
name = "lights"
6969
path = "examples/lights.rs"
7070

71+
[[example]]
72+
name = "materials"
73+
path = "examples/materials.rs"
74+
75+
[[example]]
76+
name = "pbr"
77+
path = "examples/pbr.rs"
78+
7179
[profile.wasm-release]
7280
inherits = "release"
7381
opt-level = "z"

crates/processing_ffi/src/lib.rs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1092,6 +1092,14 @@ pub extern "C" fn processing_geometry_box(width: f32, height: f32, depth: f32) -
10921092
.unwrap_or(0)
10931093
}
10941094

1095+
#[unsafe(no_mangle)]
1096+
pub extern "C" fn processing_geometry_sphere(radius: f32, sectors: u32, stacks: u32) -> u64 {
1097+
error::clear_error();
1098+
error::check(|| geometry_sphere(radius, sectors, stacks))
1099+
.map(|e| e.to_bits())
1100+
.unwrap_or(0)
1101+
}
1102+
10951103
#[unsafe(no_mangle)]
10961104
pub extern "C" fn processing_light_create_directional(
10971105
graphics_id: u64,
@@ -1146,3 +1154,70 @@ pub extern "C" fn processing_light_create_spot(
11461154
.map(|e| e.to_bits())
11471155
.unwrap_or(0)
11481156
}
1157+
1158+
#[unsafe(no_mangle)]
1159+
pub extern "C" fn processing_material_create_pbr() -> u64 {
1160+
error::clear_error();
1161+
error::check(material_create_pbr)
1162+
.map(|e| e.to_bits())
1163+
.unwrap_or(0)
1164+
}
1165+
1166+
/// Set float value for `name` field on Material.
1167+
///
1168+
/// # Safety
1169+
/// - `name` must be non-null
1170+
#[unsafe(no_mangle)]
1171+
pub unsafe extern "C" fn processing_material_set_float(
1172+
mat_id: u64,
1173+
name: *const std::ffi::c_char,
1174+
value: f32,
1175+
) {
1176+
error::clear_error();
1177+
let name = unsafe { std::ffi::CStr::from_ptr(name) }.to_str().unwrap();
1178+
error::check(|| {
1179+
material_set(
1180+
Entity::from_bits(mat_id),
1181+
name,
1182+
material::MaterialValue::Float(value),
1183+
)
1184+
});
1185+
}
1186+
1187+
/// Set float4 value for `name` field on Material.
1188+
///
1189+
/// # Safety
1190+
/// - `name` must be non-null
1191+
#[unsafe(no_mangle)]
1192+
pub unsafe extern "C" fn processing_material_set_float4(
1193+
mat_id: u64,
1194+
name: *const std::ffi::c_char,
1195+
r: f32,
1196+
g: f32,
1197+
b: f32,
1198+
a: f32,
1199+
) {
1200+
error::clear_error();
1201+
let name = unsafe { std::ffi::CStr::from_ptr(name) }.to_str().unwrap();
1202+
error::check(|| {
1203+
material_set(
1204+
Entity::from_bits(mat_id),
1205+
name,
1206+
material::MaterialValue::Float4([r, g, b, a]),
1207+
)
1208+
});
1209+
}
1210+
1211+
#[unsafe(no_mangle)]
1212+
pub extern "C" fn processing_material_destroy(mat_id: u64) {
1213+
error::clear_error();
1214+
error::check(|| material_destroy(Entity::from_bits(mat_id)));
1215+
}
1216+
1217+
#[unsafe(no_mangle)]
1218+
pub extern "C" fn processing_material(window_id: u64, mat_id: u64) {
1219+
error::clear_error();
1220+
let window_entity = Entity::from_bits(window_id);
1221+
let mat_entity = Entity::from_bits(mat_id);
1222+
error::check(|| graphics_record_command(window_entity, DrawCommand::Material(mat_entity)));
1223+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
from processing import *
2+
3+
mat = None
4+
5+
def setup():
6+
global mat
7+
size(800, 600)
8+
mode_3d()
9+
10+
dir_light = create_directional_light(1.0, 0.98, 0.95, 1500.0)
11+
point_light = create_point_light(1.0, 1.0, 1.0, 100000.0, 800.0, 0.0)
12+
point_light.position(200.0, 200.0, 400.0)
13+
14+
mat = Material()
15+
mat.set_float("roughness", 0.3)
16+
mat.set_float("metallic", 0.8)
17+
mat.set_float4("base_color", 1.0, 0.85, 0.57, 1.0)
18+
19+
def draw():
20+
camera_position(0.0, 0.0, 200.0)
21+
camera_look_at(0.0, 0.0, 0.0)
22+
background(12, 12, 18)
23+
24+
use_material(mat)
25+
draw_sphere(50.0)
26+
27+
run()

crates/processing_pyo3/src/graphics.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,11 +293,23 @@ impl Graphics {
293293
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
294294
}
295295

296+
pub fn draw_sphere(&self, radius: f32, sectors: u32, stacks: u32) -> PyResult<()> {
297+
let sphere_geo = geometry_sphere(radius, sectors, stacks)
298+
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))?;
299+
graphics_record_command(self.entity, DrawCommand::Geometry(sphere_geo))
300+
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
301+
}
302+
296303
pub fn draw_geometry(&self, geometry: &Geometry) -> PyResult<()> {
297304
graphics_record_command(self.entity, DrawCommand::Geometry(geometry.entity))
298305
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
299306
}
300307

308+
pub fn use_material(&self, material: &crate::material::Material) -> PyResult<()> {
309+
graphics_record_command(self.entity, DrawCommand::Material(material.entity))
310+
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
311+
}
312+
301313
pub fn scale(&self, x: f32, y: f32) -> PyResult<()> {
302314
graphics_record_command(self.entity, DrawCommand::Scale { x, y })
303315
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
@@ -313,6 +325,11 @@ impl Graphics {
313325
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
314326
}
315327

328+
pub fn set_material(&self, material: &crate::material::Material) -> PyResult<()> {
329+
graphics_record_command(self.entity, DrawCommand::Material(material.entity))
330+
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
331+
}
332+
316333
pub fn begin_draw(&self) -> PyResult<()> {
317334
graphics_begin_draw(self.entity).map_err(|e| PyRuntimeError::new_err(format!("{e}")))
318335
}

crates/processing_pyo3/src/lib.rs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@
1010
//! functions that forward to a singleton Graphics object pub(crate) behind the scenes.
1111
mod glfw;
1212
mod graphics;
13+
pub(crate) mod material;
1314

1415
use graphics::{Geometry, Graphics, Image, Light, Topology, get_graphics, get_graphics_mut};
16+
use material::Material;
1517
use pyo3::{
1618
exceptions::PyRuntimeError,
1719
prelude::*,
@@ -27,6 +29,7 @@ fn processing(m: &Bound<'_, PyModule>) -> PyResult<()> {
2729
m.add_class::<Image>()?;
2830
m.add_class::<Light>()?;
2931
m.add_class::<Topology>()?;
32+
m.add_class::<Material>()?;
3033
m.add_function(wrap_pyfunction!(size, m)?)?;
3134
m.add_function(wrap_pyfunction!(run, m)?)?;
3235
m.add_function(wrap_pyfunction!(mode_3d, m)?)?;
@@ -48,6 +51,8 @@ fn processing(m: &Bound<'_, PyModule>) -> PyResult<()> {
4851
m.add_function(wrap_pyfunction!(create_directional_light, m)?)?;
4952
m.add_function(wrap_pyfunction!(create_point_light, m)?)?;
5053
m.add_function(wrap_pyfunction!(create_spot_light, m)?)?;
54+
m.add_function(wrap_pyfunction!(draw_sphere, m)?)?;
55+
m.add_function(wrap_pyfunction!(use_material, m)?)?;
5156

5257
Ok(())
5358
}
@@ -112,7 +117,7 @@ fn run(module: &Bound<'_, PyModule>) -> PyResult<()> {
112117
let builtins = PyModule::import(py, "builtins")?;
113118
let locals = builtins.getattr("locals")?.call0()?;
114119

115-
let mut setup_fn = locals.get_item("setup")?;
120+
let setup_fn = locals.get_item("setup")?;
116121
let mut draw_fn = locals.get_item("draw")?;
117122

118123
// call setup
@@ -140,7 +145,7 @@ fn run(module: &Bound<'_, PyModule>) -> PyResult<()> {
140145
}
141146
}
142147

143-
setup_fn = locals.get_item("setup").unwrap().unwrap();
148+
// setup_fn = locals.get_item("setup").unwrap().unwrap();
144149
draw_fn = locals.get_item("draw").unwrap().unwrap();
145150

146151
dbg!(locals);
@@ -320,3 +325,20 @@ fn create_spot_light(
320325
) -> PyResult<Light> {
321326
get_graphics(module)?.light_spot(r, g, b, intensity, range, radius, inner_angle, outer_angle)
322327
}
328+
329+
#[pyfunction]
330+
#[pyo3(pass_module, signature = (radius, sectors=32, stacks=18))]
331+
fn draw_sphere(
332+
module: &Bound<'_, PyModule>,
333+
radius: f32,
334+
sectors: u32,
335+
stacks: u32,
336+
) -> PyResult<()> {
337+
get_graphics(module)?.draw_sphere(radius, sectors, stacks)
338+
}
339+
340+
#[pyfunction]
341+
#[pyo3(pass_module, signature = (material))]
342+
fn use_material(module: &Bound<'_, PyModule>, material: &Bound<'_, Material>) -> PyResult<()> {
343+
get_graphics(module)?.use_material(&*material.extract::<PyRef<Material>>()?)
344+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
use bevy::prelude::Entity;
2+
use processing::prelude::*;
3+
use pyo3::{exceptions::PyRuntimeError, prelude::*};
4+
5+
#[pyclass(unsendable)]
6+
pub struct Material {
7+
pub(crate) entity: Entity,
8+
}
9+
10+
#[pymethods]
11+
impl Material {
12+
#[new]
13+
pub fn new() -> PyResult<Self> {
14+
let entity = material_create_pbr().map_err(|e| PyRuntimeError::new_err(format!("{e}")))?;
15+
Ok(Self { entity })
16+
}
17+
18+
pub fn set_float(&self, name: &str, value: f32) -> PyResult<()> {
19+
material_set(self.entity, name, material::MaterialValue::Float(value))
20+
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
21+
}
22+
23+
pub fn set_float4(&self, name: &str, r: f32, g: f32, b: f32, a: f32) -> PyResult<()> {
24+
material_set(
25+
self.entity,
26+
name,
27+
material::MaterialValue::Float4([r, g, b, a]),
28+
)
29+
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
30+
}
31+
}
32+
33+
impl Drop for Material {
34+
fn drop(&mut self) {
35+
let _ = material_destroy(self.entity);
36+
}
37+
}

crates/processing_render/src/error.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,8 @@ pub enum ProcessingError {
3030
LayoutNotFound,
3131
#[error("Transform not found")]
3232
TransformNotFound,
33+
#[error("Material not found")]
34+
MaterialNotFound,
35+
#[error("Unknown material property: {0}")]
36+
UnknownMaterialProperty(String),
3337
}

crates/processing_render/src/geometry/mod.rs

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,13 @@ use std::collections::HashMap;
1111

1212
use bevy::{
1313
asset::RenderAssetUsages,
14-
mesh::{Indices, MeshVertexAttributeId, Meshable, VertexAttributeValues},
14+
mesh::{Indices, MeshVertexAttributeId, VertexAttributeValues},
1515
prelude::*,
1616
render::render_resource::PrimitiveTopology,
1717
};
1818

1919
use crate::error::{ProcessingError, Result};
20+
use crate::render::primitive::{box_mesh, sphere_mesh};
2021

2122
pub struct GeometryPlugin;
2223

@@ -158,9 +159,27 @@ pub fn create_box(
158159
mut meshes: ResMut<Assets<Mesh>>,
159160
builtins: Res<BuiltinAttributes>,
160161
) -> Entity {
161-
let cuboid = Cuboid::new(width, height, depth);
162-
let mesh = cuboid.mesh().build();
163-
let handle = meshes.add(mesh);
162+
let handle = meshes.add(box_mesh(width, height, depth));
163+
164+
let layout_entity = commands
165+
.spawn(VertexLayout::with_attributes(vec![
166+
builtins.position,
167+
builtins.normal,
168+
builtins.color,
169+
builtins.uv,
170+
]))
171+
.id();
172+
173+
commands.spawn(Geometry::new(handle, layout_entity)).id()
174+
}
175+
176+
pub fn create_sphere(
177+
In((radius, sectors, stacks)): In<(f32, u32, u32)>,
178+
mut commands: Commands,
179+
mut meshes: ResMut<Assets<Mesh>>,
180+
builtins: Res<BuiltinAttributes>,
181+
) -> Entity {
182+
let handle = meshes.add(sphere_mesh(radius, sectors, stacks));
164183

165184
let layout_entity = commands
166185
.spawn(VertexLayout::with_attributes(vec![

crates/processing_render/src/graphics.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ pub fn create(
243243
Transform::from_xyz(0.0, 0.0, 999.9),
244244
render_layer,
245245
CommandBuffer::new(),
246-
RenderState::default(),
246+
RenderState::new(),
247247
SurfaceSize(width, height),
248248
Graphics {
249249
readback_buffer,

0 commit comments

Comments
 (0)