pub struct Model(pub NonNull<_ModelT>);
Expand description
A Model is a collection of meshes, materials, and transforms that make up a visual element! This is a great way to group together complex objects that have multiple parts in them, and in fact, most model formats are composed this way already!
This class contains a number of methods for creation. If you pass in a .obj, .stl, , .ply (ASCII), .gltf, or .glb, StereoKit will load that model from file, and assemble materials and transforms from the file information. But you can also assemble a model from procedurally generated meshes!
Because models include an offset transform for each mesh element, this does have the overhead of an extra matrix multiplication in order to execute a render command. So if you need speed, and only have a single mesh with a precalculated transform matrix, it can be faster to render a Mesh instead of a Model! https://stereokit.net/Pages/StereoKit/Model.html
§Examples
use stereokit_rust::{maths::{Vec3, Matrix}, model::Model, mesh::Mesh, material::Material};
let sphere = Mesh::generate_sphere(0.6, None);
let rounded_cube = Mesh::generate_rounded_cube(Vec3::ONE * 0.6, 0.2, None);
let cylinder = Mesh::generate_cylinder(0.25, 0.6, Vec3::Z, None);
let transform1 = Matrix::t([-0.7,-0.5, 0.0]);
let transform2 = Matrix::t([ 0.0, 0.0, 0.0]);
let transform3 = Matrix::t([ 0.7, 0.5, 0.0]);
let material = Material::pbr();
let model = Model::new();
let mut nodes = model.get_nodes();
nodes.add("sphere", transform1 , Some(&sphere), Some(&material), true)
.add("cube", transform2 , Some(&rounded_cube), Some(&material), true)
.add("cylinder", transform3 , Some(&cylinder), Some(&material), true);
filename_scr = "screenshots/model.jpeg";
test_screenshot!( // !!!! Get a proper main loop !!!!
model.draw(token, Matrix::IDENTITY, None, None);
);

Tuple Fields§
§0: NonNull<_ModelT>
Implementations§
Source§impl Model
impl Model
Sourcepub fn new() -> Model
pub fn new() -> Model
Create an empty model https://stereokit.net/Pages/StereoKit/Model/Model.html
see also model_create
Model::default
§Examples
use stereokit_rust::{maths::{Vec3, Matrix}, model::Model, mesh::Mesh, material::Material};
// Let's create a model with two identical spheres.
let sphere = Mesh::generate_sphere(0.6, None);
let transform_mesh1 = Matrix::t([-0.7,-0.5, 0.0]);
let transform_mesh2 = Matrix::t([ 0.7, 0.5, 0.0]);
let transform_model = Matrix::r([ 0.0, 180.0, 0.0]);
let material = Material::pbr();
let model = Model::new();
let mut nodes = model.get_nodes();
assert_eq!(nodes.get_count(), 0);
nodes.add("sphere1", transform_mesh1, Some(&sphere), Some(&material), true);
nodes.add("sphere2", transform_mesh2, Some(&sphere), Some(&material), true);
assert_eq!(nodes.get_count(), 2);
test_steps!( // !!!! Get a proper main loop !!!!
model.draw(token, transform_model, None, None);
);
Sourcepub fn from_mesh<Me: AsRef<Mesh>, Ma: AsRef<Material>>(
mesh: Me,
material: Ma,
) -> Model
pub fn from_mesh<Me: AsRef<Mesh>, Ma: AsRef<Material>>( mesh: Me, material: Ma, ) -> Model
Creates a single mesh subset Model using the indicated Mesh and Material! An id will be automatically generated for this asset. https://stereokit.net/Pages/StereoKit/Model/FromMesh.html
mesh
- The mesh to use for this model.material
- The material to use for this mesh.
see also model_create_mesh
§Examples
use stereokit_rust::{maths::{Vec3, Matrix}, model::Model, mesh::Mesh, material::Material};
// Let's create a model with two identical spheres.
let sphere = Mesh::generate_sphere(0.8, None);
let transform_mesh1 = Matrix::t([-0.5,-0.5, 0.0]);
let transform_mesh2 = Matrix::t([ 0.5, 0.5, 0.0]);
let transform_model = Matrix::r([ 0.0, 150.0, 0.0]);
let material = Material::pbr();
let model = Model::from_mesh(&sphere, &material);
let mut nodes = model.get_nodes();
assert_eq!(nodes.get_count(), 1);
nodes.add("sphere2", transform_mesh1, Some(&sphere), Some(&material), true);
nodes.add("sphere3", transform_mesh2, Some(&sphere), Some(&material), true);
assert_eq!(nodes.get_count(), 3);
filename_scr = "screenshots/model_from_mesh.jpeg";
test_screenshot!( // !!!! Get a proper main loop !!!!
model.draw(token, transform_model, None, None);
);

