mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-07-18 18:09:18 +02:00
259 lines
7.8 KiB
HLSL
259 lines
7.8 KiB
HLSL
// Partially stolen from https://www.3dgep.com/forward-plus/
|
|
|
|
#ifndef FORWARD_PLUS_PRIMITIVES_HLSLI
|
|
#define FORWARD_PLUS_PRIMITIVES_HLSLI
|
|
|
|
/* ---------------------------------------------------------------------------------------------- */
|
|
/* Plane */
|
|
/* ---------------------------------------------------------------------------------------------- */
|
|
|
|
struct Plane
|
|
{
|
|
float3 N; // Plane normal.
|
|
float d; // Distance to origin.
|
|
};
|
|
|
|
// Compute a plane from 3 noncollinear points that form a triangle.
|
|
// This equation assumes a right-handed (counter-clockwise winding order)
|
|
// coordinate system to determine the direction of the plane normal.
|
|
Plane ComputePlane( float3 p0, float3 p1, float3 p2 )
|
|
{
|
|
Plane plane;
|
|
|
|
float3 v0 = p1 - p0;
|
|
float3 v2 = p2 - p0;
|
|
|
|
plane.N = normalize( cross( v0, v2 ) );
|
|
|
|
// Compute the distance to the origin using p0.
|
|
plane.d = dot( plane.N, p0 );
|
|
|
|
return plane;
|
|
}
|
|
|
|
// Check to see if a point is fully behind (inside the negative halfspace of) a plane.
|
|
bool PointInsidePlane( float3 p, Plane plane )
|
|
{
|
|
return dot( plane.N, p ) - plane.d < 0;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------------------------------- */
|
|
/* Frustum */
|
|
/* ---------------------------------------------------------------------------------------------- */
|
|
|
|
struct ConeFrustum
|
|
{
|
|
float3 m_origin;
|
|
float m_cos_angle;
|
|
float3 m_direction;
|
|
float m_sin_angle;
|
|
float m_cos_angle_sqr;
|
|
float m_inv_sin_angle;
|
|
};
|
|
|
|
ConeFrustum ComputeConeFrustum(in float3 origin, in float3 direction, in float cos_angle) {
|
|
ConeFrustum cone;
|
|
cone.m_origin = origin;
|
|
cone.m_direction = direction;
|
|
cone.m_cos_angle = cos_angle;
|
|
cone.m_cos_angle_sqr = cos_angle * cos_angle;
|
|
cone.m_sin_angle = sqrt(1. - saturate(cone.m_cos_angle_sqr));
|
|
cone.m_inv_sin_angle = 1. / cone.m_sin_angle;
|
|
return cone;
|
|
}
|
|
|
|
// Four planes of a view frustum (in view space).
|
|
// The planes are:
|
|
// * Left,
|
|
// * Right,
|
|
// * Top,
|
|
// * Bottom.
|
|
// The back and/or front planes can be computed from depth values in the
|
|
// light culling compute shader.
|
|
struct Frustum
|
|
{
|
|
Plane planes[4]; // left, right, top, bottom frustum planes.
|
|
float3 m_view_ray;
|
|
float m_tan_frustum_angle;
|
|
};
|
|
|
|
/* ---------------------------------------------------------------------------------------------- */
|
|
/* Sphere */
|
|
/* ---------------------------------------------------------------------------------------------- */
|
|
|
|
struct Sphere
|
|
{
|
|
float3 m_origin; // Center point.
|
|
float m_radius; // Radius.
|
|
};
|
|
|
|
// Check to see if a sphere is fully behind (inside the negative halfspace of) a plane.
|
|
// Source: Real-time collision detection, Christer Ericson (2005)
|
|
bool SphereInsidePlane( Sphere sphere, Plane plane )
|
|
{
|
|
return dot( plane.N, sphere.m_origin ) - plane.d < -sphere.m_radius;
|
|
}
|
|
|
|
// Check to see of a light is partially contained within the frustum.
|
|
bool SphereInsideFrustum( Sphere sphere, Frustum frustum, float zNear, float zFar )
|
|
{
|
|
bool result = true;
|
|
|
|
// First check depth
|
|
// Note: Here, the view vector points in the -Z axis so the
|
|
// far depth value will be approaching -infinity.
|
|
if ( sphere.m_origin.z - sphere.m_radius > zNear || sphere.m_origin.z + sphere.m_radius < zFar )
|
|
{
|
|
result = false;
|
|
}
|
|
|
|
// Then check frustum planes
|
|
for ( int i = 0; i < 4 && result; ++i )
|
|
{
|
|
if ( SphereInsidePlane( sphere, frustum.planes[i] ) )
|
|
{
|
|
result = false;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------------------------------- */
|
|
/* Cone */
|
|
/* ---------------------------------------------------------------------------------------------- */
|
|
|
|
struct Cone
|
|
{
|
|
float3 T; // Cone tip.
|
|
float h; // Height of the cone.
|
|
float3 d; // Direction of the cone.
|
|
float r; // bottom radius of the cone.
|
|
};
|
|
|
|
// Check to see if a cone if fully behind (inside the negative halfspace of) a plane.
|
|
// Source: Real-time collision detection, Christer Ericson (2005)
|
|
bool ConeInsidePlane( Cone cone, Plane plane )
|
|
{
|
|
// Compute the farthest point on the end of the cone to the positive space of the plane.
|
|
float3 m = cross( cross( plane.N, cone.d ), cone.d );
|
|
float3 Q = cone.T + cone.d * cone.h - m * cone.r;
|
|
|
|
// The cone is in the negative halfspace of the plane if both
|
|
// the tip of the cone and the farthest point on the end of the cone to the
|
|
// positive halfspace of the plane are both inside the negative halfspace
|
|
// of the plane.
|
|
return PointInsidePlane( cone.T, plane ) && PointInsidePlane( Q, plane );
|
|
}
|
|
|
|
bool ConeInsideFrustum( Cone cone, Frustum frustum, float zNear, float zFar )
|
|
{
|
|
bool result = true;
|
|
|
|
Plane nearPlane = { float3( 0, 0, -1 ), -zNear };
|
|
Plane farPlane = { float3( 0, 0, 1 ), zFar };
|
|
|
|
// First check the near and far clipping planes.
|
|
if ( ConeInsidePlane( cone, nearPlane ) || ConeInsidePlane( cone, farPlane ) )
|
|
{
|
|
result = false;
|
|
}
|
|
|
|
// Then check frustum planes
|
|
for ( int i = 0; i < 4 && result; ++i )
|
|
{
|
|
if ( ConeInsidePlane( cone, frustum.planes[i] ) )
|
|
{
|
|
result = false;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------------------------------- */
|
|
/* AABB */
|
|
/* ---------------------------------------------------------------------------------------------- */
|
|
|
|
struct Aabb {
|
|
float3 min;
|
|
float3 max;
|
|
};
|
|
|
|
float3 GetAabbCorner( Aabb aabb, float4x4 transform, uint index ) {
|
|
float3 t = float3(
|
|
( index & 1 ) ? 1. : 0.,
|
|
( index & 2 ) ? 1. : 0.,
|
|
( index & 4 ) ? 1. : 0. );
|
|
return mul(
|
|
transform,
|
|
float4( ( 1. - t ) * aabb.min + t * aabb.max, 1. ) ).xyz;
|
|
}
|
|
|
|
bool AabbInsidePlane( Aabb aabb, float4x4 transform, Plane plane ) {
|
|
bool result = true;
|
|
|
|
for( uint i = 0; i < 8 && result; ++i ) {
|
|
result = PointInsidePlane( GetAabbCorner( aabb, transform, i ), plane );
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
bool AabbInsideFrustum( Aabb aabb, float4x4 transform, Frustum frustum, float zNear, float zFar )
|
|
{
|
|
bool result = true;
|
|
|
|
Plane nearPlane = { float3( 0, 0, -1 ), -zNear };
|
|
Plane farPlane = { float3( 0, 0, 1 ), zFar };
|
|
|
|
// First check the near and far clipping planes.
|
|
if ( AabbInsidePlane( aabb, transform, nearPlane ) || AabbInsidePlane( aabb, transform, farPlane ) )
|
|
{
|
|
result = false;
|
|
}
|
|
|
|
// Then check frustum planes
|
|
for ( int i = 0; i < 4 && result; ++i )
|
|
{
|
|
if ( AabbInsidePlane( aabb, transform, frustum.planes[i] ) )
|
|
{
|
|
result = false;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
bool DoQueryInfiniteCone(in Sphere sphere, in ConeFrustum cone)
|
|
{
|
|
float3 U = cone.m_origin - (sphere.m_radius * cone.m_inv_sin_angle) * cone.m_direction;
|
|
float3 CmU = sphere.m_origin - U;
|
|
float AdCmU = dot(cone.m_direction, CmU);
|
|
if (AdCmU > 0.)
|
|
{
|
|
float sqrLengthCmU = dot(CmU, CmU);
|
|
if (AdCmU * AdCmU >= sqrLengthCmU * cone.m_cos_angle_sqr)
|
|
{
|
|
float3 CmV = sphere.m_origin - cone.m_origin;
|
|
float AdCmV = dot(cone.m_direction, CmV);
|
|
if (AdCmV < -sphere.m_radius)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
float rSinAngle = sphere.m_radius * cone.m_sin_angle;
|
|
if (AdCmV >= -rSinAngle)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
float sqrLengthCmV = dot(CmV, CmV);
|
|
return sqrLengthCmV <= sphere.m_radius * sphere.m_radius;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
#endif |