/* Create vertex color attributes. */ static void attr_create_vertex_color(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh, bool subdivision) { if (subdivision) { BL::Mesh::vertex_colors_iterator l; for (b_mesh.vertex_colors.begin(l); l != b_mesh.vertex_colors.end(); ++l) { if (!mesh->need_attribute(scene, ustring(l->name().c_str()))) continue; Attribute *attr = mesh->subd_attributes.add( ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CORNER_BYTE); BL::Mesh::polygons_iterator p; uchar4 *cdata = attr->data_uchar4(); for (b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) { int n = p->loop_total(); for (int i = 0; i < n; i++) { float3 color = get_float3(l->data[p->loop_start() + i].color()); /* Compress/encode vertex color using the sRGB curve. */ *(cdata++) = color_float_to_byte(color_srgb_to_linear_v3(color)); } } } } else { BL::Mesh::vertex_colors_iterator l; for (b_mesh.vertex_colors.begin(l); l != b_mesh.vertex_colors.end(); ++l) { if (!mesh->need_attribute(scene, ustring(l->name().c_str()))) continue; Attribute *attr = mesh->attributes.add( ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CORNER_BYTE); BL::Mesh::loop_triangles_iterator t; uchar4 *cdata = attr->data_uchar4(); for (b_mesh.loop_triangles.begin(t); t != b_mesh.loop_triangles.end(); ++t) { int3 li = get_int3(t->loops()); float3 c1 = get_float3(l->data[li[0]].color()); float3 c2 = get_float3(l->data[li[1]].color()); float3 c3 = get_float3(l->data[li[2]].color()); /* Compress/encode vertex color using the sRGB curve. */ cdata[0] = color_float_to_byte(color_srgb_to_linear_v3(c1)); cdata[1] = color_float_to_byte(color_srgb_to_linear_v3(c2)); cdata[2] = color_float_to_byte(color_srgb_to_linear_v3(c3)); cdata += 3; } } } }
static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh, const vector<Shader *> &used_shaders, bool subdivision = false, bool subdivide_uvs = true) { /* count vertices and faces */ int numverts = b_mesh.vertices.length(); int numfaces = (!subdivision) ? b_mesh.loop_triangles.length() : b_mesh.polygons.length(); int numtris = 0; int numcorners = 0; int numngons = 0; bool use_loop_normals = b_mesh.use_auto_smooth() && (mesh->subdivision_type != Mesh::SUBDIVISION_CATMULL_CLARK); /* If no faces, create empty mesh. */ if (numfaces == 0) { return; } if (!subdivision) { numtris = numfaces; } else { BL::Mesh::polygons_iterator p; for (b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) { numngons += (p->loop_total() == 4) ? 0 : 1; numcorners += p->loop_total(); } } /* allocate memory */ mesh->reserve_mesh(numverts, numtris); mesh->reserve_subd_faces(numfaces, numngons, numcorners); /* create vertex coordinates and normals */ BL::Mesh::vertices_iterator v; for (b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v) mesh->add_vertex(get_float3(v->co())); AttributeSet &attributes = (subdivision) ? mesh->subd_attributes : mesh->attributes; Attribute *attr_N = attributes.add(ATTR_STD_VERTEX_NORMAL); float3 *N = attr_N->data_float3(); for (b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v, ++N) *N = get_float3(v->normal()); N = attr_N->data_float3(); /* create generated coordinates from undeformed coordinates */ const bool need_default_tangent = (subdivision == false) && (b_mesh.uv_layers.length() == 0) && (mesh->need_attribute(scene, ATTR_STD_UV_TANGENT)); if (mesh->need_attribute(scene, ATTR_STD_GENERATED) || need_default_tangent) { Attribute *attr = attributes.add(ATTR_STD_GENERATED); attr->flags |= ATTR_SUBDIVIDED; float3 loc, size; mesh_texture_space(b_mesh, loc, size); float3 *generated = attr->data_float3(); size_t i = 0; for (b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v) { generated[i++] = get_float3(v->undeformed_co()) * size - loc; } } /* create faces */ if (!subdivision) { BL::Mesh::loop_triangles_iterator t; for (b_mesh.loop_triangles.begin(t); t != b_mesh.loop_triangles.end(); ++t) { BL::MeshPolygon p = b_mesh.polygons[t->polygon_index()]; int3 vi = get_int3(t->vertices()); int shader = clamp(p.material_index(), 0, used_shaders.size() - 1); bool smooth = p.use_smooth() || use_loop_normals; if (use_loop_normals) { BL::Array<float, 9> loop_normals = t->split_normals(); for (int i = 0; i < 3; i++) { N[vi[i]] = make_float3( loop_normals[i * 3], loop_normals[i * 3 + 1], loop_normals[i * 3 + 2]); } } /* Create triangles. * * NOTE: Autosmooth is already taken care about. */ mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth); } } else { BL::Mesh::polygons_iterator p; vector<int> vi; for (b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) { int n = p->loop_total(); int shader = clamp(p->material_index(), 0, used_shaders.size() - 1); bool smooth = p->use_smooth() || use_loop_normals; vi.resize(n); for (int i = 0; i < n; i++) { /* NOTE: Autosmooth is already taken care about. */ vi[i] = b_mesh.loops[p->loop_start() + i].vertex_index(); } /* create subd faces */ mesh->add_subd_face(&vi[0], n, shader, smooth); } } /* Create all needed attributes. * The calculate functions will check whether they're needed or not. */ attr_create_pointiness(scene, mesh, b_mesh, subdivision); attr_create_vertex_color(scene, mesh, b_mesh, subdivision); if (subdivision) { attr_create_subd_uv_map(scene, mesh, b_mesh, subdivide_uvs); } else { attr_create_uv_map(scene, mesh, b_mesh); } /* for volume objects, create a matrix to transform from object space to * mesh texture space. this does not work with deformations but that can * probably only be done well with a volume grid mapping of coordinates */ if (mesh->need_attribute(scene, ATTR_STD_GENERATED_TRANSFORM)) { Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED_TRANSFORM); Transform *tfm = attr->data_transform(); float3 loc, size; mesh_texture_space(b_mesh, loc, size); *tfm = transform_translate(-loc) * transform_scale(size); } }
static void attr_create_subd_uv_map(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh, bool subdivide_uvs) { if (b_mesh.uv_layers.length() != 0) { BL::Mesh::uv_layers_iterator l; int i = 0; for (b_mesh.uv_layers.begin(l); l != b_mesh.uv_layers.end(); ++l, ++i) { bool active_render = l->active_render(); AttributeStandard uv_std = (active_render) ? ATTR_STD_UV : ATTR_STD_NONE; ustring uv_name = ustring(l->name().c_str()); AttributeStandard tangent_std = (active_render) ? ATTR_STD_UV_TANGENT : ATTR_STD_NONE; ustring tangent_name = ustring((string(l->name().c_str()) + ".tangent").c_str()); /* Denotes whether UV map was requested directly. */ const bool need_uv = mesh->need_attribute(scene, uv_name) || mesh->need_attribute(scene, uv_std); /* Denotes whether tangent was requested directly. */ const bool need_tangent = mesh->need_attribute(scene, tangent_name) || (active_render && mesh->need_attribute(scene, tangent_std)); Attribute *uv_attr = NULL; /* UV map */ if (need_uv || need_tangent) { if (active_render) uv_attr = mesh->subd_attributes.add(uv_std, uv_name); else uv_attr = mesh->subd_attributes.add(uv_name, TypeFloat2, ATTR_ELEMENT_CORNER); if (subdivide_uvs) { uv_attr->flags |= ATTR_SUBDIVIDED; } BL::Mesh::polygons_iterator p; float2 *fdata = uv_attr->data_float2(); for (b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) { int n = p->loop_total(); for (int j = 0; j < n; j++) { *(fdata++) = get_float2(l->data[p->loop_start() + j].uv()); } } } /* UV tangent */ if (need_tangent) { AttributeStandard sign_std = (active_render) ? ATTR_STD_UV_TANGENT_SIGN : ATTR_STD_NONE; ustring sign_name = ustring((string(l->name().c_str()) + ".tangent_sign").c_str()); bool need_sign = (mesh->need_attribute(scene, sign_name) || mesh->need_attribute(scene, sign_std)); mikk_compute_tangents(b_mesh, l->name().c_str(), mesh, need_sign, active_render); } /* Remove temporarily created UV attribute. */ if (!need_uv && uv_attr != NULL) { mesh->subd_attributes.remove(uv_attr); } } } else if (mesh->need_attribute(scene, ATTR_STD_UV_TANGENT)) { bool need_sign = mesh->need_attribute(scene, ATTR_STD_UV_TANGENT_SIGN); mikk_compute_tangents(b_mesh, NULL, mesh, need_sign, true); if (!mesh->need_attribute(scene, ATTR_STD_GENERATED)) { mesh->subd_attributes.remove(ATTR_STD_GENERATED); } } }
static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh& b_mesh, const vector<Shader*>& used_shaders, bool subdivision=false, bool subdivide_uvs=true) { /* count vertices and faces */ int numverts = b_mesh.vertices.length(); int numfaces = (!subdivision) ? b_mesh.tessfaces.length() : b_mesh.polygons.length(); int numtris = 0; int numcorners = 0; int numngons = 0; bool use_loop_normals = b_mesh.use_auto_smooth() && (mesh->subdivision_type != Mesh::SUBDIVISION_CATMULL_CLARK); BL::Mesh::vertices_iterator v; BL::Mesh::tessfaces_iterator f; BL::Mesh::polygons_iterator p; if(!subdivision) { for(b_mesh.tessfaces.begin(f); f != b_mesh.tessfaces.end(); ++f) { int4 vi = get_int4(f->vertices_raw()); numtris += (vi[3] == 0)? 1: 2; } } else { for(b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) { numngons += (p->loop_total() == 4)? 0: 1; numcorners += p->loop_total(); } } /* allocate memory */ mesh->reserve_mesh(numverts, numtris); mesh->reserve_subd_faces(numfaces, numngons, numcorners); /* create vertex coordinates and normals */ for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v) mesh->add_vertex(get_float3(v->co())); AttributeSet& attributes = (subdivision)? mesh->subd_attributes: mesh->attributes; Attribute *attr_N = attributes.add(ATTR_STD_VERTEX_NORMAL); float3 *N = attr_N->data_float3(); for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v, ++N) *N = get_float3(v->normal()); N = attr_N->data_float3(); /* create generated coordinates from undeformed coordinates */ if(mesh->need_attribute(scene, ATTR_STD_GENERATED)) { Attribute *attr = attributes.add(ATTR_STD_GENERATED); attr->flags |= ATTR_SUBDIVIDED; float3 loc, size; mesh_texture_space(b_mesh, loc, size); float3 *generated = attr->data_float3(); size_t i = 0; for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v) generated[i++] = get_float3(v->undeformed_co())*size - loc; } /* Create needed vertex attributes. */ attr_create_pointiness(scene, mesh, b_mesh, subdivision); /* create faces */ vector<int> nverts(numfaces); vector<int> face_flags(numfaces, FACE_FLAG_NONE); int fi = 0; if(!subdivision) { for(b_mesh.tessfaces.begin(f); f != b_mesh.tessfaces.end(); ++f, ++fi) { int4 vi = get_int4(f->vertices_raw()); int n = (vi[3] == 0)? 3: 4; int shader = clamp(f->material_index(), 0, used_shaders.size()-1); bool smooth = f->use_smooth() || use_loop_normals; /* split vertices if normal is different * * note all vertex attributes must have been set here so we can split * and copy attributes in split_vertex without remapping later */ if(use_loop_normals) { BL::Array<float, 12> loop_normals = f->split_normals(); for(int i = 0; i < n; i++) { float3 loop_N = make_float3(loop_normals[i * 3], loop_normals[i * 3 + 1], loop_normals[i * 3 + 2]); if(N[vi[i]] != loop_N) { int new_vi = mesh->split_vertex(vi[i]); /* set new normal and vertex index */ N = attr_N->data_float3(); N[new_vi] = loop_N; vi[i] = new_vi; } } } /* create triangles */ if(n == 4) { if(is_zero(cross(mesh->verts[vi[1]] - mesh->verts[vi[0]], mesh->verts[vi[2]] - mesh->verts[vi[0]])) || is_zero(cross(mesh->verts[vi[2]] - mesh->verts[vi[0]], mesh->verts[vi[3]] - mesh->verts[vi[0]]))) { mesh->add_triangle(vi[0], vi[1], vi[3], shader, smooth); mesh->add_triangle(vi[2], vi[3], vi[1], shader, smooth); face_flags[fi] |= FACE_FLAG_DIVIDE_24; } else { mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth); mesh->add_triangle(vi[0], vi[2], vi[3], shader, smooth); face_flags[fi] |= FACE_FLAG_DIVIDE_13; } } else { mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth); } nverts[fi] = n; } } else { vector<int> vi; for(b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) { int n = p->loop_total(); int shader = clamp(p->material_index(), 0, used_shaders.size()-1); bool smooth = p->use_smooth() || use_loop_normals; vi.reserve(n); for(int i = 0; i < n; i++) { vi[i] = b_mesh.loops[p->loop_start() + i].vertex_index(); /* split vertices if normal is different * * note all vertex attributes must have been set here so we can split * and copy attributes in split_vertex without remapping later */ if(use_loop_normals) { float3 loop_N = get_float3(b_mesh.loops[p->loop_start() + i].normal()); if(N[vi[i]] != loop_N) { int new_vi = mesh->split_vertex(vi[i]); /* set new normal and vertex index */ N = attr_N->data_float3(); N[new_vi] = loop_N; vi[i] = new_vi; } } } /* create subd faces */ mesh->add_subd_face(&vi[0], n, shader, smooth); } } /* Create all needed attributes. * The calculate functions will check whether they're needed or not. */ attr_create_vertex_color(scene, mesh, b_mesh, nverts, face_flags, subdivision); attr_create_uv_map(scene, mesh, b_mesh, nverts, face_flags, subdivision, subdivide_uvs); /* for volume objects, create a matrix to transform from object space to * mesh texture space. this does not work with deformations but that can * probably only be done well with a volume grid mapping of coordinates */ if(mesh->need_attribute(scene, ATTR_STD_GENERATED_TRANSFORM)) { Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED_TRANSFORM); Transform *tfm = attr->data_transform(); float3 loc, size; mesh_texture_space(b_mesh, loc, size); *tfm = transform_translate(-loc)*transform_scale(size); } }
/* Create uv map attributes. */ static void attr_create_uv_map(Scene *scene, Mesh *mesh, BL::Mesh& b_mesh, const vector<int>& nverts, const vector<int>& face_flags, bool subdivision, bool subdivide_uvs) { if(subdivision) { BL::Mesh::uv_layers_iterator l; int i = 0; for(b_mesh.uv_layers.begin(l); l != b_mesh.uv_layers.end(); ++l, ++i) { bool active_render = b_mesh.uv_textures[i].active_render(); AttributeStandard std = (active_render)? ATTR_STD_UV: ATTR_STD_NONE; ustring name = ustring(l->name().c_str()); /* UV map */ if(mesh->need_attribute(scene, name) || mesh->need_attribute(scene, std)) { Attribute *attr; if(active_render) attr = mesh->subd_attributes.add(std, name); else attr = mesh->subd_attributes.add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CORNER); if(subdivide_uvs) { attr->flags |= ATTR_SUBDIVIDED; } BL::Mesh::polygons_iterator p; float3 *fdata = attr->data_float3(); for(b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) { int n = p->loop_total(); for(int j = 0; j < n; j++) { *(fdata++) = get_float3(l->data[p->loop_start() + j].uv()); } } } } } else if(b_mesh.tessface_uv_textures.length() != 0) { BL::Mesh::tessface_uv_textures_iterator l; for(b_mesh.tessface_uv_textures.begin(l); l != b_mesh.tessface_uv_textures.end(); ++l) { bool active_render = l->active_render(); AttributeStandard std = (active_render)? ATTR_STD_UV: ATTR_STD_NONE; ustring name = ustring(l->name().c_str()); /* UV map */ if(mesh->need_attribute(scene, name) || mesh->need_attribute(scene, std)) { Attribute *attr; if(active_render) attr = mesh->attributes.add(std, name); else attr = mesh->attributes.add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CORNER); BL::MeshTextureFaceLayer::data_iterator t; float3 *fdata = attr->data_float3(); size_t i = 0; for(l->data.begin(t); t != l->data.end(); ++t, ++i) { int tri_a[3], tri_b[3]; face_split_tri_indices(nverts[i], face_flags[i], tri_a, tri_b); float3 uvs[4]; uvs[0] = get_float3(t->uv1()); uvs[1] = get_float3(t->uv2()); uvs[2] = get_float3(t->uv3()); if(nverts[i] == 4) { uvs[3] = get_float3(t->uv4()); } fdata[0] = uvs[tri_a[0]]; fdata[1] = uvs[tri_a[1]]; fdata[2] = uvs[tri_a[2]]; fdata += 3; if(nverts[i] == 4) { fdata[0] = uvs[tri_b[0]]; fdata[1] = uvs[tri_b[1]]; fdata[2] = uvs[tri_b[2]]; fdata += 3; } } } /* UV tangent */ std = (active_render)? ATTR_STD_UV_TANGENT: ATTR_STD_NONE; name = ustring((string(l->name().c_str()) + ".tangent").c_str()); if(mesh->need_attribute(scene, name) || (active_render && mesh->need_attribute(scene, std))) { std = (active_render)? ATTR_STD_UV_TANGENT_SIGN: ATTR_STD_NONE; name = ustring((string(l->name().c_str()) + ".tangent_sign").c_str()); bool need_sign = (mesh->need_attribute(scene, name) || mesh->need_attribute(scene, std)); mikk_compute_tangents(b_mesh, &(*l), mesh, nverts, face_flags, need_sign, active_render); } } } else if(mesh->need_attribute(scene, ATTR_STD_UV_TANGENT)) { bool need_sign = mesh->need_attribute(scene, ATTR_STD_UV_TANGENT_SIGN); mikk_compute_tangents(b_mesh, NULL, mesh, nverts, face_flags, need_sign, true); } }
/* Create vertex color attributes. */ static void attr_create_vertex_color(Scene *scene, Mesh *mesh, BL::Mesh& b_mesh, const vector<int>& nverts, const vector<int>& face_flags, bool subdivision) { if(subdivision) { BL::Mesh::vertex_colors_iterator l; for(b_mesh.vertex_colors.begin(l); l != b_mesh.vertex_colors.end(); ++l) { if(!mesh->need_attribute(scene, ustring(l->name().c_str()))) continue; Attribute *attr = mesh->subd_attributes.add(ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CORNER_BYTE); BL::Mesh::polygons_iterator p; uchar4 *cdata = attr->data_uchar4(); for(b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) { int n = p->loop_total(); for(int i = 0; i < n; i++) { float3 color = get_float3(l->data[p->loop_start() + i].color()); *(cdata++) = color_float_to_byte(color_srgb_to_scene_linear(color)); } } } } else { BL::Mesh::tessface_vertex_colors_iterator l; for(b_mesh.tessface_vertex_colors.begin(l); l != b_mesh.tessface_vertex_colors.end(); ++l) { if(!mesh->need_attribute(scene, ustring(l->name().c_str()))) continue; Attribute *attr = mesh->attributes.add(ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CORNER_BYTE); BL::MeshColorLayer::data_iterator c; uchar4 *cdata = attr->data_uchar4(); size_t i = 0; for(l->data.begin(c); c != l->data.end(); ++c, ++i) { int tri_a[3], tri_b[3]; face_split_tri_indices(nverts[i], face_flags[i], tri_a, tri_b); uchar4 colors[4]; colors[0] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color1()))); colors[1] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color2()))); colors[2] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color3()))); if(nverts[i] == 4) { colors[3] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color4()))); } cdata[0] = colors[tri_a[0]]; cdata[1] = colors[tri_a[1]]; cdata[2] = colors[tri_a[2]]; if(nverts[i] == 4) { cdata[3] = colors[tri_b[0]]; cdata[4] = colors[tri_b[1]]; cdata[5] = colors[tri_b[2]]; cdata += 6; } else cdata += 3; } } } }