Browse Source

Add ray sphere intersection & some other refactoring

Panagiotis Christopoulos Charitos 9 years ago
parent
commit
82d09a356c

+ 2 - 2
src/anki/collision/Frustum.cpp

@@ -148,13 +148,13 @@ void PerspectiveFrustum::recalculate()
 	//
 	F32 c, s; // cos & sine
 
-	sinCos(getPi<F32>() + m_fovX / 2.0, s, c);
+	sinCos(PI + m_fovX / 2.0, s, c);
 	// right
 	m_planesL[PlaneType::RIGHT] = Plane(Vec4(c, 0.0, s, 0.0), 0.0);
 	// left
 	m_planesL[PlaneType::LEFT] = Plane(Vec4(-c, 0.0, s, 0.0), 0.0);
 
-	sinCos((getPi<F32>() + m_fovY) * 0.5, s, c);
+	sinCos((PI + m_fovY) * 0.5, s, c);
 	// bottom
 	m_planesL[PlaneType::BOTTOM] = Plane(Vec4(0.0, s, c, 0.0), 0.0);
 	// top

+ 2 - 2
src/anki/collision/Frustum.h

@@ -187,8 +187,8 @@ public:
 	{
 		ANKI_ASSERT(near > 0.0);
 		ANKI_ASSERT(far > near);
-		ANKI_ASSERT(fovX <= getPi<F32>());
-		ANKI_ASSERT(fovY <= getPi<F32>());
+		ANKI_ASSERT(fovX <= PI);
+		ANKI_ASSERT(fovY <= PI);
 		m_fovX = fovX;
 		m_fovY = fovY;
 		m_near = near;

+ 1 - 38
src/anki/collision/Obb.cpp

@@ -10,43 +10,6 @@
 namespace anki
 {
 
-Obb::Obb()
-	: Base(CollisionShapeType::OBB)
-	, m_center(Vec4(0.0))
-	, m_rotation(Mat3x4::getIdentity())
-	, m_transposedRotation(Mat3x4::getIdentity())
-	, m_extend(Vec3(getEpsilon<F32>()), 0.0)
-{
-}
-
-Obb::Obb(const Obb& b)
-	: Base(CollisionShapeType::OBB)
-{
-	operator=(b);
-}
-
-Obb::Obb(const Vec4& center, const Mat3x4& rotation, const Vec4& extend)
-	: Base(CollisionShapeType::OBB)
-	, m_center(center)
-	, m_rotation(rotation)
-	, m_transposedRotation(rotation)
-	, m_extend(extend)
-{
-	m_transposedRotation.transposeRotationPart();
-}
-
-Obb& Obb::operator=(const Obb& b)
-{
-	m_center = b.m_center;
-	m_rotation = b.m_rotation;
-	m_transposedRotation = b.m_transposedRotation;
-	m_extend = b.m_extend;
-
-	m_cache = b.m_cache;
-
-	return *this;
-}
-
 F32 Obb::testPlane(const Plane& p) const
 {
 	Vec4 xNormal = (m_transposedRotation * p.getNormal()).xyz0();
@@ -177,7 +140,7 @@ void Obb::computeAabb(Aabb& aabb) const
 	Vec4 newE = Vec4(absM * m_extend, 0.0);
 
 	// Add a small epsilon to avoid some assertions
-	Vec4 epsilon(Vec3(getEpsilon<F32>() * 100.0), 0.0);
+	Vec4 epsilon(Vec3(EPSILON * 100.0), 0.0);
 	aabb = Aabb(m_center - newE, m_center + newE + epsilon);
 
 	// Update cache

+ 43 - 18
src/anki/collision/Obb.h

@@ -22,11 +22,36 @@ class Obb : public ConvexShape
 public:
 	using Base = ConvexShape;
 
-	Obb();
+	Obb()
+		: Base(CollisionShapeType::OBB)
+	{
+	}
+
+	Obb(const Obb& b)
+		: Base(CollisionShapeType::OBB)
+	{
+		operator=(b);
+	}
 
-	Obb(const Obb& b);
+	Obb(const Vec4& center, const Mat3x4& rotation, const Vec4& extend)
+		: Base(CollisionShapeType::OBB)
+		, m_center(center)
+		, m_rotation(rotation)
+		, m_transposedRotation(rotation)
+		, m_extend(extend)
+	{
+		m_transposedRotation.transposeRotationPart();
+	}
 
-	Obb(const Vec4& center, const Mat3x4& rotation, const Vec4& extend);
+	Obb& operator=(const Obb& b)
+	{
+		m_center = b.m_center;
+		m_rotation = b.m_rotation;
+		m_transposedRotation = b.m_transposedRotation;
+		m_extend = b.m_extend;
+		m_cache = b.m_cache;
+		return *this;
+	}
 
 	const Vec4& getCenter() const
 	{
@@ -63,34 +88,32 @@ public:
 		m_extend = x;
 	}
 
-	Obb& operator=(const Obb& b);
-
 	/// Implements CollisionShape::accept
-	void accept(MutableVisitor& v)
+	void accept(MutableVisitor& v) override
 	{
 		v.visit(*this);
 	}
 	/// Implements CollisionShape::accept
-	void accept(ConstVisitor& v) const
+	void accept(ConstVisitor& v) const override
 	{
 		v.visit(*this);
 	}
 
 	/// Implements CollisionShape::testPlane
-	F32 testPlane(const Plane& p) const;
+	F32 testPlane(const Plane& p) const override;
 
 	/// Implements CollisionShape::transform
-	void transform(const Transform& trf)
+	void transform(const Transform& trf) override
 	{
 		*this = getTransformed(trf);
 	}
 
 	/// Implements CollisionShape::computeAabb
-	void computeAabb(Aabb& aabb) const;
+	void computeAabb(Aabb& aabb) const override;
 
 	Obb getTransformed(const Transform& transform) const;
 
-	/// Get a collision shape that includes this and the given. Its not very accurate
+	/// Get a collision shape that includes this and the given. It's not very accurate.
 	Obb getCompoundShape(const Obb& b) const;
 
 	/// Calculate from a set of points
@@ -100,16 +123,18 @@ public:
 	void getExtremePoints(Array<Vec4, 8>& points) const;
 
 	/// Implements ConvexShape::computeSupport
-	Vec4 computeSupport(const Vec4& dir) const;
+	Vec4 computeSupport(const Vec4& dir) const override;
 
-public:
-	Vec4 m_center;
-	Mat3x4 m_rotation;
-	Mat3x4 m_transposedRotation; ///< Used for visibility tests
-	Vec4 m_extend; ///< With identity rotation this points to max (front, right, top in our case)
+private:
+	Vec4 m_center = Vec4(0.0f);
+	Mat3x4 m_rotation = Mat3x4::getIdentity();
+	Mat3x4 m_transposedRotation = Mat3x4::getIdentity(); ///< Used for visibility tests
+	/// With identity rotation this points to max (front, right, top in our case)
+	Vec4 m_extend = Vec4(Vec3(EPSILON), 0.0);
 
-	struct
+	class
 	{
+	public:
 		mutable Aabb m_aabb;
 		mutable Array<Vec4, 8> m_extremePoints;
 		mutable Bool8 m_dirtyAabb = true;

+ 49 - 0
src/anki/collision/Sphere.cpp

@@ -143,4 +143,53 @@ Vec4 Sphere::computeSupport(const Vec4& dir) const
 	return m_center + dir.getNormalized() * m_radius;
 }
 
+Bool Sphere::intersectsRay(
+	const Vec4& rayDir, const Vec4& rayOrigin, Array<Vec4, 2>& intersectionPoints, U& intersectionPointCount) const
+{
+	ANKI_ASSERT(isZero(rayDir.getLengthSquared() - 1.0));
+	ANKI_ASSERT(rayDir.w() == 0.0 && rayOrigin.w() == 0.0);
+
+	// See https://en.wikipedia.org/wiki/Line%E2%80%93sphere_intersection
+
+	const Vec4& o = rayOrigin;
+	const Vec4& l = rayDir;
+	const Vec4& c = m_center;
+	F32 R = m_radius;
+
+	Vec4 o_c = o - c;
+
+	F32 a = l.dot(o_c);
+	F32 b = a * a - o_c.getLengthSquared() + R * R;
+
+	if(b < 0.0)
+	{
+		intersectionPointCount = 0;
+		return false;
+	}
+	else if(b == 0.0)
+	{
+		intersectionPointCount = 1;
+		intersectionPoints[0] = -a * l + o;
+		return true;
+	}
+	else
+	{
+		F32 d = -a - sqrt(b);
+		intersectionPointCount = 0;
+		if(d > 0.0)
+		{
+			intersectionPointCount = 1;
+			intersectionPoints[0] = d * l + o;
+		}
+
+		d = -a + sqrt(b);
+		if(d > 0.0)
+		{
+			intersectionPoints[intersectionPointCount++] = d * l + o;
+		}
+
+		return intersectionPointCount > 0;
+	}
+}
+
 } // end namespace anki

+ 4 - 0
src/anki/collision/Sphere.h

@@ -114,6 +114,10 @@ public:
 	/// Implements CompoundShape::computeSupport
 	Vec4 computeSupport(const Vec4& dir) const;
 
+	/// Intersect a ray with the sphere. It will not return the points that are not part of the ray.
+	Bool intersectsRay(
+		const Vec4& rayDir, const Vec4& rayOrigin, Array<Vec4, 2>& intersectionPoints, U& intersectionPointCount) const;
+
 private:
 	Vec4 m_center;
 	F32 m_radius;

+ 1 - 1
src/anki/event/JitterMoveEvent.cpp

@@ -43,7 +43,7 @@ Error JitterMoveEvent::update(F32 prevUpdateTime, F32 crntTime)
 
 	Transform trf = move.getLocalTransform();
 
-	F32 factor = sin(getDelta(crntTime) * getPi<F32>());
+	F32 factor = sin(getDelta(crntTime) * PI);
 
 	trf.getOrigin() = linearInterpolate(m_originalPos, m_newPos, factor);
 

+ 1 - 1
src/anki/event/LightEvent.cpp

@@ -41,7 +41,7 @@ Error LightEvent::update(F32 prevUpdateTime, F32 crntTime)
 {
 	F32 freq = randRange(m_freq - m_freqDeviation, m_freq + m_freqDeviation);
 
-	F32 factor = sin(crntTime * freq * getPi<F32>()) / 2.0 + 0.5;
+	F32 factor = sin(crntTime * freq * PI) / 2.0 + 0.5;
 	LightComponent& lightc = getSceneNode()->getComponent<LightComponent>();
 
 	// Update radius

+ 1 - 1
src/anki/math/Axisang.h

@@ -67,7 +67,7 @@ public:
 				return;
 			}
 
-			m_ang = getPi<T>();
+			m_ang = PI;
 			m_axis.x() = (m3(0, 0) + 1.0) / 2.0;
 			if(m_axis.x() > 0.0)
 			{

+ 2 - 2
src/anki/math/Euler.h

@@ -45,14 +45,14 @@ public:
 		if(test > 0.499)
 		{
 			y() = 2.0 * atan2<T>(q.x(), q.w());
-			z() = getPi<T>() / 2.0;
+			z() = PI / 2.0;
 			x() = 0.0;
 			return;
 		}
 		if(test < -0.499)
 		{
 			y() = -2.0 * atan2<T>(q.x(), q.w());
-			z() = -getPi<T>() / 2.0;
+			z() = -PI / 2.0;
 			x() = 0.0;
 			return;
 		}

+ 8 - 36
src/anki/math/Functions.h

@@ -15,39 +15,11 @@ namespace anki
 /// @addtogroup math
 /// @{
 
-template<typename Scalar>
-constexpr Scalar getPi();
+/// Just PI.
+const F32 PI = 3.14159265358979323846f;
 
-template<>
-inline constexpr F32 getPi<F32>()
-{
-	return 3.14159265358979323846f;
-}
-
-template<>
-inline constexpr F64 getPi<F64>()
-{
-	return 3.14159265358979323846;
-}
-
-template<typename Scalar>
-constexpr Scalar getEpsilon()
-{
-	static_assert(1, "Shouldn't instantiate");
-	return Scalar(0);
-}
-
-template<>
-constexpr F32 getEpsilon<F32>()
-{
-	return 1.0e-6f;
-}
-
-template<>
-constexpr F64 getEpsilon<F64>()
-{
-	return 1.0e-6;
-}
+/// Floating point epsilon.
+const F32 EPSILON = 1.0e-6f;
 
 template<typename T>
 inline T sin(const T rad)
@@ -145,7 +117,7 @@ inline F64 absolute(const F64 f)
 template<typename T>
 inline Bool isZero(const T f)
 {
-	return absolute<T>(f) < getEpsilon<T>();
+	return absolute<T>(f) < EPSILON;
 }
 
 #define ANKI_SPECIALIZE_IS_ZERO_INT(type_)                                                                             \
@@ -169,13 +141,13 @@ ANKI_SPECIALIZE_IS_ZERO_INT(U64)
 template<typename T>
 inline T toRad(const T degrees)
 {
-	return degrees * (getPi<T>() / T(180));
+	return degrees * (PI / T(180));
 }
 
 template<typename T>
 inline T toDegrees(const T rad)
 {
-	return rad * (T(180) / getPi<T>());
+	return rad * (T(180) / PI);
 }
 
 /// Linear interpolation between values
@@ -195,7 +167,7 @@ static Type linearInterpolate(const Type& from, const Type& to, F32 u)
 template<typename Type>
 static Type cosInterpolate(const Type& from, const Type& to, F32 u)
 {
-	F32 u2 = (1.0 - cos<F32>(u * getPi<F32>())) / 2.0;
+	F32 u2 = (1.0 - cos<F32>(u * PI)) / 2.0;
 	return from * (1.0 - u2) + to * u2;
 }
 

+ 2 - 2
src/anki/math/Quat.h

@@ -78,7 +78,7 @@ public:
 	explicit TQuat(const TMat3<T>& m3)
 	{
 		T trace = m3(0, 0) + m3(1, 1) + m3(2, 2) + 1.0;
-		if(trace > getEpsilon<T>())
+		if(trace > EPSILON)
 		{
 			T s = 0.5 / sqrt<T>(trace);
 			w() = 0.25 / s;
@@ -174,7 +174,7 @@ public:
 		normalize();
 		w() += 1.0;
 
-		if(w() <= getEpsilon<T>())
+		if(w() <= EPSILON)
 		{
 			if(from.z() * from.z() > from.x() * from.x())
 			{

+ 1 - 1
src/anki/physics/PhysicsPlayerController.cpp

@@ -172,7 +172,7 @@ Error PhysicsPlayerController::create(const PhysicsPlayerControllerInitInfo& ini
 	}
 
 	// Create the outer thick cylinder
-	Mat4 outerShapeRot(Mat3(Axisang(getPi<F32>() / 2.0, Vec3(0.0, 0.0, 1.0))));
+	Mat4 outerShapeRot(Mat3(Axisang(PI / 2.0, Vec3(0.0, 0.0, 1.0))));
 	Mat4 outerShapeMatrix = localAxis * outerShapeRot;
 	F32 capsuleHeight = m_height - m_stepHeight;
 	ANKI_ASSERT(capsuleHeight > 0.0);

+ 19 - 0
src/anki/renderer/Clusterer.cpp

@@ -43,6 +43,25 @@ Clusterer::~Clusterer()
 	m_allPlanes.destroy(m_alloc);
 }
 
+void Clusterer::initDisk()
+{
+	ANKI_ASSERT(m_disk.getSize() == 8 && "Assumes that");
+
+	// The radius is a little bit bigger than 1.0
+	F32 radius = 1.0 / cos(PI / 8.0);
+
+	for(U i = 0; i < 8; ++i)
+	{
+		F32 ang = (PI / 2.0) / 8.0;
+		ang = i * ang;
+
+		F32 x = cos(ang) * radius;
+		F32 y = sin(ang) * radius;
+
+		m_disk[i] = Vec4(x, y, 0.0, 0.0);
+	}
+}
+
 void Clusterer::initTestResults(const GenericMemoryPoolAllocator<U8>& alloc, ClustererTestResult& rez) const
 {
 	rez.m_clusterIds.create(alloc, getClusterCount());

+ 6 - 0
src/anki/renderer/Clusterer.h

@@ -141,6 +141,10 @@ private:
 	F32 m_calcNearOpt = 0.0;
 	F32 m_shaderMagicVal = 0.0;
 
+	Array<Vec4, 8> m_disk; ///< To bin a sphere in tiles.
+
+	void initDisk();
+
 	F32 calcNear(U k) const;
 
 	U calcZ(F32 zVspace) const;
@@ -163,6 +167,8 @@ private:
 
 	/// Call this when a shape is visible by all tiles.
 	void totallyInsideAllTiles(U zBegin, U zEnd, ClustererTestResult& rez) const;
+
+	void createConverHull();
 };
 /// @}
 

+ 15 - 20
src/anki/renderer/Dbg.cpp

@@ -176,30 +176,25 @@ Error Dbg::run(RenderingContext& ctx)
 		CollisionDebugDrawer cd(m_drawer);
 		Mat4 proj = camFrc.getProjectionMatrix();
 
-		Array<Plane, 6> planes;
-		Array<Plane*, 6> pplanes = {&planes[0],
-			&planes[1],
-			&planes[2],
-			&planes[3],
-			&planes[4],
-			&planes[5]};
-		extractClipPlanes(proj, pplanes);
+		m_drawer->setViewProjectionMatrix(camFrc.getViewProjectionMatrix());
 
-		planes[5].accept(cd);
+		Sphere s(Vec4(1.2, 2.0, -1.1, 0.0), 2.1);
 
-		m_drawer->setViewProjectionMatrix(camFrc.getViewProjectionMatrix());
-		m_drawer->setModelMatrix(Mat4::getIdentity());
+		s.accept(cd);
 
-		m_drawer->setColor(Vec4(0.0, 1.0, 1.0, 1.0));
-		PerspectiveFrustum frc;
-		const PerspectiveFrustum& cfrc =
-			(const PerspectiveFrustum&)camFrc.getFrustum();
-		frc.setAll(
-			cfrc.getFovX(), cfrc.getFovY(), cfrc.getNear(), cfrc.getFar());
-		cd.visit(frc);
+		Transform trf = scene.findSceneNode("light0").getComponent<MoveComponent>().getWorldTransform();
+		Vec4 rayOrigin = trf.getOrigin();
+		Vec3 rayDir = -trf.getRotation().getZAxis().getNormalized();
+		m_drawer->setModelMatrix(Mat4::getIdentity());
+		m_drawer->drawLine(rayOrigin.xyz(), rayOrigin.xyz() + rayDir.xyz() * 10.0, Vec4(1.0, 1.0, 1.0, 1.0));
 
-		m_drawer->drawLine(Vec3(0.0), planes[5].getNormal().xyz() * 100.0, 
-			Vec4(1.0));
+		Array<Vec4, 2> intersectionPoints;
+		U intersectionPointCount;
+		s.intersectsRay(rayDir.xyz0(), rayOrigin, intersectionPoints, intersectionPointCount);
+		for(U i = 0; i < intersectionPointCount; ++i)
+		{
+			m_drawer->drawLine(Vec3(0.0), intersectionPoints[i].xyz(), Vec4(0.0, 1.0, 0.0, 1.0));
+		}
 	}
 #endif
 

+ 6 - 6
src/anki/renderer/DebugDrawer.cpp

@@ -256,14 +256,14 @@ void DebugDrawer::drawSphere(F32 radius, I complexity)
 	begin(PrimitiveTopology::LINES);
 
 	// Pre-calculate the sphere points5
-	F32 fi = getPi<F32>() / complexity;
+	F32 fi = PI / complexity;
 
 	Vec3 prev(1.0, 0.0, 0.0);
-	for(F32 th = fi; th < getPi<F32>() * 2.0 + fi; th += fi)
+	for(F32 th = fi; th < PI * 2.0 + fi; th += fi)
 	{
 		Vec3 p = Mat3(Euler(0.0, th, 0.0)) * Vec3(1.0, 0.0, 0.0);
 
-		for(F32 th2 = 0.0; th2 < getPi<F32>(); th2 += fi)
+		for(F32 th2 = 0.0; th2 < PI; th2 += fi)
 		{
 			Mat3 rot(Euler(th2, 0.0, 0.0));
 
@@ -273,7 +273,7 @@ void DebugDrawer::drawSphere(F32 radius, I complexity)
 			pushBackVertex(rotPrev);
 			pushBackVertex(rotP);
 
-			Mat3 rot2(Euler(0.0, 0.0, getPi<F32>() / 2));
+			Mat3 rot2(Euler(0.0, 0.0, PI / 2));
 
 			pushBackVertex(rot2 * rotPrev);
 			pushBackVertex(rot2 * rotP);
@@ -341,7 +341,7 @@ void CollisionDebugDrawer::visit(const Plane& plane)
 	Quat q;
 	q.setFrom2Vec3(Vec3(0.0, 0.0, 1.0), n);
 	Mat3 rot(q);
-	rot.rotateXAxis(getPi<F32>() / 2.0);
+	rot.rotateXAxis(PI / 2.0);
 	Mat4 trf(Vec4(n * o, 1.0), rot);
 
 	m_dbg->setModelMatrix(trf);
@@ -388,7 +388,7 @@ void CollisionDebugDrawer::visit(const Frustum& f)
 		const PerspectiveFrustum& pf = static_cast<const PerspectiveFrustum&>(f);
 
 		F32 camLen = pf.getFar();
-		F32 tmp0 = camLen / tan((getPi<F32>() - pf.getFovX()) * 0.5) + 0.001;
+		F32 tmp0 = camLen / tan((PI - pf.getFovX()) * 0.5) + 0.001;
 		F32 tmp1 = camLen * tan(pf.getFovY() * 0.5) + 0.001;
 
 		Vec3 points[] = {

+ 0 - 1
src/anki/scene/Light.cpp

@@ -205,7 +205,6 @@ Error PointLight::frameUpdate(F32 prevUpdateTime, F32 crntTime)
 		const F32 zNear = LightComponent::FRUSTUM_NEAR_PLANE;
 
 		Mat3 rot;
-		const F32 PI = getPi<F32>();
 
 		rot = Mat3(Euler(0.0, -PI / 2.0, 0.0)) * Mat3(Euler(0.0, 0.0, PI));
 		m_shadowData[0].m_localTrf.setRotation(Mat3x4(rot));

+ 1 - 1
src/anki/scene/ParticleEmitter.cpp

@@ -444,7 +444,7 @@ Error ParticleEmitter::frameUpdate(F32 prevUpdateTime, F32 crntTime)
 			// Set alpha
 			if(m_particle.m_alphaAnimation)
 			{
-				verts[4] = sin((lifePercent)*getPi<F32>()) * p->m_alpha;
+				verts[4] = sin((lifePercent)*PI) * p->m_alpha;
 			}
 			else
 			{

+ 0 - 1
src/anki/scene/ReflectionProbe.cpp

@@ -63,7 +63,6 @@ Error ReflectionProbe::init(F32 radius)
 	const F32 zNear = FRUSTUM_NEAR_PLANE;
 
 	Mat3 rot;
-	const F32 PI = getPi<F32>();
 
 	rot = Mat3(Euler(0.0, -PI / 2.0, 0.0)) * Mat3(Euler(0.0, 0.0, PI));
 	m_cubeSides[0].m_localTrf.setRotation(Mat3x4(rot));

+ 1 - 1
src/anki/scene/Sector.cpp

@@ -451,7 +451,7 @@ void SectorGroup::binSpatial(SpatialComponent* sp)
 			}
 
 			// Detailed test
-			const F32 smallf = getEpsilon<F32>() * 10.0;
+			const F32 smallf = EPSILON * 10.0;
 			Aabb smallBox(center, center + Vec4(smallf, smallf, smallf, 0.0));
 			if(collide)
 			{

+ 1 - 1
src/anki/scene/SoftwareRasterizer.cpp

@@ -42,7 +42,7 @@ void SoftwareRasterizer::clipTriangle(const Vec4* inVerts, Vec4* outVerts, U& ou
 	ANKI_ASSERT(inVerts && outVerts);
 
 	const Plane& plane = m_planesL[Frustum::PlaneType::NEAR];
-	F32 clipZ = -plane.getOffset() - getEpsilon<F32>();
+	F32 clipZ = -plane.getOffset() - EPSILON;
 	ANKI_ASSERT(clipZ < 0.0);
 
 	Array<Bool, 3> vertInside;