Sourcepub fn from_memory<S: AsRef<str>>(
file_name: S,
data: &[u8],
shader: Option<Shader>,
) -> Result<Model, StereoKitError>
pub fn from_memory<S: AsRef<str>>( file_name: S, data: &[u8], shader: Option<Shader>, ) -> Result<Model, StereoKitError>
Loads a list of mesh and material subsets from a .obj, .stl, .ply (ASCII), .gltf, or .glb file stored in memory. Note that this function won’t work well on files that reference other files, such as .gltf files with references in them. https://stereokit.net/Pages/StereoKit/Model/FromMemory.html
file_name
- StereoKit still uses the filename of the data for format discovery, but not asset Id creation. If you don’t have a real filename for the data, just pass in an extension with a leading ‘.’ character here, like “.glb”.data
- The binary data of a model file, this is NOT a raw array of vertex and index data!shader
- The shader to use for the model’s materials!, if None, this will automatically determine the best available shader to use.
see also model_create_mem
Model::from_file
§Examples
use stereokit_rust::{maths::{Vec3, Matrix}, model::Model, util::named_colors};
let my_bytes = std::include_bytes!("../assets/plane.glb");
let model = Model::from_memory("my_bytes_center.glb", my_bytes, None).unwrap().copy();
let transform = Matrix::t_r_s(Vec3::Y * 0.10, [0.0, 110.0, 0.0], Vec3::ONE * 0.09);
filename_scr = "screenshots/model_from_memory.jpeg";
test_screenshot!( // !!!! Get a proper main loop !!!!
model.draw(token, transform, Some(named_colors::GREEN.into()), None);
);

Sourcepub fn from_file(
file: impl AsRef<Path>,
shader: Option<Shader>,
) -> Result<Model, StereoKitError>
pub fn from_file( file: impl AsRef<Path>, shader: Option<Shader>, ) -> Result<Model, StereoKitError>
Loads a list of mesh and material subsets from a .obj, .stl, .ply (ASCII), .gltf, or .glb file.
Important: The model is loaded only once. If you open the same file a second time, it will return the model loaded the first time and all its modifications afterwards. If you want two different instances, remember to copy the model while not forgetting that the assets that the copies contain when loaded are the same. https://stereokit.net/Pages/StereoKit/Model/FromFile.html
file
- Name of the file to load! This gets prefixed with the StereoKit asset folder if no drive letter is specified in the path.shader
- The shader to use for the model’s materials! If None, this will automatically determine the best shader available to use.
see also model_create_file
Model::from_memory
§Examples
use stereokit_rust::{maths::{Vec3, Matrix}, model::Model};
let model = Model::from_file("center.glb", None)
.expect("Could not load model").copy();
let transform = Matrix::t_r_s(Vec3::NEG_Y * 0.40, [0.0, 190.0, 0.0], Vec3::ONE * 0.25);
filename_scr = "screenshots/model_from_file.jpeg";
test_screenshot!( // !!!! Get a proper main loop !!!!
model.draw(token, transform, None, None);
);

