* fix alt + m1 indirect faces picking, when object is partially or fully out of camera view

refactor math functions
This commit is contained in:
Garux
2019-04-28 20:54:29 +03:00
parent b9a43074f0
commit 71c63fbdc6
12 changed files with 218 additions and 287 deletions

View File

@@ -195,7 +195,7 @@ void bestPlaneDirect( const AABB& aabb, SelectionTest& test, Plane3& plane, Sele
}
m_bounds = aabb;
}
void bestPlaneIndirect( const AABB& aabb, SelectionTest& test, Plane3& plane, Vector3& intersection, float& dist, const Vector3& viewer, const Matrix4& rotation = g_matrix4_identity ){
void bestPlaneIndirect( const AABB& aabb, SelectionTest& test, Plane3& plane, Vector3& intersection, float& dist, const Matrix4& rotation = g_matrix4_identity ){
Vector3 corners[8];
aabb_corners_oriented( aabb, rotation, corners );
@@ -256,33 +256,32 @@ void bestPlaneIndirect( const AABB& aabb, SelectionTest& test, Plane3& plane, Ve
3, 1,
};
for( std::size_t i = 0; i < 8; ++i ){
corners[i] = vector4_projected( matrix4_transformed_vector4( test.getVolume().GetViewMatrix(), Vector4( corners[i], 1 ) ) );
}
for ( std::size_t i = 0; i < 24; ++++i ){
const Vector3 intersection_new = line_closest_point( Line( corners[edges[i]], corners[edges[i + 1]] ), g_vector3_identity );
const float dist_new = vector3_length_squared( intersection_new );
if( dist_new < dist ){
const Plane3& plane1 = planes[adjacent_planes[i]];
const Plane3& plane2 = planes[adjacent_planes[i + 1]];
if( ( vector3_dot( plane1.normal(), viewer ) - plane1.dist() ) <= 0 ){
if( aabb.extents[( ( adjacent_planes[i] >> 1 ) << 1 ) / 2] == 0 ) /* select the other, if zero bound */
plane = plane2;
else
plane = plane1;
intersection = intersection_new;
dist = dist_new;
}
else{
if( ( vector3_dot( plane2.normal(), viewer ) - plane2.dist() ) <= 0 ){
if( aabb.extents[( ( adjacent_planes[i + 1] >> 1 ) << 1 ) / 2] == 0 ) /* select the other, if zero bound */
plane = plane1;
else
Line line( corners[edges[i]], corners[edges[i + 1]] );
if( matrix4_clip_line_by_nearplane( test.getVolume().GetViewMatrix(), line ) == 2 ){
const Vector3 intersection_new = line_closest_point( line, g_vector3_identity );
const float dist_new = vector3_length_squared( intersection_new );
if( dist_new < dist ){
const Plane3& plane1 = planes[adjacent_planes[i]];
const Plane3& plane2 = planes[adjacent_planes[i + 1]];
if( plane3_distance_to_point( plane1, test.getVolume().getViewer() ) <= 0 ){
if( aabb.extents[( ( adjacent_planes[i] >> 1 ) << 1 ) / 2] == 0 ) /* select the other, if zero bound */
plane = plane2;
else
plane = plane1;
intersection = intersection_new;
dist = dist_new;
}
else{
if( plane3_distance_to_point( plane2, test.getVolume().getViewer() ) <= 0 ){
if( aabb.extents[( ( adjacent_planes[i + 1] >> 1 ) << 1 ) / 2] == 0 ) /* select the other, if zero bound */
plane = plane1;
else
plane = plane2;
intersection = intersection_new;
dist = dist_new;
}
}
}
}
}

View File

@@ -363,6 +363,51 @@ inline std::size_t matrix4_clip_line( const Matrix4& self, const Vector3& p0, co
return homogenous_clip_line( clipped );
}
inline std::size_t matrix4_clip_line_by_nearplane( const Matrix4& self, Line& line ){
Vector4 points[2] = { matrix4_transformed_vector4( self, Vector4( line.start, 1 ) ), matrix4_transformed_vector4( self, Vector4( line.end, 1 ) ) };
const Vector4& p0 = points[0];
const Vector4& p1 = points[1];
// early out
{
const bool passed0 = CLIP_Z_GT_W( p0 );
const bool passed1 = CLIP_Z_GT_W( p1 );
if ( passed0 && passed1 ) { // both points passed all planes
line.start = vector4_projected( p0 );
line.end = vector4_projected( p1 );
return 2;
}
if ( !passed0 && !passed1 ) { // both points failed any one plane
return 0;
}
}
{
const bool index = CLIP_Z_GT_W( p0 );
if ( index ^ CLIP_Z_GT_W( p1 ) ) {
Vector4 clip( vector4_subtracted( p1, p0 ) );
double scale = ( p0[2] + p0[3] ) / ( -clip[3] - clip[2] );
clip[0] = static_cast<float>( p0[0] + scale * clip[0] );
clip[1] = static_cast<float>( p0[1] + scale * clip[1] );
clip[2] = static_cast<float>( p0[2] + scale * clip[2] );
clip[3] = static_cast<float>( p0[3] + scale * clip[3] );
points[index] = clip;
}
else if ( index == 0 ) {
return 0;
}
}
line.start = vector4_projected( p0 );
line.end = vector4_projected( p1 );
return 2;
}

View File

@@ -91,20 +91,25 @@ inline unsigned int segment_classify_plane( const Segment& segment, const Plane3
}
class Ray
template<typename T>
class BasicRay
{
public:
Vector3 origin, direction;
BasicVector3<T> origin, direction;
Ray(){
BasicRay(){
}
Ray( const Vector3& origin_, const Vector3& direction_ ) :
BasicRay( const BasicVector3<T>& origin_, const BasicVector3<T>& direction_ ) :
origin( origin_ ), direction( direction_ ){
}
};
inline Ray ray_for_points( const Vector3& origin, const Vector3& p2 ){
return Ray( origin, vector3_normalised( vector3_subtracted( p2, origin ) ) );
typedef BasicRay<float> Ray;
typedef BasicRay<double> DoubleRay;
template<typename T>
inline BasicRay<T> ray_for_points( const BasicVector3<T>& origin, const BasicVector3<T>& p2 ){
return BasicRay<T>( origin, vector3_normalised( vector3_subtracted( p2, origin ) ) );
}
inline void ray_transform( Ray& ray, const Matrix4& matrix ){
@@ -132,7 +137,45 @@ inline double ray_squared_distance_to_point( const Ray& ray, const Vector3& poin
}
inline double ray_distance_to_plane( const Ray& ray, const Plane3& plane ){
return -( vector3_dot( plane.normal(), ray.origin ) - plane.dist() ) / vector3_dot( ray.direction, plane.normal() );
return -plane3_distance_to_point( plane, ray.origin ) / vector3_dot( ray.direction, plane.normal() );
}
/// \brief Returns the point at which \p ray intersects \p plane, or an undefined value if there is no intersection.
template<typename T>
inline BasicVector3<T> ray_intersect_plane( const BasicRay<T>& ray, const Plane3& plane ){
return ray.origin + vector3_scaled(
ray.direction,
-plane3_distance_to_point( plane, ray.origin )
/ vector3_dot( ray.direction, plane.normal() )
);
}
/// \brief Returns the infinite line that is the intersection of \p plane and \p other.
inline DoubleRay plane3_intersect_plane3( const Plane3& plane, const Plane3& other ){
DoubleRay line;
line.direction = vector3_cross( plane.normal(), other.normal() );
switch ( vector3_max_abs_component_index( line.direction ) )
{
case 0:
line.origin.x() = 0;
line.origin.y() = ( -other.dist() * plane.normal().z() - -plane.dist() * other.normal().z() ) / line.direction.x();
line.origin.z() = ( -plane.dist() * other.normal().y() - -other.dist() * plane.normal().y() ) / line.direction.x();
break;
case 1:
line.origin.x() = ( -plane.dist() * other.normal().z() - -other.dist() * plane.normal().z() ) / line.direction.y();
line.origin.y() = 0;
line.origin.z() = ( -other.dist() * plane.normal().x() - -plane.dist() * other.normal().x() ) / line.direction.y();
break;
case 2:
line.origin.x() = ( -other.dist() * plane.normal().y() - -plane.dist() * other.normal().y() ) / line.direction.z();
line.origin.y() = ( -plane.dist() * other.normal().x() - -other.dist() * plane.normal().x() ) / line.direction.z();
line.origin.z() = 0;
break;
default:
break;
}
return line;
}
#endif

View File

@@ -138,5 +138,10 @@ inline Plane3 plane3_for_points( const BasicVector3<Element> planepts[3] ){
return plane3_for_points( planepts[2], planepts[1], planepts[0] );
}
template<typename T>
inline double plane3_distance_to_point( const Plane3& plane, const BasicVector3<T>& point ){
return vector3_dot( point, plane.normal() ) - plane.dist();
}
#endif