static void mikk_get_normal(const SMikkTSpaceContext *context, float N[3], const int face_num, const int vert_num) { const MikkUserData *userdata = (const MikkUserData *)context->m_pUserData; const Mesh *mesh = userdata->mesh; float3 vN; if (mesh->subd_faces.size()) { const Mesh::SubdFace &face = mesh->subd_faces[face_num]; if (face.smooth) { const int vertex_index = mikk_vertex_index(mesh, face_num, vert_num); vN = userdata->vertex_normal[vertex_index]; } else { vN = face.normal(mesh); } } else { if (mesh->smooth[face_num]) { const int vertex_index = mikk_vertex_index(mesh, face_num, vert_num); vN = userdata->vertex_normal[vertex_index]; } else { const Mesh::Triangle tri = mesh->get_triangle(face_num); vN = tri.compute_normal(&mesh->verts[0]); } } N[0] = vN.x; N[1] = vN.y; N[2] = vN.z; }
void BVHBuild::add_reference_mesh(BoundBox& root, BoundBox& center, Mesh *mesh, int i) { Attribute *attr_mP = NULL; if(mesh->has_motion_blur()) attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); for(uint j = 0; j < mesh->triangles.size(); j++) { Mesh::Triangle t = mesh->triangles[j]; BoundBox bounds = BoundBox::empty; PrimitiveType type = PRIMITIVE_TRIANGLE; t.bounds_grow(&mesh->verts[0], bounds); /* motion triangles */ if(attr_mP) { size_t mesh_size = mesh->verts.size(); size_t steps = mesh->motion_steps - 1; float3 *vert_steps = attr_mP->data_float3(); for(size_t i = 0; i < steps; i++) t.bounds_grow(vert_steps + i*mesh_size, bounds); type = PRIMITIVE_MOTION_TRIANGLE; } if(bounds.valid()) { references.push_back(BVHReference(bounds, j, i, type)); root.grow(bounds); center.grow(bounds.center2()); } } Attribute *curve_attr_mP = NULL; if(mesh->has_motion_blur()) curve_attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); for(uint j = 0; j < mesh->curves.size(); j++) { Mesh::Curve curve = mesh->curves[j]; PrimitiveType type = PRIMITIVE_CURVE; for(int k = 0; k < curve.num_keys - 1; k++) { BoundBox bounds = BoundBox::empty; curve.bounds_grow(k, &mesh->curve_keys[0], bounds); /* motion curve */ if(curve_attr_mP) { size_t mesh_size = mesh->curve_keys.size(); size_t steps = mesh->motion_steps - 1; float4 *key_steps = curve_attr_mP->data_float4(); for(size_t i = 0; i < steps; i++) curve.bounds_grow(k, key_steps + i*mesh_size, bounds); type = PRIMITIVE_MOTION_CURVE; } if(bounds.valid()) { int packed_type = PRIMITIVE_PACK_SEGMENT(type, k); references.push_back(BVHReference(bounds, j, i, packed_type)); root.grow(bounds); center.grow(bounds.center2()); } } } }
void BVH4::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility) { if(leaf) { int4 *data = &pack.leaf_nodes[idx]; int4 c = data[0]; /* Refit leaf node. */ for(int prim = c.x; prim < c.y; prim++) { int pidx = pack.prim_index[prim]; int tob = pack.prim_object[prim]; Object *ob = objects[tob]; if(pidx == -1) { /* Object instance. */ bbox.grow(ob->bounds); } else { /* Primitives. */ const Mesh *mesh = ob->mesh; if(pack.prim_type[prim] & PRIMITIVE_ALL_CURVE) { /* Curves. */ int str_offset = (params.top_level)? mesh->curve_offset: 0; Mesh::Curve curve = mesh->get_curve(pidx - str_offset); int k = PRIMITIVE_UNPACK_SEGMENT(pack.prim_type[prim]); curve.bounds_grow(k, &mesh->curve_keys[0], &mesh->curve_radius[0], bbox); visibility |= PATH_RAY_CURVE; /* Motion curves. */ if(mesh->use_motion_blur) { Attribute *attr = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); if(attr) { size_t mesh_size = mesh->curve_keys.size(); size_t steps = mesh->motion_steps - 1; float3 *key_steps = attr->data_float3(); for(size_t i = 0; i < steps; i++) curve.bounds_grow(k, key_steps + i*mesh_size, &mesh->curve_radius[0], bbox); } } } else { /* Triangles. */ int tri_offset = (params.top_level)? mesh->tri_offset: 0; Mesh::Triangle triangle = mesh->get_triangle(pidx - tri_offset); const float3 *vpos = &mesh->verts[0]; triangle.bounds_grow(vpos, bbox); /* Motion triangles. */ if(mesh->use_motion_blur) { Attribute *attr = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); if(attr) { size_t mesh_size = mesh->verts.size(); size_t steps = mesh->motion_steps - 1; float3 *vert_steps = attr->data_float3(); for(size_t i = 0; i < steps; i++) triangle.bounds_grow(vert_steps + i*mesh_size, bbox); } } } } visibility |= ob->visibility_for_tracing(); } /* TODO(sergey): This is actually a copy of pack_leaf(), * but this chunk of code only knows actual data and has * no idea about BVHNode. * * Would be nice to de-duplicate code, but trying to make * making code more general ends up in much nastier code * in my opinion so far. * * Same applies to the inner nodes case below. */ float4 leaf_data[BVH_QNODE_LEAF_SIZE]; leaf_data[0].x = __int_as_float(c.x); leaf_data[0].y = __int_as_float(c.y); leaf_data[0].z = __uint_as_float(visibility); leaf_data[0].w = __uint_as_float(c.w); memcpy(&pack.leaf_nodes[idx], leaf_data, sizeof(float4)*BVH_QNODE_LEAF_SIZE); } else { int4 *data = &pack.nodes[idx]; bool is_unaligned = (data[0].x & PATH_RAY_NODE_UNALIGNED) != 0; int4 c; if(is_unaligned) { c = data[13]; } else { c = data[7]; } /* Refit inner node, set bbox from children. */ BoundBox child_bbox[4] = {BoundBox::empty, BoundBox::empty, BoundBox::empty, BoundBox::empty}; uint child_visibility[4] = {0}; int num_nodes = 0; for(int i = 0; i < 4; ++i) { if(c[i] != 0) { refit_node((c[i] < 0)? -c[i]-1: c[i], (c[i] < 0), child_bbox[i], child_visibility[i]); ++num_nodes; bbox.grow(child_bbox[i]); visibility |= child_visibility[i]; } } if(is_unaligned) { Transform aligned_space[4] = {transform_identity(), transform_identity(), transform_identity(), transform_identity()}; pack_unaligned_node(idx, aligned_space, child_bbox, &c[0], visibility, 0.0f, 1.0f, 4); } else { pack_aligned_node(idx, child_bbox, &c[0], visibility, 0.0f, 1.0f, 4); } } }
void BVH8::refit_node(int idx, bool leaf, BoundBox &bbox, uint &visibility) { if (leaf) { int4 *data = &pack.leaf_nodes[idx]; int4 c = data[0]; /* Refit leaf node. */ for (int prim = c.x; prim < c.y; prim++) { int pidx = pack.prim_index[prim]; int tob = pack.prim_object[prim]; Object *ob = objects[tob]; if (pidx == -1) { /* Object instance. */ bbox.grow(ob->bounds); } else { /* Primitives. */ const Mesh *mesh = ob->mesh; if (pack.prim_type[prim] & PRIMITIVE_ALL_CURVE) { /* Curves. */ int str_offset = (params.top_level) ? mesh->curve_offset : 0; Mesh::Curve curve = mesh->get_curve(pidx - str_offset); int k = PRIMITIVE_UNPACK_SEGMENT(pack.prim_type[prim]); curve.bounds_grow(k, &mesh->curve_keys[0], &mesh->curve_radius[0], bbox); visibility |= PATH_RAY_CURVE; /* Motion curves. */ if (mesh->use_motion_blur) { Attribute *attr = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); if (attr) { size_t mesh_size = mesh->curve_keys.size(); size_t steps = mesh->motion_steps - 1; float3 *key_steps = attr->data_float3(); for (size_t i = 0; i < steps; i++) { curve.bounds_grow(k, key_steps + i * mesh_size, &mesh->curve_radius[0], bbox); } } } } else { /* Triangles. */ int tri_offset = (params.top_level) ? mesh->tri_offset : 0; Mesh::Triangle triangle = mesh->get_triangle(pidx - tri_offset); const float3 *vpos = &mesh->verts[0]; triangle.bounds_grow(vpos, bbox); /* Motion triangles. */ if (mesh->use_motion_blur) { Attribute *attr = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); if (attr) { size_t mesh_size = mesh->verts.size(); size_t steps = mesh->motion_steps - 1; float3 *vert_steps = attr->data_float3(); for (size_t i = 0; i < steps; i++) { triangle.bounds_grow(vert_steps + i * mesh_size, bbox); } } } } } visibility |= ob->visibility; } float4 leaf_data[BVH_ONODE_LEAF_SIZE]; leaf_data[0].x = __int_as_float(c.x); leaf_data[0].y = __int_as_float(c.y); leaf_data[0].z = __uint_as_float(visibility); leaf_data[0].w = __uint_as_float(c.w); memcpy(&pack.leaf_nodes[idx], leaf_data, sizeof(float4) * BVH_ONODE_LEAF_SIZE); } else { float8 *data = (float8 *)&pack.nodes[idx]; bool is_unaligned = (__float_as_uint(data[0].a) & PATH_RAY_NODE_UNALIGNED) != 0; /* Refit inner node, set bbox from children. */ BoundBox child_bbox[8] = {BoundBox::empty, BoundBox::empty, BoundBox::empty, BoundBox::empty, BoundBox::empty, BoundBox::empty, BoundBox::empty, BoundBox::empty}; int child[8]; uint child_visibility[8] = {0}; int num_nodes = 0; for (int i = 0; i < 8; ++i) { child[i] = __float_as_int(data[(is_unaligned) ? 13 : 7][i]); if (child[i] != 0) { refit_node((child[i] < 0) ? -child[i] - 1 : child[i], (child[i] < 0), child_bbox[i], child_visibility[i]); ++num_nodes; bbox.grow(child_bbox[i]); visibility |= child_visibility[i]; } } if (is_unaligned) { Transform aligned_space[8] = {transform_identity(), transform_identity(), transform_identity(), transform_identity(), transform_identity(), transform_identity(), transform_identity(), transform_identity()}; pack_unaligned_node( idx, aligned_space, child_bbox, child, visibility, 0.0f, 1.0f, num_nodes); } else { pack_aligned_node(idx, child_bbox, child, visibility, 0.0f, 1.0f, num_nodes); } } }
void FindClosestTriangle:: find ( mesh::Triangle& triangle ) { typedef utils::GeometryComputations GeoComp; using utils::Vector2D; using utils::Vector3D; using namespace tarch::la; Vector3D barycentricCoords; Vector3D projected; // Methodology of book "Computational Geometry", Joseph O' Rourke, Chapter 7.3 // with the barycentric coordinates method and real projection into 2D, instead // of outprojecting one coordinate // Parametric representation for triangle plane: // (x, y, z) * normal = d Vector3D a = triangle.vertex(0).getCoords(); Vector3D normal = triangle.getNormal(); double d = dot(normal, a); // Parametric description of line from searchpoint orthogonal to triangle: // _searchPoint + t * normal = x (where t is parameter) // Determine t such that x lies on triangle plane: double t = d - dot(_searchPoint, normal) / dot(normal, normal); // Compute projected point with parameter t: projected = normal; projected *= t; projected += _searchPoint; // Project everything to 2D Vector3D normalAbs; int iMax = indexMax(abs(normal, normalAbs)); int indices[2]; if (iMax == 0){ indices[0] = 1; indices[1] = 2; } else if (iMax == 1){ indices[0] = 0; indices[1] = 2; } else { assertion1(iMax == 2, iMax); indices[0] = 0; indices[1] = 1; } Vector2D a2D(triangle.vertex(0).getCoords()[indices[0]], triangle.vertex(0).getCoords()[indices[1]]); Vector2D b2D(triangle.vertex(1).getCoords()[indices[0]], triangle.vertex(1).getCoords()[indices[1]]); Vector2D c2D(triangle.vertex(2).getCoords()[indices[0]], triangle.vertex(2).getCoords()[indices[1]]); Vector2D projected2D(projected[indices[0]], projected[indices[1]]); // Compute barycentric coordinates by solving linear 3x3 system Vector3D rhs (projected2D(0), projected2D(1), 1); Matrix<3,3,double> A; assignList(A) = a2D(0), b2D(0), c2D(0), a2D(1), b2D(1), c2D(1), 1, 1, 1; solveSystem3x3(A, rhs, barycentricCoords); // Determine from barycentric coordinates, if point is inside triangle bool inside = true; for (int i=0; i < 3; i++){ if (barycentricCoords(i) < - NUMERICAL_ZERO_DIFFERENCE){ inside = false; } } // if inside, compute distance to triangle and evtl. store distance if (inside){ Vector3D distanceVector = projected - _searchPoint; double distance = norm2(distanceVector); if (_shortestDistance > distance){ _shortestDistance = distance; _vectorToProjectionPoint = distanceVector; _parametersProjectionPoint[0] = barycentricCoords(0); _parametersProjectionPoint[1] = barycentricCoords(1); _parametersProjectionPoint[2] = barycentricCoords(2); _closestTriangle = ▵ } } }
void BVH::refit_primitives(int start, int end, BoundBox& bbox, uint& visibility) { /* Refit range of primitives. */ for(int prim = start; prim < end; prim++) { int pidx = pack.prim_index[prim]; int tob = pack.prim_object[prim]; Object *ob = objects[tob]; if(pidx == -1) { /* Object instance. */ bbox.grow(ob->bounds); } else { /* Primitives. */ const Mesh *mesh = ob->mesh; if(pack.prim_type[prim] & PRIMITIVE_ALL_CURVE) { /* Curves. */ int str_offset = (params.top_level)? mesh->curve_offset: 0; Mesh::Curve curve = mesh->get_curve(pidx - str_offset); int k = PRIMITIVE_UNPACK_SEGMENT(pack.prim_type[prim]); curve.bounds_grow(k, &mesh->curve_keys[0], &mesh->curve_radius[0], bbox); visibility |= PATH_RAY_CURVE; /* Motion curves. */ if(mesh->use_motion_blur) { Attribute *attr = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); if(attr) { size_t mesh_size = mesh->curve_keys.size(); size_t steps = mesh->motion_steps - 1; float3 *key_steps = attr->data_float3(); for(size_t i = 0; i < steps; i++) curve.bounds_grow(k, key_steps + i*mesh_size, &mesh->curve_radius[0], bbox); } } } else { /* Triangles. */ int tri_offset = (params.top_level)? mesh->tri_offset: 0; Mesh::Triangle triangle = mesh->get_triangle(pidx - tri_offset); const float3 *vpos = &mesh->verts[0]; triangle.bounds_grow(vpos, bbox); /* Motion triangles. */ if(mesh->use_motion_blur) { Attribute *attr = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); if(attr) { size_t mesh_size = mesh->verts.size(); size_t steps = mesh->motion_steps - 1; float3 *vert_steps = attr->data_float3(); for(size_t i = 0; i < steps; i++) triangle.bounds_grow(vert_steps + i*mesh_size, bbox); } } } } visibility |= ob->visibility_for_tracing(); } }