Sourcepub fn copy(&self) -> Model
pub fn copy(&self) -> Model
Creates a shallow copy of a Model asset! Meshes and Materials referenced by this Model will be referenced, not copied. https://stereokit.net/Pages/StereoKit/Model/Copy.html
see also model_copy()
§Examples
use stereokit_rust::{maths::{Vec3, Matrix}, model::Model};
let model = Model::from_file("center.glb", None).expect("Model should load");
let model_copy = model.copy();
assert_ne!(model, model_copy);
assert_eq!(model.get_nodes().get_count(), model_copy.get_nodes().get_count());
// The nodes contains the same meshes as these are not copied.
assert_eq!(model.get_nodes().get_index(0).expect("Node should exist").get_mesh(),
model_copy.get_nodes().get_index(0).expect("Node should exist").get_mesh());
assert_eq!(model.get_nodes().get_index(2).expect("Node should exist").get_mesh(),
model_copy.get_nodes().get_index(2).expect("Node should exist").get_mesh());
Sourcepub fn find<S: AsRef<str>>(id: S) -> Result<Model, StereoKitError>
pub fn find<S: AsRef<str>>(id: S) -> Result<Model, StereoKitError>
Looks for a Model asset that’s already loaded, matching the given id! https://stereokit.net/Pages/StereoKit/Model/Find.html
id
- Which Model are you looking for?
see also model_find
Model::clone_ref
§Examples
use stereokit_rust::{maths::{Vec3, Matrix}, model::Model};
let mut model = Model::from_file("center.glb", None).expect("Model should load");
model.id("my_model_id");
let same_model = Model::find("my_model_id").expect("Model should be found");
assert_eq!(model, same_model);
Sourcepub fn clone_ref(&self) -> Model
pub fn clone_ref(&self) -> Model
Creates a clone of the same reference. Basically, the new variable is the same asset. This is what you get by calling find() method. https://stereokit.net/Pages/StereoKit/Model/Find.html
see also model_find
Model::find
§Examples
use stereokit_rust::{maths::{Vec3, Matrix}, model::Model};
let mut model = Model::from_file("center.glb", None).expect("Model should load");
let same_model = model.clone_ref();
assert_eq!(model, same_model);
Sourcepub fn id<S: AsRef<str>>(&mut self, id: S) -> &mut Self
pub fn id<S: AsRef<str>>(&mut self, id: S) -> &mut Self
Set a new id to the model. https://stereokit.net/Pages/StereoKit/Model/Id.html
see also model_set_id
§Examples
use stereokit_rust::{maths::{Vec3, Matrix}, model::Model};
let mut model = Model::new();
assert!(model.get_id().starts_with("auto/model_"));
model.id("my_model_id");
assert_eq!(model.get_id(), "my_model_id");
Sourcepub fn bounds(&mut self, bounds: impl AsRef<Bounds>) -> &mut Self
pub fn bounds(&mut self, bounds: impl AsRef<Bounds>) -> &mut Self
Set the bounds of this model. This is a bounding box that encapsulates the Model and all its subsets! It’s used for collision, visibility testing, UI layout, and probably other things. While it’s normally calculated from the mesh bounds, you can also override this to suit your needs. https://stereokit.net/Pages/StereoKit/Model/Bounds.html
see also model_set_bounds
§Examples
use stereokit_rust::{maths::{Vec3, Matrix, Bounds}, model::Model, mesh::Mesh,
material::Material, util::named_colors};
let cube_bounds = Mesh::cube();
let cube = Mesh::generate_cube(Vec3::ONE * 0.3, None);
let transform1 = Matrix::t([-0.30,-0.30,-0.30]);
let transform2 = Matrix::t([ 0.30, 0.30, 0.30]);
let material = Material::pbr();
let mut model = Model::new();
let mut nodes = model.get_nodes();
nodes.add("cube1", transform1, Some(&cube), Some(&material), true)
.add("cube2", transform2, Some(&cube), Some(&material), true);
let mut material_before = Material::ui_box();
material_before.color_tint(named_colors::GOLD)
.border_size(0.025);
let mut material_after = material_before.copy();
material_after.color_tint(named_colors::RED);
let bounds = model.get_bounds();
let transform_before = Matrix::t_s( bounds.center, bounds.dimensions);
assert_eq!(bounds.center, Vec3::ZERO);
assert_eq!(bounds.dimensions, Vec3::ONE * 0.9);
// let's reduce the bounds to the upper cube only
model.bounds( Bounds::new([0.30, 0.30, 0.30].into(), Vec3::ONE * 0.301));
let new_bounds = model.get_bounds();
let transform_after = Matrix::t_s( new_bounds.center, new_bounds.dimensions);
filename_scr = "screenshots/model_bounds.jpeg";
test_screenshot!( // !!!! Get a proper main loop !!!!
model.draw(token, Matrix::IDENTITY, None, None);
cube_bounds.draw( token, &material_before, transform_before, None, None);
cube_bounds.draw( token, &material_after, transform_after, None, None);
);

