1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
//! Blender files can have meshes such as circles, cubes, cylinders, a dragon or any other //! 3D shape. //! //! A mesh can be represented as a group of vertices and data about those vertices, such as their //! normals or UV coordinates. //! //! Meshes can also have metadata, such as the name of it's parent armature (useful for vertex //! skinning). //! //! blender-mesh-to-json seeks to be a well tested, well documented exporter for blender mesh //! metadata. //! //! You can write data to stdout or to a file. At the onset it will be geared towards @chinedufn's //! needs - but if you have needs that aren't met feel very free to open an issue. //! //! @see https://docs.blender.org/manual/en/dev/modeling/meshes/introduction.html - Mesh Introduction //! @see https://github.com/chinedufn/blender-actions-to-json - Exporting blender armatures / actions #[macro_use] extern crate failure; #[macro_use] extern crate serde_derive; #[macro_use] extern crate log; pub use self::combine_indices::CreateSingleIndexConfig; pub use self::export::*; use crate::bone::BoneInfluencesPerVertex; use crate::bounding_box::BoundingBox; use crate::material::PrincipledBSDF; use crate::vertex_data::{VertexAttribute, VertexData}; pub use material::{Channel, MaterialInput}; use serde_json; use serde_json::Error; use std::collections::HashMap; mod bone; mod bounding_box; mod combine_indices; mod export; mod individual_vertex; mod material; mod tangent; mod triangulate; mod vertex_data; mod y_up; #[cfg(test)] mod test_utils; /// Something went wrong in the Blender child process that was trying to parse your mesh data. #[derive(Debug, Fail)] pub enum BlenderError { /// Errors in Blender are written to stderr. We capture the stderr from the `blender` child /// process that we spawned when attempting to export meshes from a `.blend` file. #[fail( display = "There was an issue while exporting meshes: Blender stderr output: {}", _0 )] Stderr(String), } /// All of the data about a Blender mesh #[derive(Debug, Serialize, Deserialize, PartialEq)] #[cfg_attr(test, derive(Default))] #[serde(deny_unknown_fields)] pub struct BlenderMesh { /// All of the mesh's vertices. Three items in the vector make one vertex. /// So indices 0, 1 and 2 are a vertex, 3, 4 and 5 are a vertex.. etc. /// [v1x, v1y, v1z, v2x, v2y, v2z, ...] pub vertex_positions: Vec<f32>, /// The indices within vertex positions that make up each triangle in our mesh. /// Three vertex position indices correspond to one triangle /// [0, 1, 2, 0, 2, 3, ...] pub vertex_position_indices: Vec<u16>, /// TODO: enum..? if they're all equal we replace the MyEnum::PerVertex(Vec<u8>) with MyEnum::Equal(4) pub num_vertices_in_each_face: Vec<u8>, pub vertex_normals: Vec<f32>, pub vertex_normal_indices: Option<Vec<u16>>, /// If your mesh is textured these will be all of the mesh's vertices' uv coordinates. /// Every vertex has two UV coordinates. /// [v1s, v1t, v2s, v2t, v3s, v3t] /// TODO: Combine vertex_uvs, vertex_uv_indices, texture_name into texture_info pub vertex_uvs: Option<Vec<f32>>, pub vertex_uv_indices: Option<Vec<u16>>, pub armature_name: Option<String>, /// TODO: When we move to single index triangulate and add new vertices give those vertices the same group indices / weights /// TODO: A function that trims this down to `n` weights and indices per vertex. Similar to our /// triangulate function /// TODO: Make sure that when we combine vertex indices we expand our group weights pub vertex_group_indices: Option<Vec<u8>>, pub vertex_group_weights: Option<Vec<f32>>, /// TODO: enum..? if they're all equal we replace the MyEnum::PerVertex(Vec<u8>) with MyEnum::Equal(4) bone_influences_per_vertex: Option<BoneInfluencesPerVertex>, pub bounding_box: BoundingBox, /// A map of material name (in Blender) to the material's data materials: HashMap<String, PrincipledBSDF>, /// Tangent vectors per vertex, useful for normal mapping. /// /// These get set during [`BlenderMesh.combine_indices`], if there are triangle_tangents. /// /// Useful for normal mapping. per_vertex_tangents: Option<VertexAttribute>, /// Tangent vector to the vertex, calculated using [`BlenderMesh.calculate_face_tangents`]. /// /// [`BlenderMesh.calculate_face_tangents`]: struct.BlenderMesh.html#method.calculate_face_tangents face_tangents: Option<Vec<f32>>, // FIXME: Temporary move all of the vertex data above into VertexData // Then we no longer need default .. it'll be required #[serde(default)] vertex_data: VertexData, } impl BlenderMesh { // TODO: Delete this.. let the consumer worry about serializing / deserializing pub fn from_json(json_str: &str) -> Result<BlenderMesh, Error> { serde_json::from_str(json_str) } } /// Concatenate a series of vectors into one vector. /// /// Useful for generating fake vertex data for unit tests. /// /// ```ignore /// assert_eq!( /// concat_vecs!(vec![1, 2, 3], vec![4,5]), /// vec![1, 2, 3, 4, 5] /// ); /// ``` #[cfg(test)] #[macro_export] #[cfg(test)] macro_rules! concat_vecs { ( $( $vec:expr),* ) => { { let mut concatenated_vec = Vec::new(); $( concatenated_vec.append(&mut $vec.clone()); )* concatenated_vec } } }