primitives generates IndexedModel

This commit is contained in:
Quaternions 2023-09-28 15:43:10 -07:00
parent 39861c526b
commit bd191c65a1
2 changed files with 86 additions and 58 deletions

View File

@ -3,14 +3,14 @@ use bytemuck::{Pod, Zeroable};
#[repr(C)] #[repr(C)]
pub struct Vertex { pub struct Vertex {
pub pos: [f32; 3], pub pos: [f32; 3],
pub texture: [f32; 2], pub tex: [f32; 2],
pub normal: [f32; 3], pub normal: [f32; 3],
pub color: [f32; 4], pub color: [f32; 4],
} }
#[derive(Hash)] #[derive(Hash,PartialEq,Eq)]
pub struct IndexedVertex{ pub struct IndexedVertex{
pub pos:u32, pub pos:u32,
pub texture:u32, pub tex:u32,
pub normal:u32, pub normal:u32,
pub color:u32, pub color:u32,
} }
@ -23,7 +23,7 @@ pub struct IndexedGroup{
} }
pub struct IndexedModel{ pub struct IndexedModel{
pub unique_pos:Vec<[f32; 3]>, pub unique_pos:Vec<[f32; 3]>,
pub unique_texture:Vec<[f32; 2]>, pub unique_tex:Vec<[f32; 2]>,
pub unique_normal:Vec<[f32; 3]>, pub unique_normal:Vec<[f32; 3]>,
pub unique_color:Vec<[f32; 4]>, pub unique_color:Vec<[f32; 4]>,
pub unique_vertices:Vec<IndexedVertex>, pub unique_vertices:Vec<IndexedVertex>,
@ -59,7 +59,7 @@ pub fn generate_indexed_model_from_obj(data:obj::ObjData,color:[f32;4]) -> Vec<I
let i=unique_vertices.len() as u32; let i=unique_vertices.len() as u32;
unique_vertices.push(IndexedVertex{ unique_vertices.push(IndexedVertex{
pos: tup.0 as u32, pos: tup.0 as u32,
texture: tup.1.unwrap() as u32, tex: tup.1.unwrap() as u32,
normal: tup.2.unwrap() as u32, normal: tup.2.unwrap() as u32,
color: 0, color: 0,
}); });
@ -73,7 +73,7 @@ pub fn generate_indexed_model_from_obj(data:obj::ObjData,color:[f32;4]) -> Vec<I
}).collect(); }).collect();
IndexedModel{ IndexedModel{
unique_pos: data.position, unique_pos: data.position,
unique_texture: data.texture, unique_tex: data.texture,
unique_normal: data.normal, unique_normal: data.normal,
unique_color: vec![color], unique_color: vec![color],
unique_vertices, unique_vertices,

View File

@ -1,3 +1,5 @@
use crate::model::{IndexedModel, IndexedPolygon, IndexedGroup, IndexedVertex};
const CUBE_DEFAULT_TEXTURE_COORDS:[[f32;2];4]=[[0.0,0.0],[1.0,0.0],[1.0,1.0],[0.0,1.0]]; const CUBE_DEFAULT_TEXTURE_COORDS:[[f32;2];4]=[[0.0,0.0],[1.0,0.0],[1.0,1.0],[0.0,1.0]];
const CUBE_DEFAULT_VERTICES:[[f32;3];8]=[ const CUBE_DEFAULT_VERTICES:[[f32;3];8]=[
[-1.,-1., 1.],//0 left bottom back [-1.,-1., 1.],//0 left bottom back
@ -20,7 +22,7 @@ const CUBE_DEFAULT_NORMALS:[[f32;3];6]=[
const CUBE_DEFAULT_POLYS:[[[u32;3];4];6]=[ const CUBE_DEFAULT_POLYS:[[[u32;3];4];6]=[
// right (1, 0, 0) // right (1, 0, 0)
[ [
[6,2,0],//[vert,tex,norm] [6,2,0],//[vertex,tex,norm]
[5,1,0], [5,1,0],
[2,0,0], [2,0,0],
[1,3,0], [1,3,0],
@ -61,82 +63,108 @@ const CUBE_DEFAULT_POLYS:[[[u32;3];4];6]=[
[7,2,5], [7,2,5],
], ],
]; ];
pub fn the_unit_cube_lol() -> crate::model::ModelData{ pub fn the_unit_cube_lol() -> crate::model::IndexedModel{
generate_partial_unit_cube([Some(FaceDescription::default());6],None) generate_partial_unit_cube([Some(FaceDescription::default());6])
} }
#[derive(Copy,Clone)]
pub struct FaceDescription{ pub struct FaceDescription{
texture:Option<u32>,
transform:glam::Affine2, transform:glam::Affine2,
color:glam::Vec4, color:glam::Vec4,
} }
impl std::default::Default for FaceDescription{ impl std::default::Default for FaceDescription{
fn default() -> Self { fn default() -> Self {
Self{ Self{
texture:None,
transform:glam::Affine2::IDENTITY, transform:glam::Affine2::IDENTITY,
color:glam::Vec4::ONE, color:glam::Vec4::ONE,
} }
} }
} }
impl FaceDescription{ impl FaceDescription{
pub fn new(transform:glam::Affine2,color:glam::Vec4)->Self{ pub fn new(texture:u32,transform:glam::Affine2,color:glam::Vec4)->Self{
Self{transform,color} Self{texture:Some(texture),transform,color}
}
pub fn from_texture(texture:u32)->Self{
Self{
texture:Some(texture),
transform:glam::Affine2::IDENTITY,
color:glam::Vec4::ONE,
}
} }
} }
pub fn generate_partial_unit_cube(face_transforms:[Option<FaceDescription>;6],texture:Option<u32>) -> crate::model::ModelData{ //generate transformed vertices //TODO: it's probably better to use a shared vertex buffer between all primitives and use indexed rendering instead of generating a unique vertex buffer for each primitive.
let mut generated_verts=Vec::new(); pub fn generate_partial_unit_cube(face_descriptions:[Option<FaceDescription>;6]) -> crate::model::IndexedModel{
let mut generated_pos=Vec::<[f32;3]>::new();
let mut generated_tex=Vec::new();
let mut generated_normal=Vec::new();
let mut generated_color=Vec::new();
let mut generated_vertices=Vec::new();
let mut groups=Vec::new();
let mut transforms=Vec::new(); let mut transforms=Vec::new();
let mut generated_polys=Vec::new(); //note that on a cube every vertex is guaranteed to be unique, so there's no need to hash them against existing vertices.
for (i,maybe_transform) in face_transforms.iter().enumerate(){ for (i,maybe_face_description) in face_descriptions.iter().enumerate(){
if let Some(transform)=maybe_transform{ if let Some(face_description)=maybe_face_description{
let transform_index=if let Some(transform_index)=transforms.iter().position(|&t|t==transform){ //assume that scanning short lists is faster than hashing.
let transform_index=if let Some(transform_index)=transforms.iter().position(|&transform|transform==face_description.transform){
transform_index transform_index
}else{ }else{
//create new transform_index //create new transform_index
let transform_index=transforms.len(); let transform_index=transforms.len();
transforms.push(transform); transforms.push(face_description.transform);
for vert in default_verts{ for tex in CUBE_DEFAULT_TEXTURE_COORDS{
generated_verts.push(*transform.transform_point2(glam::vec2(vert[0],vert[1])).as_ref()); generated_tex.push(*face_description.transform.transform_point2(glam::Vec2::from_array(tex)).as_ref());
} }
transform_index transform_index
}; } as u32;
generated_polys.push(obj::SimplePolygon( let color_index=if let Some(color_index)=generated_color.iter().position(|color|color==face_description.color.as_ref()){
default_polys[i].0.iter().map( color_index
|&v|obj::IndexTuple(v.0,Some(v.1.unwrap()+4*transform_index),v.2) }else{
).collect() //create new color_index
)); let color_index=generated_color.len();
generated_color.push(*face_description.color.as_ref());
color_index
} as u32;
//always push normal
let normal_index=generated_normal.len() as u32;
generated_normal.push(CUBE_DEFAULT_NORMALS[i]);
//push vertices as they are needed
groups.push(IndexedGroup{
texture:face_description.texture,
polys:vec![IndexedPolygon{
vertices:CUBE_DEFAULT_POLYS[i].map(|tup|{
let pos=CUBE_DEFAULT_VERTICES[tup[0] as usize];
let pos_index=if let Some(pos_index)=generated_pos.iter().position(|&p|p==pos){
pos_index
}else{
//create new pos_index
let pos_index=generated_pos.len();
generated_pos.push(pos);
pos_index
} as u32;
//always push vertex
let vertex=IndexedVertex{
pos:pos_index,
tex:tup[1]+4*transform_index,
normal:normal_index,
color:color_index,
};
let vert_index=generated_vertices.len();
generated_vertices.push(vertex);
vert_index as u32
}).to_vec(),
}],
});
} }
} }
let mut vertices = Vec::new(); IndexedModel{
let mut vertex_index = std::collections::HashMap::<obj::IndexTuple,u16>::new(); unique_pos:generated_pos,
let mut entities = Vec::new(); unique_tex:generated_tex,
for group in object.groups { unique_normal:generated_normal,
let mut indices = Vec::new(); unique_color:generated_color,
for poly in group.polys { unique_vertices:generated_vertices,
for end_index in 2..poly.0.len() { groups,
for &index in &[0, end_index - 1, end_index] { instances:Vec::new(),
let vert = poly.0[index];
if let Some(&i)=vertex_index.get(&vert){
indices.push(i);
}else{
let i=vertices.len() as u16;
vertices.push(Vertex {
pos: data.position[vert.0],
texture: data.texture[vert.1.unwrap()],
normal: data.normal[vert.2.unwrap()],
color,
});
vertex_index.insert(vert,i);
indices.push(i);
}
}
}
}
entities.push(indices);
}
ModelData {
instances: Vec::new(),
vertices,
entities,
texture,
} }
} }