Sourcepub fn draw(
&self,
_token: &MainThreadToken,
transform: impl Into<Matrix>,
color_linear: Option<Color128>,
layer: Option<RenderLayer>,
)
pub fn draw( &self, _token: &MainThreadToken, transform: impl Into<Matrix>, color_linear: Option<Color128>, layer: Option<RenderLayer>, )
Adds this Model to the render queue for this frame! If the Hierarchy has a transform on it, that transform is combined with the Matrix provided here. https://stereokit.net/Pages/StereoKit/Model/Draw.html
token
- To be sure we are in the right thread, once per frame.transform
- A Matrix that will transform the Model from Model Space into the current Hierarchy Space.color_linear
- A per-instance linear space color value to pass into the shader! Normally this gets used like a material tint. If you’re adventurous and don’t need per-instance colors, this is a great spot to pack in extra per-instance data for the shader! If None has default value of WHITE.layer
- All visuals are rendered using a layer bit-flag. By default, all layers are rendered, but this can be useful for filtering out objects for different rendering purposes! For example: rendering a mesh over the user’s head from a 3rd person perspective, but filtering it out from the 1st person perspective. If None has default value of Layer0.
see also model_draw
Model::draw_with_material
§Examples
use stereokit_rust::{maths::{Vec3, Matrix}, model::Model, util::named_colors,
system::RenderLayer};
let model = Model::from_file("center.glb", None)
.expect("Could not load model").copy();
let transform1 = Matrix::t_r_s([-0.70, -0.70, 0.0], [0.0, 190.0, 0.0], [0.25, 0.25, 0.25]);
let transform2 = transform1 * Matrix::t(Vec3::X * 0.70);
let transform3 = transform2 * Matrix::t(Vec3::X * 0.70);
filename_scr = "screenshots/model_draw.jpeg";
test_screenshot!( // !!!! Get a proper main loop !!!!
model.draw(token, transform1, None, None);
model.draw(token, transform2, Some(named_colors::YELLOW.into()), None);
model.draw(token, transform3, Some(named_colors::BLACK.into()),
Some(RenderLayer::FirstPerson));
);

Sourcepub fn draw_with_material<M: AsRef<Material>>(
&self,
_token: &MainThreadToken,
material_override: M,
transform: impl Into<Matrix>,
color_linear: Option<Color128>,
layer: Option<RenderLayer>,
)
pub fn draw_with_material<M: AsRef<Material>>( &self, _token: &MainThreadToken, material_override: M, transform: impl Into<Matrix>, color_linear: Option<Color128>, layer: Option<RenderLayer>, )
Adds the model to the render queue of this frame overrided with the given material https://stereokit.net/Pages/StereoKit/Model/Draw.html
token
- To be sure we are in the right thread, once per frame.material_override
- the material that will override all materials of this modeltransform
- A Matrix that will transform the Model from Model Space into the current Hierarchy Space.color_linear
- A per-instance linear space color value to pass into the shader! Normally this gets used like a material tint. If you’re adventurous and don’t need per-instance colors, this is a great spot to pack in extra per-instance data for the shader! If None has default value of WHITE.layer
- All visuals are rendered using a layer bit-flag. By default, all layers are rendered, but this can be useful for filtering out objects for different rendering purposes! For example: rendering a mesh over the user’s head from a 3rd person perspective, but filtering it out from the 1st person perspective. If None has default value of Layer0.
see also model_draw
Model::draw
§Examples
use stereokit_rust::{maths::{Vec3, Matrix}, model::Model, util::named_colors,
material::Material, system::RenderLayer};
let model = Model::from_file("cuve.glb", None)
.expect("Could not load model").copy();
let transform1 = Matrix::t_r_s([-0.50, -0.10, 0.0], [45.0, 0.0, 0.0], [0.07, 0.07, 0.07]);
let transform2 = transform1 * Matrix::t(Vec3::X * 0.70);
let transform3 = transform2 * Matrix::t(Vec3::X * 0.70);
let mut material_ui = Material::ui_box();
material_ui.color_tint(named_colors::GOLD)
.border_size(0.01);
let material_brick =Material::from_file("shaders/brick_pbr.hlsl.sks",
Some("my_material_brick")).unwrap();
filename_scr = "screenshots/model_draw_with_material.jpeg";
test_screenshot!( // !!!! Get a proper main loop !!!!
model.draw_with_material(token, &material_ui, transform1, None, None);
model.draw_with_material(token, &material_brick, transform2, None, None);
model.draw_with_material(token, &material_ui, transform3, Some(named_colors::RED.into()),
Some(RenderLayer::FirstPerson));
);

