use std::{
mem::{size_of, transmute},
sync::Arc,
};
use glam::{
f32::{Mat4, Vec3, Vec4},
Vec4Swizzles,
};
use metal::*;
pub const GEOMETRY_MASK_TRIANGLE: u32 = 1 ;
pub const GEOMETRY_MASK_SPHERE: u32 = 2 ;
pub const GEOMETRY_MASK_LIGHT: u32 = 4 ;
pub const FACE_MASK_NONE: u16 = 0 ;
pub const FACE_MASK_NEGATIVE_X: u16 = 1 << 0 ;
pub const FACE_MASK_POSITIVE_X: u16 = 1 << 1 ;
pub const FACE_MASK_NEGATIVE_Y: u16 = 1 << 2 ;
pub const FACE_MASK_POSITIVE_Y: u16 = 1 << 3 ;
pub const FACE_MASK_NEGATIVE_Z: u16 = 1 << 4 ;
pub const FACE_MASK_POSITIVE_Z: u16 = 1 << 5 ;
pub const FACE_MASK_ALL: u16 = (1 << 6 ) - 1 ;
pub trait Geometry {
fn upload_to_buffers(&mut self ) {
todo!()
}
fn clear(&mut self ) {
todo!()
}
fn get_geometry_descriptor(&self ) -> AccelerationStructureGeometryDescriptor {
todo!()
}
fn get_resources(&self ) -> Vec<Resource> {
todo!()
}
fn get_intersection_function_name(&self ) -> Option<&str> {
None
}
}
pub fn compute_triangle_normal(v0: &Vec3, v1: &Vec3, v2: &Vec3) -> Vec3 {
let e1 = Vec3::normalize(*v1 - *v0);
let e2 = Vec3::normalize(*v2 - *v0);
return Vec3::cross(e1, e2);
}
#[ derive(Default)]
#[ repr(C)]
pub struct Triangle {
pub normals: [Vec4; 3 ],
pub colours: [Vec4; 3 ],
}
pub fn get_managed_buffer_storage_mode() -> MTLResourceOptions {
return MTLResourceOptions::StorageModeManaged;
}
pub struct TriangleGeometry {
pub device: Device,
pub name: String,
pub index_buffer: Option<Buffer>,
pub vertex_position_buffer: Option<Buffer>,
pub vertex_normal_buffer: Option<Buffer>,
pub vertex_colour_buffer: Option<Buffer>,
pub per_primitive_data_buffer: Option<Buffer>,
pub indices: Vec<u16>,
pub vertices: Vec<Vec4>,
pub normals: Vec<Vec4>,
pub colours: Vec<Vec4>,
pub triangles: Vec<Triangle>,
}
impl TriangleGeometry {
pub fn new(device: Device, name: String) -> Self {
Self {
device,
name,
index_buffer: None,
vertex_position_buffer: None,
vertex_normal_buffer: None,
vertex_colour_buffer: None,
per_primitive_data_buffer: None,
indices: Vec::new(),
vertices: Vec::new(),
normals: Vec::new(),
colours: Vec::new(),
triangles: Vec::new(),
}
}
pub fn add_cube_face_with_cube_vertices(
&mut self ,
cube_vertices: &[Vec3],
colour: Vec3,
i0: u16,
i1: u16,
i2: u16,
i3: u16,
inward_normals: bool,
) {
let v0 = cube_vertices[i0 as usize];
let v1 = cube_vertices[i1 as usize];
let v2 = cube_vertices[i2 as usize];
let v3 = cube_vertices[i3 as usize];
let n0 = compute_triangle_normal(&v0, &v1, &v2) * if inward_normals { -1 f32 } else { 1 f32 };
let n1 = compute_triangle_normal(&v0, &v2, &v3) * if inward_normals { -1 f32 } else { 1 f32 };
let first_index = self .indices.len();
let base_index = self .vertices.len() as u16;
self .indices.push(base_index + 0 );
self .indices.push(base_index + 1 );
self .indices.push(base_index + 2 );
self .indices.push(base_index + 0 );
self .indices.push(base_index + 2 );
self .indices.push(base_index + 3 );
self .vertices.push(From::from((v0, 0 .0 )));
self .vertices.push(From::from((v1, 0 .0 )));
self .vertices.push(From::from((v2, 0 .0 )));
self .vertices.push(From::from((v3, 0 .0 )));
self .normals
.push(From::from((Vec3::normalize(n0 + n1), 0 .0 )));
self .normals.push(From::from((n0, 0 .0 )));
self .normals
.push(From::from((Vec3::normalize(n0 + n1), 0 .0 )));
self .normals.push(From::from((n1, 0 .0 )));
for _ in 0 ..4 {
self .colours.push(From::from((colour, 0 .0 )));
}
for triangle_index in 0 ..2 {
let mut triangle = Triangle::default();
for i in 0 ..3 {
let index = self .indices[first_index + triangle_index * 3 + i];
triangle.normals[i] = self .normals[index as usize];
triangle.colours[i] = self .colours[index as usize];
}
self .triangles.push(triangle);
}
}
pub fn add_cube_with_faces(
&mut self ,
face_mask: u16,
colour: Vec3,
transform: Mat4,
inward_normals: bool,
) {
let mut cube_vertices = [
Vec3::new(-0 .5 , -0 .5 , -0 .5 ),
Vec3::new(0 .5 , -0 .5 , -0 .5 ),
Vec3::new(-0 .5 , 0 .5 , -0 .5 ),
Vec3::new(0 .5 , 0 .5 , -0 .5 ),
Vec3::new(-0 .5 , -0 .5 , 0 .5 ),
Vec3::new(0 .5 , -0 .5 , 0 .5 ),
Vec3::new(-0 .5 , 0 .5 , 0 .5 ),
Vec3::new(0 .5 , 0 .5 , 0 .5 ),
];
for i in 0 ..8 {
let transformed_vertex = Vec4::from((cube_vertices[i], 1 .0 ));
let transformed_vertex = transform * transformed_vertex;
cube_vertices[i] = transformed_vertex.xyz();
}
const CUBE_INDICES: [[u16; 4 ]; 6 ] = [
[0 , 4 , 6 , 2 ],
[1 , 3 , 7 , 5 ],
[0 , 1 , 5 , 4 ],
[2 , 6 , 7 , 3 ],
[0 , 2 , 3 , 1 ],
[4 , 5 , 7 , 6 ],
];
for face in 0 ..6 {
if face_mask & (1 << face) != 0 {
self .add_cube_face_with_cube_vertices(
&cube_vertices,
colour,
CUBE_INDICES[face][0 ],
CUBE_INDICES[face][1 ],
CUBE_INDICES[face][2 ],
CUBE_INDICES[face][3 ],
inward_normals,
);
}
}
}
}
impl Geometry for TriangleGeometry {
fn upload_to_buffers(&mut self ) {
self .index_buffer = Some(unsafe {
self .device.new_buffer_with_data(
transmute(self .indices.as_ptr()),
(self .indices.len() * size_of::<u16>()) as NSUInteger,
get_managed_buffer_storage_mode(),
)
});
self .vertex_position_buffer = Some(unsafe {
self .device.new_buffer_with_data(
transmute(self .vertices.as_ptr()),
(self .vertices.len() * size_of::<Vec4>()) as NSUInteger,
get_managed_buffer_storage_mode(),
)
});
self .vertex_normal_buffer = Some(unsafe {
self .device.new_buffer_with_data(
transmute(self .normals.as_ptr()),
(self .normals.len() * size_of::<Vec4>()) as NSUInteger,
get_managed_buffer_storage_mode(),
)
});
self .vertex_colour_buffer = Some(unsafe {
self .device.new_buffer_with_data(
transmute(self .colours.as_ptr()),
(self .colours.len() * size_of::<Vec4>()) as NSUInteger,
get_managed_buffer_storage_mode(),
)
});
self .per_primitive_data_buffer = Some(unsafe {
self .device.new_buffer_with_data(
transmute(self .triangles.as_ptr()),
(self .triangles.len() * size_of::<Triangle>()) as NSUInteger,
get_managed_buffer_storage_mode(),
)
});
self .index_buffer
.as_ref()
.unwrap()
.did_modify_range(NSRange::new(
0 ,
self .index_buffer.as_ref().unwrap().length(),
));
self .vertex_position_buffer
.as_ref()
.unwrap()
.did_modify_range(NSRange::new(
0 ,
self .vertex_position_buffer.as_ref().unwrap().length(),
));
self .vertex_normal_buffer
.as_ref()
.unwrap()
.did_modify_range(NSRange::new(
0 ,
self .vertex_normal_buffer.as_ref().unwrap().length(),
));
self .vertex_colour_buffer
.as_ref()
.unwrap()
.did_modify_range(NSRange::new(
0 ,
self .vertex_colour_buffer.as_ref().unwrap().length(),
));
self .per_primitive_data_buffer
.as_ref()
.unwrap()
.did_modify_range(NSRange::new(
0 ,
self .per_primitive_data_buffer.as_ref().unwrap().length(),
));
self .index_buffer
.as_ref()
.unwrap()
.set_label(&format!("index buffer of {}" , self .name));
self .vertex_position_buffer
.as_ref()
.unwrap()
.set_label(&format!("vertex position buffer of {}" , self .name));
self .vertex_normal_buffer
.as_ref()
.unwrap()
.set_label(&format!("vertex normal buffer of {}" , self .name));
self .vertex_colour_buffer
.as_ref()
.unwrap()
.set_label(&format!("vertex colour buffer of {}" , self .name));
self .per_primitive_data_buffer
.as_ref()
.unwrap()
.set_label(&format!("per primitive data buffer of {}" , self .name));
}
fn clear(&mut self ) {
self .indices.clear();
self .vertices.clear();
self .normals.clear();
self .colours.clear();
self .triangles.clear();
}
fn get_geometry_descriptor(&self ) -> AccelerationStructureGeometryDescriptor {
let descriptor = AccelerationStructureTriangleGeometryDescriptor::descriptor();
descriptor.set_index_buffer(Some(self .index_buffer.as_ref().unwrap()));
descriptor.set_index_type(MTLIndexType::UInt16);
descriptor.set_vertex_buffer(Some(self .vertex_position_buffer.as_ref().unwrap()));
descriptor.set_vertex_stride(size_of::<Vec4>() as NSUInteger);
descriptor.set_triangle_count((self .indices.len() / 3 ) as NSUInteger);
descriptor
.set_primitive_data_buffer(Some(self .per_primitive_data_buffer.as_ref().unwrap()));
descriptor.set_primitive_data_stride(size_of::<Triangle>() as NSUInteger);
descriptor.set_primitive_data_element_size(size_of::<Triangle>() as NSUInteger);
From::from(descriptor)
}
fn get_resources(&self ) -> Vec<Resource> {
vec![
From::from(self .index_buffer.as_ref().unwrap().clone()),
From::from(self .vertex_normal_buffer.as_ref().unwrap().clone()),
From::from(self .vertex_colour_buffer.as_ref().unwrap().clone()),
]
}
}
#[ repr(C)]
pub struct BoundingBox {
pub min: Vec3,
pub max: Vec3,
}
#[ repr(C)]
pub struct Sphere {
pub origin_radius_squared: Vec4,
pub colour_radius: Vec4,
}
pub struct SphereGeometry {
pub device: Device,
pub sphere_buffer: Option<Buffer>,
pub bounding_box_buffer: Option<Buffer>,
pub per_primitive_data_buffer: Option<Buffer>,
pub spheres: Vec<Sphere>,
}
impl SphereGeometry {
pub fn new(device: Device) -> Self {
Self {
device,
sphere_buffer: None,
bounding_box_buffer: None,
per_primitive_data_buffer: None,
spheres: Vec::new(),
}
}
pub fn add_sphere_with_origin(&mut self , origin: Vec3, radius: f32, colour: Vec3) {
self .spheres.push(Sphere {
origin_radius_squared: Vec4::from((origin, radius * radius)),
colour_radius: Vec4::from((colour, radius)),
});
}
}
impl Geometry for SphereGeometry {
fn upload_to_buffers(&mut self ) {
self .sphere_buffer = Some(unsafe {
self .device.new_buffer_with_data(
transmute(self .spheres.as_ptr()),
(self .spheres.len() * size_of::<Sphere>()) as NSUInteger,
get_managed_buffer_storage_mode(),
)
});
self .sphere_buffer
.as_ref()
.unwrap()
.set_label("sphere buffer" );
let mut bounding_boxes = Vec::new();
for sphere in &self .spheres {
bounding_boxes.push(BoundingBox {
min: sphere.origin_radius_squared.xyz() - sphere.colour_radius.w,
max: sphere.origin_radius_squared.xyz() + sphere.colour_radius.w,
});
}
self .bounding_box_buffer = Some(unsafe {
self .device.new_buffer_with_data(
transmute(bounding_boxes.as_ptr()),
(bounding_boxes.len() * size_of::<BoundingBox>()) as NSUInteger,
get_managed_buffer_storage_mode(),
)
});
self .bounding_box_buffer
.as_ref()
.unwrap()
.set_label("bounding box buffer" );
self .sphere_buffer
.as_ref()
.unwrap()
.did_modify_range(NSRange::new(
0 ,
self .sphere_buffer.as_ref().unwrap().length(),
));
self .bounding_box_buffer
.as_ref()
.unwrap()
.did_modify_range(NSRange::new(
0 ,
self .bounding_box_buffer.as_ref().unwrap().length(),
));
}
fn clear(&mut self ) {
self .spheres.clear();
}
fn get_geometry_descriptor(&self ) -> AccelerationStructureGeometryDescriptor {
let descriptor = AccelerationStructureBoundingBoxGeometryDescriptor::descriptor();
descriptor.set_bounding_box_buffer(Some(self .bounding_box_buffer.as_ref().unwrap()));
descriptor.set_bounding_box_count(self .spheres.len() as NSUInteger);
descriptor.set_primitive_data_buffer(Some(&self .sphere_buffer.as_ref().unwrap()));
descriptor.set_primitive_data_stride(size_of::<Sphere>() as NSUInteger);
descriptor.set_primitive_data_element_size(size_of::<Sphere>() as NSUInteger);
From::from(descriptor)
}
fn get_resources(&self ) -> Vec<Resource> {
return vec![From::from(self .sphere_buffer.as_ref().unwrap().clone())];
}
fn get_intersection_function_name(&self ) -> Option<&str> {
Some("sphereIntersectionFunction" )
}
}
pub struct GeometryInstance {
pub geometry: Arc<dyn Geometry>,
pub transform: Mat4,
pub mask: u32,
pub index_in_scene: NSUInteger,
}
#[ repr(C)]
pub struct AreaLight {
pub position: Vec4,
pub forward: Vec4,
pub right: Vec4,
pub up: Vec4,
pub colour: Vec4,
}
Messung V0.5 in Prozent C=99 H=95 G=96
¤ Dauer der Verarbeitung: 0.11 Sekunden
(vorverarbeitet am 2026-06-27)
¤
*© Formatika GbR, Deutschland