use crate::camera::Camera3d;
use crate::color::Color;
use crate::context::Context;
use crate::light::LightCollection;
use crate::resource::vertex_index::{VertexIndex, VERTEX_INDEX_FORMAT};
use crate::resource::{
AllocationType, BufferType, GPUVec, GpuData, GpuMesh3d, Material3d, RenderContext, RenderPhase,
Texture, TextureManager,
};
use crate::scene::SceneNodeData3d;
use glamx::{Mat3, Mat4, Pose3, Vec2, Vec3};
use std::any::Any;
use std::cell::RefCell;
use std::path::Path;
use std::rc::{Rc, Weak};
use std::sync::atomic::{AtomicU32, Ordering};
use std::sync::Arc;
pub struct Skin3d {
pub(crate) joints: Vec<Weak<RefCell<SceneNodeData3d>>>,
pub(crate) inverse_bind: Vec<Mat4>,
pub(crate) palette: Vec<Mat4>,
palette_buffer: Option<wgpu::Buffer>,
palette_capacity: usize,
}
impl Skin3d {
pub(crate) fn new(
joints: Vec<Weak<RefCell<SceneNodeData3d>>>,
inverse_bind: Vec<Mat4>,
) -> Self {
let n = joints.len();
Skin3d {
joints,
inverse_bind,
palette: vec![Mat4::IDENTITY; n],
palette_buffer: None,
palette_capacity: 0,
}
}
pub fn joint_count(&self) -> usize {
self.joints.len()
}
pub(crate) fn palette(&self) -> &[Mat4] {
&self.palette
}
pub(crate) fn upload(&mut self) {
if self.palette.is_empty() {
return;
}
let ctxt = Context::get();
if self.palette_buffer.is_none() || self.palette.len() > self.palette_capacity {
let cap = self.palette.len().next_power_of_two().max(1);
self.palette_buffer = Some(ctxt.create_buffer(&wgpu::BufferDescriptor {
label: Some("skin_palette_buffer"),
size: (cap * std::mem::size_of::<[[f32; 4]; 4]>()) as u64,
usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
}));
self.palette_capacity = cap;
}
ctxt.write_buffer(
self.palette_buffer.as_ref().unwrap(),
0,
bytemuck::cast_slice(&self.palette),
);
}
#[cfg_attr(target_arch = "wasm32", allow(dead_code))]
pub(crate) fn palette_buffer(&self) -> Option<&wgpu::Buffer> {
self.palette_buffer.as_ref()
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Bsdf {
Opaque,
Glass,
Metal,
Emissive,
}
impl Bsdf {
pub(crate) fn tag(self) -> u32 {
match self {
Bsdf::Opaque => 0,
Bsdf::Glass => 1,
Bsdf::Metal => 2,
Bsdf::Emissive => 3,
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum AlphaMode {
Opaque,
Mask(f32),
#[default]
Blend,
Premultiplied,
}
impl AlphaMode {
pub(crate) fn is_transparent(self, color_alpha: f32) -> bool {
matches!(self, AlphaMode::Blend | AlphaMode::Premultiplied) && color_alpha < 1.0
}
pub(crate) fn shader_params(self) -> (u32, f32) {
match self {
AlphaMode::Opaque => (0, 0.0),
AlphaMode::Mask(c) => (1, c),
AlphaMode::Blend => (2, 0.0),
AlphaMode::Premultiplied => (3, 0.0),
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ParallaxMethod {
#[default]
Occlusion,
Relief { max_steps: u32 },
}
impl ParallaxMethod {
pub(crate) fn code(self) -> f32 {
match self {
ParallaxMethod::Occlusion => 0.0,
ParallaxMethod::Relief { max_steps } => max_steps.clamp(1, 64) as f32,
}
}
}
static NEXT_SEGMENTATION_ID: AtomicU32 = AtomicU32::new(1);
fn next_segmentation_id() -> u32 {
NEXT_SEGMENTATION_ID.fetch_add(1, Ordering::Relaxed)
}
pub struct ObjectData3d {
material: Rc<RefCell<Box<dyn Material3d + 'static>>>,
texture: Arc<Texture>,
color: Color,
lines_color: Option<Color>,
points_color: Option<Color>,
wlines: f32,
wpoints: f32,
lines_use_perspective: bool,
points_use_perspective: bool,
draw_surface: bool,
cull: bool,
segmentation_id: u32,
user_data: Box<dyn Any + 'static>,
render_layers: u32,
light_layers: u32,
casts_shadows: bool,
metallic: f32,
roughness: f32,
emissive: Color,
alpha_mode: AlphaMode,
bsdf: Bsdf,
ior: f32,
transmission: f32,
specular_tint: Color,
subsurface: f32,
subsurface_radius: f32,
thickness: f32,
attenuation_color: Color,
attenuation_distance: f32,
reflectance: f32,
clearcoat: f32,
clearcoat_roughness: f32,
anisotropy: f32,
anisotropy_rotation: f32,
ssr: Option<crate::renderer::SsrMaterial>,
reflector: Option<crate::renderer::Reflector>,
normal_map: Option<Arc<Texture>>,
metallic_roughness_map: Option<Arc<Texture>>,
ao_map: Option<Arc<Texture>>,
emissive_map: Option<Arc<Texture>>,
height_map: Option<Arc<Texture>>,
parallax_scale: f32,
parallax_layers: f32,
parallax_method: ParallaxMethod,
skin: Option<Skin3d>,
morph_weights: Vec<f32>,
deform: Option<crate::builtin::deform::DeformGpu>,
shadow_tex_bind_group: Option<wgpu::BindGroup>,
cached_shadow_tex_ptr: usize,
}
impl ObjectData3d {
#[inline]
pub fn texture(&self) -> &Arc<Texture> {
&self.texture
}
#[inline]
pub fn color(&self) -> Color {
self.color
}
#[inline]
pub fn lines_width(&self) -> f32 {
self.wlines
}
#[inline]
pub fn lines_color(&self) -> Option<Color> {
self.lines_color
}
#[inline]
pub fn points_size(&self) -> f32 {
self.wpoints
}
#[inline]
pub fn points_color(&self) -> Option<Color> {
self.points_color
}
#[inline]
pub fn lines_use_perspective(&self) -> bool {
self.lines_use_perspective
}
#[inline]
pub fn points_use_perspective(&self) -> bool {
self.points_use_perspective
}
#[inline]
pub fn surface_rendering_active(&self) -> bool {
self.draw_surface
}
#[inline]
pub fn backface_culling_enabled(&self) -> bool {
self.cull
}
#[inline]
pub fn segmentation_id(&self) -> u32 {
self.segmentation_id
}
#[inline]
pub fn user_data(&self) -> &dyn Any {
&*self.user_data
}
#[inline]
pub fn has_skin(&self) -> bool {
self.skin.is_some()
}
#[inline]
pub fn skin(&self) -> Option<&Skin3d> {
self.skin.as_ref()
}
#[inline]
pub(crate) fn skin_mut(&mut self) -> Option<&mut Skin3d> {
self.skin.as_mut()
}
#[inline]
pub(crate) fn set_skin(&mut self, skin: Skin3d) {
self.skin = Some(skin);
}
#[inline]
pub fn morph_weights(&self) -> &[f32] {
&self.morph_weights
}
#[inline]
pub fn set_morph_weights(&mut self, weights: &[f32]) {
self.morph_weights.clear();
self.morph_weights.extend_from_slice(weights);
}
#[inline]
pub fn morph_target_count(&self) -> usize {
self.morph_weights.len()
}
#[inline]
pub(crate) fn is_deformable(&self) -> bool {
self.skin.is_some() || !self.morph_weights.is_empty()
}
#[inline]
pub(crate) fn deform_bind_group(&self) -> Option<&wgpu::BindGroup> {
self.deform.as_ref().and_then(|d| d.bind_group())
}
pub(crate) fn update_deform(&mut self, mesh: &GpuMesh3d) {
use crate::builtin::deform::{DeformControl, DeformGpu};
let has_skin = mesh.has_skin_vertices()
&& self
.skin
.as_ref()
.and_then(|s| s.palette_buffer())
.is_some();
let has_morph = mesh.has_morph() && !self.morph_weights.is_empty();
if !has_skin && !has_morph {
return;
}
let (joints, weights) = match has_skin {
true => mesh
.ensure_skin_on_gpu()
.map_or((None, None), |(j, w)| (Some(j), Some(w))),
false => (None, None),
};
let (morph_pos, morph_nrm) = match has_morph {
true => mesh
.ensure_morph_on_gpu()
.map_or((None, None), |(p, n)| (Some(p), n)),
false => (None, None),
};
let palette = if has_skin {
self.skin.as_ref().and_then(|s| s.palette_buffer())
} else {
None
};
let mut ctrl = DeformControl::default();
ctrl.set_weights(if has_morph { &self.morph_weights } else { &[] });
ctrl.num_vertices = mesh.morph_vertex_count() as u32;
ctrl.has_skin = has_skin as u32;
ctrl.has_morph_normals = (has_morph && mesh.has_morph_normals()) as u32;
let deform = self.deform.get_or_insert_with(DeformGpu::new);
deform.update(&ctrl, palette, joints, weights, morph_pos, morph_nrm);
}
pub(crate) fn shadow_tex_bind_group(
&mut self,
layout: &wgpu::BindGroupLayout,
) -> &wgpu::BindGroup {
let ptr = Arc::as_ptr(&self.texture) as usize;
if self.shadow_tex_bind_group.is_none() || self.cached_shadow_tex_ptr != ptr {
let ctxt = Context::get();
self.shadow_tex_bind_group = Some(ctxt.create_bind_group(&wgpu::BindGroupDescriptor {
label: Some("shadow_tex_bind_group"),
layout,
entries: &[
wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::TextureView(&self.texture.view),
},
wgpu::BindGroupEntry {
binding: 1,
resource: wgpu::BindingResource::Sampler(&self.texture.sampler),
},
],
}));
self.cached_shadow_tex_ptr = ptr;
}
self.shadow_tex_bind_group.as_ref().unwrap()
}
#[inline]
pub fn metallic(&self) -> f32 {
self.metallic
}
#[inline]
pub fn roughness(&self) -> f32 {
self.roughness
}
#[inline]
pub fn emissive(&self) -> Color {
self.emissive
}
#[inline]
pub fn alpha_mode(&self) -> AlphaMode {
self.alpha_mode
}
#[inline]
pub fn render_layers(&self) -> u32 {
self.render_layers
}
#[inline]
pub fn light_layers(&self) -> u32 {
self.light_layers
}
#[inline]
pub fn casts_shadows(&self) -> bool {
self.casts_shadows
}
#[inline]
pub fn bsdf(&self) -> Bsdf {
self.bsdf
}
#[inline]
pub fn ior(&self) -> f32 {
self.ior
}
#[inline]
pub fn transmission(&self) -> f32 {
self.transmission
}
#[inline]
pub fn thickness(&self) -> f32 {
self.thickness
}
#[inline]
pub fn attenuation_color(&self) -> Color {
self.attenuation_color
}
#[inline]
pub fn attenuation_distance(&self) -> f32 {
self.attenuation_distance
}
#[inline]
pub fn specular_tint(&self) -> Color {
self.specular_tint
}
#[inline]
pub fn subsurface(&self) -> f32 {
self.subsurface
}
#[inline]
pub fn subsurface_radius(&self) -> f32 {
self.subsurface_radius
}
#[inline]
pub fn reflectance(&self) -> f32 {
self.reflectance
}
#[inline]
pub fn ssr(&self) -> Option<crate::renderer::SsrMaterial> {
self.ssr
}
#[inline]
pub fn reflector(&self) -> Option<&crate::renderer::Reflector> {
self.reflector.as_ref()
}
#[inline]
pub fn reflector_mut(&mut self) -> Option<&mut crate::renderer::Reflector> {
self.reflector.as_mut()
}
#[inline]
pub fn clearcoat(&self) -> f32 {
self.clearcoat
}
#[inline]
pub fn clearcoat_roughness(&self) -> f32 {
self.clearcoat_roughness
}
#[inline]
pub fn anisotropy(&self) -> f32 {
self.anisotropy
}
#[inline]
pub fn anisotropy_rotation(&self) -> f32 {
self.anisotropy_rotation
}
#[inline]
pub fn normal_map(&self) -> Option<&Arc<Texture>> {
self.normal_map.as_ref()
}
#[inline]
pub fn metallic_roughness_map(&self) -> Option<&Arc<Texture>> {
self.metallic_roughness_map.as_ref()
}
#[inline]
pub fn ao_map(&self) -> Option<&Arc<Texture>> {
self.ao_map.as_ref()
}
#[inline]
pub fn emissive_map(&self) -> Option<&Arc<Texture>> {
self.emissive_map.as_ref()
}
#[inline]
pub fn height_map(&self) -> Option<&Arc<Texture>> {
self.height_map.as_ref()
}
#[inline]
pub fn parallax_scale(&self) -> f32 {
self.parallax_scale
}
#[inline]
pub fn parallax_layers(&self) -> f32 {
self.parallax_layers
}
#[inline]
pub fn parallax_method(&self) -> ParallaxMethod {
self.parallax_method
}
}
pub struct InstanceData3d {
pub position: Vec3,
pub deformation: Mat3,
pub color: Color,
pub lines_color: Option<Color>,
pub lines_width: Option<f32>,
pub points_color: Option<Color>,
pub points_size: Option<f32>,
}
impl Default for InstanceData3d {
fn default() -> Self {
Self {
position: Vec3::ZERO,
deformation: Mat3::IDENTITY,
color: crate::color::WHITE,
lines_color: None, lines_width: None, points_color: None, points_size: None, }
}
}
pub const LINES_WIDTH_USE_OBJECT: f32 = -1.0;
pub const LINES_COLOR_USE_OBJECT: Color = Color::new(0.0, 0.0, 0.0, 0.0);
pub const POINTS_SIZE_USE_OBJECT: f32 = -1.0;
pub const POINTS_COLOR_USE_OBJECT: Color = Color::new(0.0, 0.0, 0.0, 0.0);
pub struct InstancesBuffer3d {
pub positions: GPUVec<Vec3>,
pub deformations: GPUVec<Vec3>,
pub colors: GPUVec<[f32; 4]>,
pub lines_colors: GPUVec<[f32; 4]>,
pub lines_widths: GPUVec<f32>,
pub points_colors: GPUVec<[f32; 4]>,
pub points_sizes: GPUVec<f32>,
}
#[inline]
pub(crate) fn color_to_array(color: Color) -> [f32; 4] {
[color.r, color.g, color.b, color.a]
}
impl Default for InstancesBuffer3d {
fn default() -> Self {
InstancesBuffer3d {
positions: GPUVec::new(
vec![Vec3::ZERO],
BufferType::Array,
AllocationType::StreamDraw,
),
deformations: GPUVec::new(
vec![Vec3::X, Vec3::Y, Vec3::Z],
BufferType::Array,
AllocationType::StreamDraw,
),
colors: GPUVec::new(
vec![[1.0; 4]],
BufferType::Array,
AllocationType::StreamDraw,
),
lines_colors: GPUVec::new(
vec![color_to_array(LINES_COLOR_USE_OBJECT)], BufferType::Array,
AllocationType::StreamDraw,
),
lines_widths: GPUVec::new(
vec![LINES_WIDTH_USE_OBJECT], BufferType::Array,
AllocationType::StreamDraw,
),
points_colors: GPUVec::new(
vec![color_to_array(POINTS_COLOR_USE_OBJECT)], BufferType::Array,
AllocationType::StreamDraw,
),
points_sizes: GPUVec::new(
vec![POINTS_SIZE_USE_OBJECT], BufferType::Array,
AllocationType::StreamDraw,
),
}
}
}
impl InstancesBuffer3d {
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn len(&self) -> usize {
self.positions.len()
}
pub fn any_instance_has_wireframe(&self) -> bool {
if let Some(widths) = self.lines_widths.data() {
widths.iter().any(|&w| w >= 0.0)
} else {
false
}
}
pub fn all_use_object_wireframe(&self) -> bool {
if let Some(widths) = self.lines_widths.data() {
widths.iter().all(|&w| w < 0.0)
} else {
true
}
}
}
pub struct Object3d {
data: ObjectData3d,
instances: Rc<RefCell<InstancesBuffer3d>>,
mesh: Rc<RefCell<GpuMesh3d>>,
gpu_data: Box<dyn GpuData>,
}
impl Object3d {
#[doc(hidden)]
pub fn new(
mesh: Rc<RefCell<GpuMesh3d>>,
color: Color,
texture: Arc<Texture>,
material: Rc<RefCell<Box<dyn Material3d + 'static>>>,
) -> Object3d {
let gpu_data = material.borrow().create_gpu_data();
let user_data = ();
let data = ObjectData3d {
color,
lines_color: None,
points_color: None,
texture,
wlines: 0.0,
wpoints: 0.0,
lines_use_perspective: true,
points_use_perspective: true,
draw_surface: true,
cull: true,
segmentation_id: next_segmentation_id(),
material,
user_data: Box::new(user_data),
render_layers: 1, light_layers: u32::MAX, casts_shadows: true,
metallic: 0.0,
roughness: 0.5,
emissive: crate::color::BLACK,
alpha_mode: AlphaMode::default(),
bsdf: Bsdf::Opaque,
ior: 1.5,
transmission: 0.0,
specular_tint: crate::color::WHITE,
subsurface: 0.0,
subsurface_radius: 0.0,
thickness: 0.0,
attenuation_color: crate::color::WHITE,
attenuation_distance: f32::INFINITY,
reflectance: 0.5,
clearcoat: 0.0,
clearcoat_roughness: 0.0,
anisotropy: 0.0,
anisotropy_rotation: 0.0,
ssr: Some(crate::renderer::SsrMaterial::default()),
reflector: None,
normal_map: None,
metallic_roughness_map: None,
ao_map: None,
emissive_map: None,
height_map: None,
parallax_scale: 0.1,
parallax_layers: 16.0,
parallax_method: ParallaxMethod::Occlusion,
skin: None,
morph_weights: Vec::new(),
deform: None,
shadow_tex_bind_group: None,
cached_shadow_tex_ptr: 0,
};
let instances = Rc::new(RefCell::new(InstancesBuffer3d::default()));
Object3d {
data,
instances,
mesh,
gpu_data,
}
}
#[doc(hidden)]
pub fn prepare(
&mut self,
transform: Pose3,
scale: Vec3,
pass: usize,
camera: &mut dyn Camera3d,
lights: &LightCollection,
viewport_width: u32,
viewport_height: u32,
) {
self.data.material.borrow_mut().prepare(
pass,
transform,
scale,
camera,
lights,
&self.data,
&mut *self.gpu_data,
viewport_width,
viewport_height,
);
}
#[doc(hidden)]
pub fn render(
&mut self,
transform: Pose3,
scale: Vec3,
pass: usize,
camera: &mut dyn Camera3d,
lights: &LightCollection,
render_pass: &mut wgpu::RenderPass<'_>,
context: &RenderContext,
) {
if context.phase == RenderPhase::Transparent
&& !self.data.material.borrow().renders_in_transparent_phase()
{
return;
}
if self.data.render_layers & context.render_layers == 0 {
return;
}
self.data.material.borrow_mut().render(
pass,
transform,
scale,
camera,
lights,
&self.data,
&mut self.mesh.borrow_mut(),
&mut self.instances.borrow_mut(),
&mut *self.gpu_data,
render_pass,
context,
);
}
#[doc(hidden)]
pub fn casts_shadows(&self) -> bool {
self.data.casts_shadows && self.data.surface_rendering_active()
}
#[inline]
pub fn set_casts_shadows(&mut self, casts_shadows: bool) {
self.data.casts_shadows = casts_shadows;
}
#[doc(hidden)]
pub fn render_depth_only(
&mut self,
render_pass: &mut wgpu::RenderPass<'_>,
base_pipeline: &wgpu::RenderPipeline,
deform_pipeline: Option<&wgpu::RenderPipeline>,
transmittance_tex: Option<&wgpu::BindGroupLayout>,
model_bind_group: &wgpu::BindGroup,
model_offset: u32,
) {
if !self.data.surface_rendering_active() {
return;
}
let mesh = self.mesh.borrow();
let mut instances = self.instances.borrow_mut();
let num_instances = instances.len();
instances.positions.load_to_gpu();
instances.deformations.load_to_gpu();
mesh.coords().write().unwrap().load_to_gpu();
mesh.faces().write().unwrap().load_to_gpu();
let coords_buffer = mesh.coords().read().unwrap();
let faces_buffer = mesh.faces().read().unwrap();
let coords_buf = match coords_buffer.buffer() {
Some(b) => b,
None => return,
};
let faces_buf = match faces_buffer.buffer() {
Some(b) => b,
None => return,
};
let inst_positions_buf = match instances.positions.buffer() {
Some(b) => b,
None => return,
};
let inst_deformations_buf = match instances.deformations.buffer() {
Some(b) => b,
None => return,
};
let use_deform = deform_pipeline.is_some() && self.data.deform_bind_group().is_some();
let uvs_guard;
let uvs_buf: Option<&wgpu::Buffer> = if transmittance_tex.is_some() {
mesh.uvs().write().unwrap().load_to_gpu();
uvs_guard = mesh.uvs().read().unwrap();
uvs_guard.buffer()
} else {
None
};
if use_deform {
render_pass.set_pipeline(deform_pipeline.unwrap());
render_pass.set_bind_group(1, model_bind_group, &[model_offset]);
render_pass.set_bind_group(2, self.data.deform_bind_group().unwrap(), &[]);
} else {
render_pass.set_pipeline(base_pipeline);
render_pass.set_bind_group(1, model_bind_group, &[model_offset]);
}
if let (Some(tex_layout), Some(uvs)) = (transmittance_tex, uvs_buf) {
let tex_group = if use_deform { 3 } else { 2 };
let tex_bg = self.data.shadow_tex_bind_group(tex_layout);
render_pass.set_bind_group(tex_group, tex_bg, &[]);
render_pass.set_vertex_buffer(3, uvs.slice(..));
}
render_pass.set_vertex_buffer(0, coords_buf.slice(..));
render_pass.set_vertex_buffer(1, inst_positions_buf.slice(..));
render_pass.set_vertex_buffer(2, inst_deformations_buf.slice(..));
render_pass.set_index_buffer(faces_buf.slice(..), VERTEX_INDEX_FORMAT);
render_pass.draw_indexed(0..mesh.num_indices(), 0, 0..num_instances as u32);
}
#[inline]
pub fn data(&self) -> &ObjectData3d {
&self.data
}
#[inline]
pub fn data_mut(&mut self) -> &mut ObjectData3d {
&mut self.data
}
#[inline]
pub fn has_skin(&self) -> bool {
self.data.has_skin()
}
#[inline]
pub(crate) fn set_skin(&mut self, skin: Skin3d) {
self.data.set_skin(skin);
}
#[inline]
pub fn instances(&self) -> &Rc<RefCell<InstancesBuffer3d>> {
&self.instances
}
pub fn set_instances(&mut self, instances: &[InstanceData3d]) {
let mut pos_data: Vec<_> = self
.instances
.borrow_mut()
.positions
.data_mut()
.take()
.unwrap_or_default();
let mut col_data: Vec<_> = self
.instances
.borrow_mut()
.colors
.data_mut()
.take()
.unwrap_or_default();
let mut def_data: Vec<_> = self
.instances
.borrow_mut()
.deformations
.data_mut()
.take()
.unwrap_or_default();
let mut lines_col_data: Vec<_> = self
.instances
.borrow_mut()
.lines_colors
.data_mut()
.take()
.unwrap_or_default();
let mut lines_width_data: Vec<_> = self
.instances
.borrow_mut()
.lines_widths
.data_mut()
.take()
.unwrap_or_default();
let mut points_col_data: Vec<_> = self
.instances
.borrow_mut()
.points_colors
.data_mut()
.take()
.unwrap_or_default();
let mut points_size_data: Vec<_> = self
.instances
.borrow_mut()
.points_sizes
.data_mut()
.take()
.unwrap_or_default();
pos_data.clear();
col_data.clear();
def_data.clear();
lines_col_data.clear();
lines_width_data.clear();
points_col_data.clear();
points_size_data.clear();
pos_data.extend(instances.iter().map(|i| i.position));
col_data.extend(instances.iter().map(|i| color_to_array(i.color)));
def_data.extend(instances.iter().flat_map(|i| {
[
i.deformation.x_axis,
i.deformation.y_axis,
i.deformation.z_axis,
]
}));
lines_col_data.extend(
instances
.iter()
.map(|i| color_to_array(i.lines_color.unwrap_or(LINES_COLOR_USE_OBJECT))),
);
lines_width_data.extend(
instances
.iter()
.map(|i| i.lines_width.unwrap_or(LINES_WIDTH_USE_OBJECT)),
);
points_col_data.extend(
instances
.iter()
.map(|i| color_to_array(i.points_color.unwrap_or(POINTS_COLOR_USE_OBJECT))),
);
points_size_data.extend(
instances
.iter()
.map(|i| i.points_size.unwrap_or(POINTS_SIZE_USE_OBJECT)),
);
*self.instances.borrow_mut().positions.data_mut() = Some(pos_data);
*self.instances.borrow_mut().colors.data_mut() = Some(col_data);
*self.instances.borrow_mut().deformations.data_mut() = Some(def_data);
*self.instances.borrow_mut().lines_colors.data_mut() = Some(lines_col_data);
*self.instances.borrow_mut().lines_widths.data_mut() = Some(lines_width_data);
*self.instances.borrow_mut().points_colors.data_mut() = Some(points_col_data);
*self.instances.borrow_mut().points_sizes.data_mut() = Some(points_size_data);
}
#[inline]
pub fn enable_backface_culling(&mut self, active: bool) {
self.data.cull = active;
}
#[inline]
pub fn set_user_data(&mut self, user_data: Box<dyn Any + 'static>) {
self.data.user_data = user_data;
}
#[inline]
pub fn set_segmentation_id(&mut self, id: u32) {
self.data.segmentation_id = id;
}
#[inline]
pub fn segmentation_id(&self) -> u32 {
self.data.segmentation_id
}
#[inline]
pub fn material(&self) -> Rc<RefCell<Box<dyn Material3d + 'static>>> {
self.data.material.clone()
}
#[inline]
pub fn set_material(&mut self, material: Rc<RefCell<Box<dyn Material3d + 'static>>>) {
self.gpu_data = material.borrow().create_gpu_data();
self.data.material = material;
}
#[inline]
pub fn set_lines_width(&mut self, width: f32, use_perspective: bool) {
self.data.wlines = width;
self.data.lines_use_perspective = use_perspective;
}
#[inline]
pub fn lines_width(&self) -> f32 {
self.data.wlines
}
#[inline]
pub fn set_lines_color(&mut self, color: Option<Color>) {
self.data.lines_color = color
}
#[inline]
pub fn lines_color(&self) -> Option<Color> {
self.data.lines_color
}
#[inline]
pub fn set_points_size(&mut self, size: f32, use_perspective: bool) {
self.data.wpoints = size;
self.data.points_use_perspective = use_perspective;
}
#[inline]
pub fn points_size(&self) -> f32 {
self.data.wpoints
}
#[inline]
pub fn set_points_color(&mut self, color: Option<Color>) {
self.data.points_color = color
}
#[inline]
pub fn points_color(&self) -> Option<Color> {
self.data.points_color
}
#[inline]
pub fn set_surface_rendering_activation(&mut self, active: bool) {
self.data.draw_surface = active
}
#[inline]
pub fn surface_rendering_activation(&self) -> bool {
self.data.draw_surface
}
#[inline]
pub fn mesh(&self) -> &Rc<RefCell<GpuMesh3d>> {
&self.mesh
}
#[inline(always)]
pub fn modify_vertices<F: FnMut(&mut Vec<Vec3>)>(&mut self, f: &mut F) {
let bmesh = self.mesh.borrow_mut();
let _ = bmesh.coords().write().unwrap().data_mut().as_mut().map(f);
}
#[inline(always)]
pub fn read_vertices<F: FnMut(&[Vec3])>(&self, f: &mut F) {
let bmesh = self.mesh.borrow();
let _ = bmesh
.coords()
.read()
.unwrap()
.data()
.as_ref()
.map(|coords| f(&coords[..]));
}
#[inline]
pub fn recompute_normals(&mut self) {
self.mesh.borrow_mut().recompute_normals();
}
#[inline(always)]
pub fn modify_normals<F: FnMut(&mut Vec<Vec3>)>(&mut self, f: &mut F) {
let bmesh = self.mesh.borrow_mut();
let _ = bmesh.normals().write().unwrap().data_mut().as_mut().map(f);
}
#[inline(always)]
pub fn read_normals<F: FnMut(&[Vec3])>(&self, f: &mut F) {
let bmesh = self.mesh.borrow();
let _ = bmesh
.normals()
.read()
.unwrap()
.data()
.as_ref()
.map(|normals| f(&normals[..]));
}
#[inline(always)]
pub fn modify_faces<F: FnMut(&mut Vec<[VertexIndex; 3]>)>(&mut self, f: &mut F) {
let bmesh = self.mesh.borrow_mut();
let _ = bmesh.faces().write().unwrap().data_mut().as_mut().map(f);
}
#[inline(always)]
pub fn read_faces<F: FnMut(&[[VertexIndex; 3]])>(&self, f: &mut F) {
let bmesh = self.mesh.borrow();
let _ = bmesh
.faces()
.read()
.unwrap()
.data()
.as_ref()
.map(|faces| f(&faces[..]));
}
#[inline(always)]
pub fn modify_uvs<F: FnMut(&mut Vec<Vec2>)>(&mut self, f: &mut F) {
let bmesh = self.mesh.borrow_mut();
let _ = bmesh.uvs().write().unwrap().data_mut().as_mut().map(f);
}
#[inline(always)]
pub fn read_uvs<F: FnMut(&[Vec2])>(&self, f: &mut F) {
let bmesh = self.mesh.borrow();
let _ = bmesh
.uvs()
.read()
.unwrap()
.data()
.as_ref()
.map(|uvs| f(&uvs[..]));
}
#[inline]
pub fn set_color(&mut self, color: Color) {
self.data.color = color;
}
#[inline]
pub fn set_texture_from_file(&mut self, path: &Path, name: &str) {
let texture = TextureManager::get_global_manager(|tm| tm.add(path, name));
self.set_texture(texture)
}
#[inline]
pub fn set_texture_with_name(&mut self, name: &str) {
let texture = TextureManager::get_global_manager(|tm| {
tm.get(name).unwrap_or_else(|| {
panic!("Invalid attempt to use the unregistered texture: {}", name)
})
});
self.set_texture(texture)
}
#[inline]
pub fn set_texture(&mut self, texture: Arc<Texture>) {
self.data.texture = texture
}
#[inline]
pub fn set_metallic(&mut self, metallic: f32) {
self.data.metallic = metallic.clamp(0.0, 1.0);
}
#[inline]
pub fn set_ssr(&mut self, ssr: Option<crate::renderer::SsrMaterial>) {
self.data.ssr = ssr;
}
#[inline]
pub fn set_reflector(&mut self, reflector: Option<crate::renderer::Reflector>) {
self.data.reflector = reflector;
}
#[inline]
pub fn reflector(&self) -> Option<&crate::renderer::Reflector> {
self.data.reflector.as_ref()
}
#[inline]
pub fn reflector_mut(&mut self) -> Option<&mut crate::renderer::Reflector> {
self.data.reflector.as_mut()
}
#[inline]
pub fn set_roughness(&mut self, roughness: f32) {
self.data.roughness = roughness.clamp(0.0, 1.0);
}
#[inline]
pub fn set_emissive(&mut self, color: Color) {
self.data.emissive = color;
}
#[inline]
pub fn set_render_layers(&mut self, layers: u32) {
self.data.render_layers = layers;
}
#[inline]
pub fn render_layers(&self) -> u32 {
self.data.render_layers
}
#[inline]
pub fn set_light_layers(&mut self, layers: u32) {
self.data.light_layers = layers;
}
#[inline]
pub fn light_layers(&self) -> u32 {
self.data.light_layers
}
#[inline]
pub fn set_alpha_mode(&mut self, alpha_mode: AlphaMode) {
self.data.alpha_mode = alpha_mode;
}
#[inline]
pub fn set_bsdf(&mut self, bsdf: Bsdf) {
self.data.bsdf = bsdf;
}
#[inline]
pub fn set_ior(&mut self, ior: f32) {
self.data.ior = ior.max(1.0);
}
#[inline]
pub fn set_transmission(&mut self, transmission: f32) {
self.data.transmission = transmission.clamp(0.0, 1.0);
}
#[inline]
pub fn set_thickness(&mut self, thickness: f32) {
self.data.thickness = thickness.max(0.0);
}
#[inline]
pub fn set_attenuation(&mut self, color: Color, distance: f32) {
self.data.attenuation_color = color;
self.data.attenuation_distance = distance.max(0.0);
}
#[inline]
pub fn set_specular_tint(&mut self, color: Color) {
self.data.specular_tint = color;
}
#[inline]
pub fn set_subsurface(&mut self, factor: f32, radius: f32) {
self.data.subsurface = factor.clamp(0.0, 1.0);
self.data.subsurface_radius = radius.max(0.0);
}
#[inline]
pub fn set_reflectance(&mut self, reflectance: f32) {
self.data.reflectance = reflectance.clamp(0.0, 1.0);
}
#[inline]
pub fn set_clearcoat(&mut self, strength: f32, roughness: f32) {
self.data.clearcoat = strength.clamp(0.0, 1.0);
self.data.clearcoat_roughness = roughness.clamp(0.0, 1.0);
}
#[inline]
pub fn set_anisotropy(&mut self, strength: f32, rotation: f32) {
self.data.anisotropy = strength.clamp(-1.0, 1.0);
self.data.anisotropy_rotation = rotation;
}
#[inline]
pub fn set_normal_map_from_file(&mut self, path: &Path, name: &str) {
let texture = TextureManager::get_global_manager(|tm| tm.add(path, name));
self.set_normal_map(texture);
}
#[inline]
pub fn set_normal_map(&mut self, texture: Arc<Texture>) {
self.data.normal_map = Some(texture);
}
#[inline]
pub fn clear_normal_map(&mut self) {
self.data.normal_map = None;
}
#[inline]
pub fn set_metallic_roughness_map_from_file(&mut self, path: &Path, name: &str) {
let texture = TextureManager::get_global_manager(|tm| tm.add(path, name));
self.set_metallic_roughness_map(texture);
}
#[inline]
pub fn set_metallic_roughness_map(&mut self, texture: Arc<Texture>) {
self.data.metallic_roughness_map = Some(texture);
}
#[inline]
pub fn clear_metallic_roughness_map(&mut self) {
self.data.metallic_roughness_map = None;
}
#[inline]
pub fn set_ao_map_from_file(&mut self, path: &Path, name: &str) {
let texture = TextureManager::get_global_manager(|tm| tm.add(path, name));
self.set_ao_map(texture);
}
#[inline]
pub fn set_ao_map(&mut self, texture: Arc<Texture>) {
self.data.ao_map = Some(texture);
}
#[inline]
pub fn clear_ao_map(&mut self) {
self.data.ao_map = None;
}
#[inline]
pub fn set_emissive_map_from_file(&mut self, path: &Path, name: &str) {
let texture = TextureManager::get_global_manager(|tm| tm.add(path, name));
self.set_emissive_map(texture);
}
#[inline]
pub fn set_emissive_map(&mut self, texture: Arc<Texture>) {
self.data.emissive_map = Some(texture);
}
#[inline]
pub fn clear_emissive_map(&mut self) {
self.data.emissive_map = None;
}
#[inline]
pub fn set_height_map_from_file(&mut self, path: &Path, name: &str) {
let texture = TextureManager::get_global_manager(|tm| tm.add(path, name));
self.set_height_map(texture);
}
#[inline]
pub fn set_height_map(&mut self, texture: Arc<Texture>) {
self.data.height_map = Some(texture);
}
#[inline]
pub fn clear_height_map(&mut self) {
self.data.height_map = None;
}
#[inline]
pub fn set_parallax_scale(&mut self, scale: f32) {
self.data.parallax_scale = scale.max(0.0);
}
#[inline]
pub fn set_parallax_layers(&mut self, layers: f32) {
self.data.parallax_layers = layers.clamp(1.0, 64.0);
}
#[inline]
pub fn set_parallax_method(&mut self, method: ParallaxMethod) {
self.data.parallax_method = method;
}
}