Sourcepub fn recalculate_bounds(&self)
pub fn recalculate_bounds(&self)
Examines the visuals as they currently are, and rebuilds the bounds based on that! This is normally done automatically, but if you modify a Mesh that this Model is using, the Model can’t see it, and you should call this manually. https://stereokit.net/Pages/StereoKit/Model/RecalculateBounds.html
see also model_recalculate_bounds
Model::bounds
Model::recalculate_bounds_exact
§Examples
use stereokit_rust::{maths::{Vec2, Vec3, Matrix, Bounds}, mesh::{Mesh, Vertex},
model::Model, material::Material, util::named_colors};
let material = Material::pbr();
let mut square = Mesh::new();
square.set_verts(&[
Vertex::new([-1.0, -1.0, 0.0].into(), Vec3::UP, None, None),
Vertex::new([ 1.0, -1.0, 0.0].into(), Vec3::UP, Some(Vec2::X), None),
Vertex::new([-1.0, 1.0, 0.0].into(), Vec3::UP, Some(Vec2::Y), None),
], true)
.set_inds(&[0, 1, 2]);
let model = Model::from_mesh(&square, &material);
assert_eq!(model.get_bounds(), Bounds::new(Vec3::ZERO, Vec3::new(2.0, 2.0, 0.0)));
// We add a second vertex to our mesh adding the dimension-Z.
let mut vertices = square.get_verts_copy();
vertices.push(
Vertex::new([ 1.0, 1.0, 1.0].into(), Vec3::UP, Some(Vec2::ONE), None));
square.set_verts(&vertices, true)
.set_inds(&[0, 1, 2, 2, 1, 3]);
assert_eq!(model.get_bounds(), Bounds::new(Vec3::ZERO, Vec3::new(2.0, 2.0, 0.0)));
model.recalculate_bounds();
assert_eq!(model.get_bounds(), Bounds::new([0.0, 0.0, 0.5], [2.0, 2.0, 1.0]));
Sourcepub fn recalculate_bounds_exact(&self)
pub fn recalculate_bounds_exact(&self)
Examines the visuals as they currently are, and rebuilds the bounds based on all the vertices in the model! This leads (in general) to a tighter bound than the default bound based on bounding boxes. However, computing the exact bound can take much longer! https://stereokit.net/Pages/StereoKit/Model/RecalculateBoundsExact.html
see also model_recalculate_bounds_exact
Model::bounds
Model::recalculate_bounds
§Examples
use stereokit_rust::{maths::{Vec2, Vec3, Matrix, Bounds}, mesh::{Mesh, Vertex},
model::Model, material::Material, util::named_colors};
let material = Material::pbr();
let mut square = Mesh::new();
square.set_verts(&[
Vertex::new([-1.0, -1.0, 0.0].into(), Vec3::UP, None, None),
Vertex::new([ 1.0, -1.0, 0.0].into(), Vec3::UP, Some(Vec2::X), None),
Vertex::new([-1.0, 1.0, 0.0].into(), Vec3::UP, Some(Vec2::Y), None),
], true)
.set_inds(&[0, 1, 2]);
let model = Model::from_mesh(&square, &material);
assert_eq!(model.get_bounds(), Bounds::new(Vec3::ZERO, Vec3::new(2.0, 2.0, 0.0)));
// We add a second vertex to our mesh adding the dimension-Z.
let mut vertices = square.get_verts_copy();
vertices.push(
Vertex::new([ 1.0, 1.0, 1.0].into(), Vec3::UP, Some(Vec2::ONE), None));
square.set_verts(&vertices, true)
.set_inds(&[0, 1, 2, 2, 1, 3]);
assert_eq!(model.get_bounds(), Bounds::new(Vec3::ZERO, Vec3::new(2.0, 2.0, 0.0)));
model.recalculate_bounds_exact();
assert_eq!(model.get_bounds(), Bounds::new([0.0, 0.0, 0.5], [2.0, 2.0, 1.0]));
Sourcepub fn get_id(&self) -> &str
pub fn get_id(&self) -> &str
Get the Id https://stereokit.net/Pages/StereoKit/Model/Id.html
see also model_get_id
model_set_id
see example in Model::id
Sourcepub fn get_bounds(&self) -> Bounds
pub fn get_bounds(&self) -> Bounds
Get the bounds https://stereokit.net/Pages/StereoKit/Model/Bounds.html
see also model_get_bounds
model_set_bounds
see example in Model::bounds
Sourcepub fn get_nodes(&self) -> Nodes<'_>
pub fn get_nodes(&self) -> Nodes<'_>
Get the nodes https://stereokit.net/Pages/StereoKit/ModelNodeCollection.html
see also Nodes
§Examples
use stereokit_rust::{maths::{Vec3, Matrix, Bounds}, model::Model, mesh::Mesh,
material::Material, util::named_colors};
let cube_bounds = Mesh::cube();
let cube = Mesh::generate_cube(Vec3::ONE * 0.3, None);
let transform1 = Matrix::t([-0.30,-0.30,-0.30]);
let transform2 = Matrix::t([ 0.30, 0.30, 0.30]);
let transform3 = Matrix::t([ 1.30, 1.30, 1.30]);
let material = Material::pbr();
let mut model = Model::new();
let mut nodes = model.get_nodes();
nodes.add("cube1", transform1, Some(&cube), Some(&material), true)
.add("cube2", transform2, Some(&cube), Some(&material), true)
.add("not_a_mesh", transform3, None, None, true);
for (iter, node) in nodes.all().enumerate() {
match iter {
0 => assert_eq!(node.get_name(), Some("cube1")),
1 => assert_eq!(node.get_name(), Some("cube2")),
_ => assert_eq!(node.get_name(), Some("not_a_mesh")),
}
}
Sourcepub fn get_anims(&self) -> Anims<'_> ⓘ
pub fn get_anims(&self) -> Anims<'_> ⓘ
Get the anims https://stereokit.net/Pages/StereoKit/ModelAnimCollection.html
see also Anims
§Examples
use stereokit_rust::model::{Model, Anims, AnimMode};
let model = Model::from_file("mobiles.gltf", None)
.expect("Could not load model").copy();
let mut anims = model.get_anims();
assert_eq!(anims.get_count(), 3);
for (iter, anim) in anims.enumerate() {
match iter {
0 => assert_eq!(anim.name, "rotate"),
1 => assert_eq!(anim.name, "flyRotate"),
_ => assert_eq!(anim.name, "fly"),
}
}
model.get_anims().play_anim_idx(0, AnimMode::Loop);
Sourcepub fn intersect(&self, ray: Ray, cull: Option<Cull>) -> Option<Vec3>
pub fn intersect(&self, ray: Ray, cull: Option<Cull>) -> Option<Vec3>
Checks the intersection point of a ray and the Solid flagged Meshes in the Model’s visual nodes. Ray must be in model space, intersection point will be in model space too. You can use the inverse of the mesh’s world transform matrix to bring the ray into model space, see the example in the docs! https://stereokit.net/Pages/StereoKit/Model/Intersect.html
ray
- Ray must be in model space, the intersection point will be in model space too. You can use the inverse of the mesh’s world transform matrix to bring the ray into model space, see the example in the docs!cull
- How should intersection work with respect to the direction the triangles are facing? Should we skip triangles that are facing away from the ray, or don’t skip anything? If None has default value of Cull::Back.
see also model_ray_intersect
Model::intersect_to_ptr
same as Ray::intersect_model
§Examples
use stereokit_rust::{maths::{Vec3, Matrix, Bounds, Ray}, model::Model, mesh::Mesh,
material::{Material, Cull}, util::named_colors, system::Lines};
let cube_bounds = Mesh::cube();
let cube = Mesh::generate_cube(Vec3::ONE * 0.4, None);
let transform1 = Matrix::t([-0.30,-0.30,-0.30]);
let transform2 = Matrix::t([ 0.30, 0.30, 0.30]);
let material = Material::pbr();
let mut model = Model::new();
let mut nodes = model.get_nodes();
nodes.add("cube1", transform1, Some(&cube), Some(&material), true)
.add("cube2", transform2, Some(&cube), Some(&material), true);
let transform_model = Matrix::r([0.0, 15.0, 0.0]);
let inv = transform_model.get_inverse();
let ray = Ray::from_to([-0.80, -2.8, -1.0],[0.35, 2.5, 1.0]);
let inv_ray = inv.transform_ray(ray);
let contact_model = model.intersect(inv_ray, Some(Cull::Front))
.expect("Intersection should be found");
let transform_contact_model = Matrix::t(transform_model.transform_point(contact_model));
let point = Mesh::generate_sphere(0.1, Some(2));
let material = Material::pbr();
let mut material_bounds = Material::ui_box();
material_bounds .color_tint(named_colors::GOLD)
.border_size(0.025);
let bounds = model.get_bounds();
let transform_before = transform_model * Matrix::t_s( bounds.center, bounds.dimensions);
filename_scr = "screenshots/model_intersect.jpeg";
test_screenshot!( // !!!! Get a proper main loop !!!!
model.draw(token, transform_model, None, None);
cube_bounds.draw( token, &material_bounds, transform_before, None, None);
Lines::add_ray(token, ray, 7.2, named_colors::BLUE, Some(named_colors::RED.into()), 0.02);
point.draw(token, &material, transform_contact_model,
Some(named_colors::RED.into()), None );
);

