Struct Model

Source
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);
);
screenshot

Tuple Fields§

§0: NonNull<_ModelT>

Implementations§

Source§

impl Model

Source

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);
);
Source

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);
);
screenshot
Source

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);
);
screenshot
Source

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);
);
screenshot
Source

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());
Source

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);
Source

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);
Source

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");
Source

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);
);
screenshot
Source

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));
);
screenshot
Source

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 model
  • 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

§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));
);
screenshot
Source

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]));
Source

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]));
Source

pub fn get_id(&self) -> &str

Source

pub fn get_bounds(&self) -> Bounds

Source

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")),
   }
}
Source

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);
Source

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 );
);
screenshot
Source

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 AsRef<Model> for Model

AsRef

Source§

fn as_ref(&self) -> &Model

Converts this type into a shared reference of the (usually inferred) input type.
Source§

impl Debug for Model

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Model

Source§

impl Drop for Model

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

impl From<Model> for ModelT

From / Into

Source§

fn from(val: Model) -> Self

Converts to this type from the input type.
Source§

impl IAsset for Model

Source§

fn get_id(&self) -> &str

gets the unique identifier of this asset resource! This can be helpful for debugging, managing your assets, or finding them later on! https://stereokit.net/Pages/StereoKit/IAsset/Id.html
Source§

impl PartialEq for Model

Source§

fn eq(&self, other: &Model) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

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> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert 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>

Convert 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)

Convert &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)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more