const vector4 vector4::operator / (const vector4 &v2) const { vector4 r; r.x() = x() / v2.x(); r.y() = y() / v2.y(); r.z() = z() / v2.z(); r.w() = w() / v2.w(); return r; }
vector4 vector4::Transform(const vector4& v, const matrix& m) { vector4 result = vector4( (v.x() * m(0,0)) + (v.y() * m(1,0)) + (v.z() * m(2,0)) + (v.w() * m(3,0)), (v.x() * m(0,1)) + (v.y() * m(1,1)) + (v.z() * m(2,1)) + (v.w() * m(3,1)), (v.x() * m(0,2)) + (v.y() * m(1,2)) + (v.z() * m(2,2)) + (v.w() * m(3,2)), (v.x() * m(0,3)) + (v.y() * m(1,3)) + (v.z() * m(2,3)) + (v.w() * m(3,3)) ); return result; }
// Returns the cross product of two vectors vector4 vector4::Cross(const vector4 &v2) const { vector4 r; r.x() = (y() * v2.z()) - (z() * v2.y()); r.y() = (z() * v2.x()) - (x() * v2.z()); r.z() = (x() * v2.y()) - (y() * v2.x()); r.w() = w(); return r; }
float vector4::Dot(const vector4& v1, const vector4& v2) { return v1.Dot(v2); }
// Returns the dot product of two vectors float vector4::Dot(const vector4 &v2) const { return ((x() * v2.x()) + (y() * v2.y()) + (z() * v2.z()) + (w() * v2.w())); }
// Equality operations bool vector4::operator == (const vector4 &v) const { return ((x() == v.x()) && (y() == v.y()) && (z() == v.z()) && (w() == v.w())); }
bool RayIntersectsAABB(const ray& intersectionRay, float* tEntry, float* tExit, const vector4& aabbMinExtents, const vector4& aabbMaxExtents) { // Test against front plane. const vector4& rayPosition = intersectionRay.getPosition(); const vector4& rayDirection = intersectionRay.getDirection(); bool tFound = false; float minimumTValue = FLT_MAX; float maximumTValue = 0.0f; // Containment test. Is the ray inside the aabb? if (rayPosition.extractX() >= aabbMinExtents.extractX() && rayPosition.extractX() <= aabbMaxExtents.extractX() && rayPosition.extractY() >= aabbMinExtents.extractY() && rayPosition.extractY() <= aabbMaxExtents.extractY() && rayPosition.extractZ() >= aabbMinExtents.extractZ() && rayPosition.extractZ() <= aabbMaxExtents.extractZ()) { minimumTValue = 0.0f; tFound = true; } // Intersect ray with the minimum x plane of the aabb. plane minXPlane(vector4(aabbMinExtents.extractX(), 0.0f, 0.0f, 1.0f), vector4(-1.0f, 0.0f, 0.0f, 0.0f)); float minXPlaneIntersection; if (MathLib::intersectRayWithPlane(intersectionRay, minXPlane, &minXPlaneIntersection)) { // Construct the point on the plane. Test if in bounds of the aabb. vector4 point; vector4_addScaledVector(rayPosition, rayDirection, minXPlaneIntersection, point); if (point.extractY() >= aabbMinExtents.extractY() && point.extractY() <= aabbMaxExtents.extractY() && point.extractZ() >= aabbMinExtents.extractZ() && point.extractZ() <= aabbMaxExtents.extractZ()) { if (minXPlaneIntersection >= 0.0f) tFound = true; if (minXPlaneIntersection < minimumTValue) minimumTValue = minXPlaneIntersection; if (minXPlaneIntersection > maximumTValue) maximumTValue = minXPlaneIntersection; } } // Intersect ray with the maximum x plane of the aabb. plane maxXPlane(vector4(aabbMaxExtents.extractX(), 0.0f, 0.0f, 1.0f), vector4(1.0f, 0.0f, 0.0f, 0.0f)); float maxXPlaneIntersection; if (MathLib::intersectRayWithPlane(intersectionRay, maxXPlane, &maxXPlaneIntersection)) { // Construct the point on the plane. Test if in bounds of the aabb. vector4 point; vector4_addScaledVector(rayPosition, rayDirection, maxXPlaneIntersection, point); if (point.extractY() >= aabbMinExtents.extractY() && point.extractY() <= aabbMaxExtents.extractY() && point.extractZ() >= aabbMinExtents.extractZ() && point.extractZ() <= aabbMaxExtents.extractZ()) { if (maxXPlaneIntersection >= 0.0f) tFound = true; if (maxXPlaneIntersection < minimumTValue) minimumTValue = maxXPlaneIntersection; if (maxXPlaneIntersection > maximumTValue) maximumTValue = maxXPlaneIntersection; } } // Intersect ray with the minimum y plane of the aabb. plane minYPlane(vector4(0.0f, aabbMinExtents.extractY(), 0.0f, 1.0f), vector4(0.0f, -1.0f, 0.0f, 0.0f)); float minYPlaneIntersection; if (MathLib::intersectRayWithPlane(intersectionRay, minYPlane, &minYPlaneIntersection)) { // Construct the point on the plane. Test if in bounds of the aabb. vector4 point; vector4_addScaledVector(rayPosition, rayDirection, minYPlaneIntersection, point); if (point.extractX() >= aabbMinExtents.extractX() && point.extractX() <= aabbMaxExtents.extractX() && point.extractZ() >= aabbMinExtents.extractZ() && point.extractZ() <= aabbMaxExtents.extractZ()) { if (minYPlaneIntersection >= 0.0f) tFound = true; if (minYPlaneIntersection < minimumTValue) minimumTValue = minYPlaneIntersection; if (minYPlaneIntersection > maximumTValue) maximumTValue = minYPlaneIntersection; } } // Intersect ray with the maximum y plane of the aabb. plane maxYPlane(vector4(0.0f, aabbMaxExtents.extractY(), 0.0f, 1.0f), vector4(0.0f, 1.0f, 0.0f, 0.0f)); float maxYPlaneIntersection; if (MathLib::intersectRayWithPlane(intersectionRay, maxYPlane, &maxYPlaneIntersection)) { // Construct the point on the plane. Test if in bounds of the aabb. vector4 point; vector4_addScaledVector(rayPosition, rayDirection, maxYPlaneIntersection, point); if (point.extractX() >= aabbMinExtents.extractX() && point.extractX() <= aabbMaxExtents.extractX() && point.extractZ() >= aabbMinExtents.extractZ() && point.extractZ() <= aabbMaxExtents.extractZ()) { if (maxYPlaneIntersection >= 0.0f) tFound = true; if (maxYPlaneIntersection < minimumTValue) minimumTValue = maxYPlaneIntersection; if (maxYPlaneIntersection > maximumTValue) maximumTValue = maxYPlaneIntersection; } } // Intersect ray with the minimum z plane of the aabb. plane minZPlane(vector4(0.0f, 0.0f, aabbMinExtents.extractZ(), 1.0f), vector4(0.0f, 0.0f, -1.0f, 0.0f)); float minZPlaneIntersection; if (MathLib::intersectRayWithPlane(intersectionRay, minZPlane, &minZPlaneIntersection)) { // Construct the point on the plane. Test if in bounds of the aabb. vector4 point; vector4_addScaledVector(rayPosition, rayDirection, minZPlaneIntersection, point); if (point.extractX() >= aabbMinExtents.extractX() && point.extractX() <= aabbMaxExtents.extractX() && point.extractY() >= aabbMinExtents.extractY() && point.extractY() <= aabbMaxExtents.extractY()) { if (minZPlaneIntersection >= 0.0f) tFound = true; if (minZPlaneIntersection < minimumTValue) minimumTValue = minZPlaneIntersection; if (minZPlaneIntersection > maximumTValue) maximumTValue = minZPlaneIntersection; } } // Intersect ray with the maximum z plane of the aabb. plane maxZPlane(vector4(0.0f, 0.0f, aabbMaxExtents.extractZ(), 1.0f), vector4(0.0f, 0.0f, 1.0f, 0.0f)); float maxZPlaneIntersection; if (MathLib::intersectRayWithPlane(intersectionRay, maxZPlane, &maxZPlaneIntersection)) { // Construct the point on the plane. Test if in bounds of the aabb. vector4 point; vector4_addScaledVector(rayPosition, rayDirection, maxZPlaneIntersection, point); if (point.extractX() >= aabbMinExtents.extractX() && point.extractX() <= aabbMaxExtents.extractX() && point.extractY() >= aabbMinExtents.extractY() && point.extractY() <= aabbMaxExtents.extractY()) { if (maxZPlaneIntersection >= 0.0f) tFound = true; if (maxZPlaneIntersection < minimumTValue) minimumTValue = maxZPlaneIntersection; if (maxZPlaneIntersection > maximumTValue) maximumTValue = maxZPlaneIntersection; } } if (tFound) { *tEntry = minimumTValue; *tExit = maximumTValue; } return tFound; }
fcppt::unique_ptr<fruitapp::fruit::cut_mesh_result> fruitapp::fruit::cut_mesh( fruit::mesh const &input_mesh, fruit::plane const &input_plane) { typedef sge::renderer::scalar scalar; typedef sge::renderer::vector2 vector2; typedef sge::renderer::vector3 vector3; typedef fruitlib::def_ctor< vector2 > geometry_vector2; typedef sge::renderer::vector4 vector4; typedef sge::renderer::matrix4 matrix4; typedef fcppt::math::box::object<scalar,2> box2; typedef fruitlib::def_ctor< box2 > geometry_box2; typedef fcppt::math::box::object<scalar,3> box3; fcppt::unique_ptr<fruit::cut_mesh_result> result{ fcppt::make_unique_ptr<fruit::cut_mesh_result>()}; scalar const epsilon = static_cast<scalar>( 0.01); typedef std::vector<vector3> vector3_sequence; vector3_sequence border; // First step: Collect all the triangles and the border points. for( mesh::triangle_sequence::const_iterator input_triangle = input_mesh.triangles().begin(); input_triangle != input_mesh.triangles().end(); ++input_triangle) { typedef fruitlib::math::triangle_plane_intersection<triangle> intersection; scalar const inner_epsilon = static_cast<scalar>( 0.00001); intersection const single_result = fruitlib::math::cut_triangle_at_plane( *input_triangle, input_plane, inner_epsilon); for( intersection::point_sequence::const_iterator current_is_point = single_result.points().begin(); current_is_point != single_result.points().end(); ++current_is_point) border.push_back( *current_is_point); // Only add new points if they're not already in the set /* BOOST_FOREACH( intersection::point_sequence::const_reference r, single_result.points()) if( boost::range::find_if( border, boost::phoenix::bind( &fcppt::math::range_compare < sge::renderer::vector3, sge::renderer::vector3, sge::renderer::scalar >, boost::phoenix::arg_names::arg1, r, epsilon)) == border.end()) border.push_back( r); */ // Copy all triangles boost::range::copy( single_result.triangles(), std::back_inserter( result->mesh().triangles())); } // If there were no triangles, we can return if(result->mesh().triangles().empty()) return result; // Step 2: Calculate the bounding box and the barycenter (we can do // that in one pass, luckily) result->barycenter() = fcppt::math::vector::null<vector3>(); vector3 min_pos = result->mesh().triangles().front().vertices[0], max_pos = min_pos; for( mesh::triangle_sequence::const_iterator current_tri = result->mesh().triangles().begin(); current_tri != result->mesh().triangles().end(); ++current_tri) { for( triangle::vertex_array::const_iterator current_vertex = current_tri->vertices.begin(); current_vertex != current_tri->vertices.end(); ++current_vertex) { result->barycenter() += *current_vertex; for (vector3::size_type i = 0; i < 3; ++i) { min_pos.get_unsafe(i) = std::min(min_pos.get_unsafe(i),(*current_vertex).get_unsafe(i)); max_pos.get_unsafe(i) = std::max(max_pos.get_unsafe(i),(*current_vertex).get_unsafe(i)); } } } result->bounding_box() = box3( min_pos, fcppt::math::vector::to_dim( max_pos - min_pos)); result->barycenter() /= static_cast<scalar>( result->mesh().triangles().size() * 3); for( mesh::triangle_sequence::iterator current_tri = result->mesh().triangles().begin(); current_tri != result->mesh().triangles().end(); ++current_tri) for( triangle::vertex_array::iterator current_vertex = current_tri->vertices.begin(); current_vertex != current_tri->vertices.end(); ++current_vertex) (*current_vertex) -= result->barycenter(); // If we've got no border, quit now. This happens when the cutting // plane doesn't intersect with the fruit at all (we "miss", so to // speak) if(border.size() < static_cast<vector3_sequence::size_type>(3)) return result; fcppt::optional::object<matrix4> const cs( make_coordinate_system( border, epsilon)); if(!cs.has_value()) return result; matrix4 const tcs = cs.get_unsafe(); // TODO matrix4 const coordinate_transformation = fcppt::math::matrix::inverse( tcs); typedef boost::geometry::model::multi_point< geometry_vector2 > point_cloud_2d; typedef boost::geometry::model::ring< geometry_vector2 > ring_2d; point_cloud_2d reduced; reduced.reserve( border.size()); // TODO: map for(vector3_sequence::const_iterator i = border.begin(); i != border.end(); ++i) { vector4 const transformed = coordinate_transformation * vector4( (*i).x(), (*i).y(), (*i).z(), // WATCH OUT: ONLY WORKS WITH THE 1 HERE! 1.f); reduced.push_back( geometry_vector2( fcppt::math::vector::narrow_cast< vector2 >( transformed ) ) ); FCPPT_ASSERT_ERROR( transformed.z() < epsilon); /* // Warning: Costly assert! if( fcppt::math::vector::length( vector_narrow<vector3>( (*cs) * vector4(reduced.back()[0],reduced.back()[1],0,1)) - (*i)) > epsilon) { std::cout << fcppt::math::vector::length( vector_narrow<vector3>( (*cs) * vector4(reduced.back()[0],reduced.back()[1],0,1)) - (*i)) << "\n"; std::exit(1); } */ } ring_2d convex_hull_result; boost::geometry::convex_hull( reduced, convex_hull_result); if(convex_hull_result.size() < static_cast<ring_2d::size_type>(3)) return result; geometry_box2 const envelope( boost::geometry::return_envelope< geometry_box2 >( convex_hull_result ) ); typedef std::vector<vector2> texcoord_vector; texcoord_vector texcoords; texcoords.reserve( convex_hull_result.size()); for( auto const &element : convex_hull_result ) texcoords.push_back( (element.base() - envelope.pos()) / envelope.size() ); ring_2d::size_type const triangle_count = static_cast<ring_2d::size_type>( convex_hull_result.size() - 2u); result->mesh().triangles().reserve( result->mesh().triangles().size() + triangle_count); for( ring_2d::size_type current_vertex = static_cast<ring_2d::size_type>( 2); current_vertex < convex_hull_result.size(); ++current_vertex) { result->cross_section().triangles().push_back( fruit::triangle( {{ fcppt::math::vector::narrow_cast<vector3>( tcs * vector4( convex_hull_result[0].x(), convex_hull_result[0].y(), 0.f, 1.f)) - result->barycenter(), fcppt::math::vector::narrow_cast<vector3>( tcs * vector4( convex_hull_result[current_vertex-1].x(), convex_hull_result[current_vertex-1].y(), 0.f, 1.f)) - result->barycenter(), fcppt::math::vector::narrow_cast<vector3>( tcs * vector4( convex_hull_result[current_vertex].x(), convex_hull_result[current_vertex].y(), 0.f, 1.f)) - result->barycenter()}}, {{ transform_texcoord( texcoords[ 0]), transform_texcoord( texcoords[ current_vertex-1]), transform_texcoord( texcoords[ current_vertex])}}, {{ -input_plane.normal(), -input_plane.normal(), -input_plane.normal()}})); result->mesh().triangles().push_back( result->cross_section().triangles().back()); result->area() = fruit::area( result->area().get() + fruitlib::math::triangle::area( result->mesh().triangles().back())); } return result; }
cuda_device friend vector4 fast_normalize(const vector4& v) { return v * fast_rsqrt_T(v.dot(v)); }
cuda_device friend T fast_length(const vector4& v) { return fast_sqrt_T(v.dot(v)); }
cuda_device friend T length(const vector4& v) { return sqrt_T(v.dot(v)); }
cuda_device friend T dot(const vector4& v1, const vector4& v2) { return v1.dot(v2); }
cuda_device friend vector4 cross(const vector4& v1, const vector4& v2) { return v1.cross(v2); }