Sourcepub fn intersect_to_ptr(
&self,
ray: Ray,
cull: Option<Cull>,
out_ray: *mut Ray,
) -> bool
pub fn intersect_to_ptr( &self, ray: Ray, cull: Option<Cull>, out_ray: *mut Ray, ) -> bool
Checks the intersection point of a ray and the Solid flagged Meshes in the Model’s visual nodes. Ray must be in model space, intersection point will be in model space too. You can use the inverse of the mesh’s world transform matrix to bring the ray into model space, see the example in the docs! https://stereokit.net/Pages/StereoKit/Model/Intersect.html
ray
- Ray must be in model space, the intersection point will be in model space too. You can use the inverse of the mesh’s world transform matrix to bring the ray into model space, see the example in the docs!cull
- How should intersection work with respect to the direction the triangles are facing? Should we skip triangles that are facing away from the ray, or don’t skip anything? If None has default value of Cull::Back.out_ray
- The intersection point and surface direction of the ray and the mesh, if an intersection occurs. This is in model space, and must be transformed back into world space later. Direction is not guaranteed to be normalized, especially if your own model->world transform contains scale/skew in it.
see also model_ray_intersect
Model::intersect
same as Ray::intersect_model_to_ptr
§Examples
use stereokit_rust::{maths::{Vec3, Matrix, Bounds, Ray}, model::Model, mesh::Mesh,
material::{Material, Cull}, util::named_colors, system::Lines};
let cube_bounds = Mesh::cube();
let cube = Mesh::generate_cube(Vec3::ONE * 0.4, None);
let transform1 = Matrix::t([-0.30,-0.30,-0.30]);
let transform2 = Matrix::t([ 0.30, 0.30, 0.30]);
let material = Material::pbr();
let mut model = Model::new();
let mut nodes = model.get_nodes();
nodes.add("cube1", transform1, Some(&cube), Some(&material), true)
.add("cube2", transform2, Some(&cube), Some(&material), true);
let transform_model = Matrix::r([0.0, 15.0, 0.0]);
let inv = transform_model.get_inverse();
let ray = Ray::from_to([-0.80, -2.8, -1.0],[0.35, 2.5, 1.0]);
let inv_ray = inv.transform_ray(ray);
let mut inv_contact_model_ray = Ray::default();
assert!( model.intersect_to_ptr(inv_ray, Some(Cull::Front), &mut inv_contact_model_ray)
,"Ray should touch model");
let contact_model_ray = transform_model.transform_ray(inv_contact_model_ray);
assert_eq!(contact_model_ray,
Ray { position: Vec3 { x: -0.24654332, y: -0.24928647, z: -0.037466552 },
direction: Vec3 { x: 0.25881907, y: 0.0, z: 0.9659258 } });
Trait Implementations§
Source§impl Default for Model
impl Default for Model
Source§fn default() -> Self
fn default() -> Self
Create an empty model https://stereokit.net/Pages/StereoKit/Model/Model.html
see also Model::new
Source§impl IAsset for Model
impl IAsset for Model
Source§fn get_id(&self) -> &str
fn get_id(&self) -> &str
impl StructuralPartialEq for Model
Auto Trait Implementations§
impl Freeze for Model
impl RefUnwindSafe for Model
impl !Send for Model
impl !Sync for Model
impl Unpin for Model
impl UnwindSafe for Model
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait>
(where Trait: Downcast
) to Box<dyn Any>
. Box<dyn Any>
can
then be further downcast
into Box<ConcreteType>
where ConcreteType
implements Trait
.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait>
(where Trait: Downcast
) to Rc<Any>
. Rc<Any>
can then be
further downcast
into Rc<ConcreteType>
where ConcreteType
implements Trait
.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &Any
’s vtable from &Trait
’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &mut Any
’s vtable from &mut Trait
’s.