Browse Source

More work on the S/W rasterizer

Panagiotis Christopoulos Charitos 9 years ago
parent
commit
0ac267000c

+ 40 - 0
include/anki/math/Vec.h

@@ -2165,6 +2165,46 @@ public:
 		return out;
 	}
 
+	/// Clamp between two values.
+	void clamp(const T& minv, const T& maxv)
+	{
+		for(U i = 0; i < N; ++i)
+		{
+			m_arr[i] = min<T>(max<T>(minv, m_arr[i]), maxv);
+		}
+	}
+
+	/// Get clamped between two values.
+	TV getClamped(const T& minv, const T& maxv) const
+	{
+		TV out;
+		for(U i = 0; i < N; ++i)
+		{
+			out[i] = min<T>(max<T>(minv, m_arr[i]), maxv);
+		}
+		return out;
+	}
+
+	/// Clamp between two vectors.
+	void clamp(const TV& minv, const TV& maxv)
+	{
+		for(U i = 0; i < N; ++i)
+		{
+			m_arr[i] = min<T>(max<T>(minv[i], m_arr[i]), maxv[i]);
+		}
+	}
+
+	/// Get clamped between two vectors.
+	TV getClamped(const TV& minv, const TV& maxv) const
+	{
+		TV out;
+		for(U i = 0; i < N; ++i)
+		{
+			out[i] = min<T>(max<T>(minv[i], m_arr[i]), maxv[i]);
+		}
+		return out;
+	}
+
 	template<typename TAlloc>
 	String toString(TAlloc alloc) const
 	{

+ 6 - 5
include/anki/math/Vec4.h

@@ -109,20 +109,21 @@ public:
 	/// @{
 
 	/// It's like calculating the cross of a TVec3
-	TVec4 cross(const TVec4& b) const
+	ANKI_USE_RESULT TVec4 cross(const TVec4& b) const
 	{
 		ANKI_ASSERT(isZero<T>(Base::w()));
 		ANKI_ASSERT(isZero<T>(b.w()));
 		return TVec4(Base::xyz().cross(b.xyz()), static_cast<T>(0));
 	}
 
-	TVec4 projectTo(const TVec4& toThis) const
+	ANKI_USE_RESULT TVec4 projectTo(const TVec4& toThis) const
 	{
 		ANKI_ASSERT(w() == T(0));
 		return (toThis * ((*this).dot(toThis) / (toThis.dot(toThis)))).xyz0();
 	}
 
-	TVec4 projectTo(const TVec4& rayOrigin, const TVec4& rayDir) const
+	ANKI_USE_RESULT TVec4 projectTo(
+		const TVec4& rayOrigin, const TVec4& rayDir) const
 	{
 		const auto& a = *this;
 		return rayOrigin + rayDir * ((a - rayOrigin).dot(rayDir));
@@ -133,7 +134,7 @@ public:
 	/// @{
 
 	/// @note 16 muls 12 adds
-	TVec4 operator*(const TMat4<T>& m4) const
+	ANKI_USE_RESULT TVec4 operator*(const TMat4<T>& m4) const
 	{
 		return TVec4(
 			x() * m4(0, 0) + y() * m4(1, 0) + z() * m4(2, 0) + w() * m4(3, 0),
@@ -144,7 +145,7 @@ public:
 
 	/// Perspective divide. Divide the xyzw of this to the w of this. This
 	/// method will handle some edge cases.
-	TVec4 perspectiveDivide() const
+	ANKI_USE_RESULT TVec4 perspectiveDivide() const
 	{
 		auto invw = T(1) / w(); // This may become (+-)inf
 		invw = (invw > 1e+11) ? 1e+11 : invw; // Clamp

+ 9 - 1
include/anki/scene/SoftwareRasterizer.h

@@ -43,11 +43,19 @@ public:
 	/// @param stride The stride (in bytes) of the next vertex.
 	void draw(const F32* verts, U vertCount, U stride);
 
+	/// Perform visibility tests.
+	/// @param cs The collision shape in world space.
+	/// @param aabb The Aabb in of the cs in world space.
+	/// @return Return true if it's visible and false otherwise.
+	Bool visibilityTest(const CollisionShape& cs, const Aabb& aabb) const;
+
 public: // XXX
 	GenericMemoryPoolAllocator<U8> m_alloc;
 	Mat4 m_mv; ///< ModelView.
 	Mat4 m_p; ///< Projection.
-	Array<Plane, 6> m_planes; ///< In view space.
+	Mat4 m_mvp;
+	Array<Plane, 6> m_planesL; ///< In view space.
+	Array<Plane, 6> m_planesW; ///< In world space.
 	U32 m_width;
 	U32 m_height;
 	DArray<Atomic<U32>> m_zbuffer;

+ 2 - 2
sandbox/Main.cpp

@@ -76,7 +76,7 @@ Error MyApp::init(int argc, char* argv[])
 //==============================================================================
 Error MyApp::userMainLoop(Bool& quit)
 {
-	F32 dist = 0.1;
+	F32 dist = 0.05;
 	F32 ang = toRad(2.5);
 	F32 scale = 0.01;
 	F32 mouseSensivity = 9.0;
@@ -102,7 +102,7 @@ Error MyApp::userMainLoop(Bool& quit)
 	}
 	if(in.getKey(KeyCode::_2))
 	{
-		mover = &scene.findSceneNode("proxy").getComponent<MoveComponent>();
+		mover = &scene.findSceneNode("Lamp").getComponent<MoveComponent>();
 	}
 
 	if(in.getKey(KeyCode::L) == 1)

+ 22 - 12
src/renderer/Dbg.cpp

@@ -221,7 +221,7 @@ Error Dbg::run(RenderingContext& ctx)
 			view, proj, m_r->getTileCountXY().x(), m_r->getTileCountXY().y());
 		r.draw(&ltriangle[0][0], 12, sizeof(Vec4));
 
-		m_drawer->begin(PrimitiveTopology::TRIANGLES);
+		/*m_drawer->begin(PrimitiveTopology::TRIANGLES);
 		U count = 0;
 		for(U y = 0; y < m_r->getTileCountXY().y(); ++y)
 		{
@@ -258,22 +258,32 @@ Error Dbg::run(RenderingContext& ctx)
 				}
 			}
 		}
-		m_drawer->end();
-		// printf("%u\n", count);
+		m_drawer->end();*/
 
 		m_drawer->setViewProjectionMatrix(camFrc.getViewProjectionMatrix());
 		Vec3 offset(0.0, 0.0, 0.0);
+		m_drawer->setColor(Vec4(0.5));
+		m_drawer->begin(PrimitiveTopology::TRIANGLES);
 		for(U i = 0; i < ltriangle.getSize() / 3; ++i)
 		{
-			m_drawer->drawLine(ltriangle[i * 3 + 0].xyz() + offset,
-				ltriangle[i * 3 + 1].xyz() + offset,
-				Vec4(0, 0.2, 0, 1));
-			m_drawer->drawLine(ltriangle[i * 3 + 1].xyz() + offset,
-				ltriangle[i * 3 + 2].xyz() + offset,
-				Vec4(0.0, 0.2, 0.0, 1.0));
-			m_drawer->drawLine(ltriangle[i * 3 + 2].xyz() + offset,
-				ltriangle[i * 3 + 0].xyz() + offset,
-				Vec4(0.0, 0.2, 0.0, 1.0));
+			m_drawer->pushBackVertex(ltriangle[i * 3 + 0].xyz());
+			m_drawer->pushBackVertex(ltriangle[i * 3 + 1].xyz());
+			m_drawer->pushBackVertex(ltriangle[i * 3 + 2].xyz());
+		}
+		m_drawer->end();
+
+		SceneNode& node = scene.findSceneNode("Lamp");
+		SpatialComponent& spc = node.getComponent<SpatialComponent>();
+		Aabb nodeAabb = spc.getAabb();
+
+		Bool inside =
+			r.visibilityTest(spc.getSpatialCollisionShape(), nodeAabb);
+
+		if(inside)
+		{
+			m_drawer->setColor(Vec4(1.0, 0.0, 0.0, 1.0));
+			CollisionDebugDrawer cd(m_drawer);
+			nodeAabb.accept(cd);
 		}
 	}
 #endif

+ 85 - 12
src/scene/SoftwareRasterizer.cpp

@@ -15,15 +15,24 @@ void SoftwareRasterizer::prepare(
 {
 	m_mv = mv;
 	m_p = p;
-
-	Array<Plane*, 6> planes = {&m_planes[0],
-		&m_planes[1],
-		&m_planes[2],
-		&m_planes[3],
-		&m_planes[4],
-		&m_planes[5]};
+	m_mvp = p * mv;
+
+	Array<Plane*, 6> planes = {&m_planesL[0],
+		&m_planesL[1],
+		&m_planesL[2],
+		&m_planesL[3],
+		&m_planesL[4],
+		&m_planesL[5]};
 	extractClipPlanes(p, planes);
 
+	Array<Plane*, 6> planes2 = {&m_planesW[0],
+		&m_planesW[1],
+		&m_planesW[2],
+		&m_planesW[3],
+		&m_planesW[4],
+		&m_planesW[5]};
+	extractClipPlanes(m_mvp, planes2);
+
 	// Reset z buffer
 	ANKI_ASSERT(width > 0 && height > 0);
 	m_width = width;
@@ -43,7 +52,7 @@ void SoftwareRasterizer::clipTriangle(
 {
 	ANKI_ASSERT(inVerts && outVerts);
 
-	const Plane& plane = m_planes[Frustum::PlaneType::NEAR];
+	const Plane& plane = m_planesL[Frustum::PlaneType::NEAR];
 	F32 clipZ = -plane.getOffset() - getEpsilon<F32>();
 	ANKI_ASSERT(clipZ < 0.0);
 
@@ -189,10 +198,10 @@ void SoftwareRasterizer::draw(const F32* verts, U vertCount, U stride)
 		// Cull if backfacing
 		Vec4 norm =
 			(triVspace[1] - triVspace[0]).cross(triVspace[2] - triVspace[1]);
-		ANKI_ASSERT(norm.w() == 0.0);
+		ANKI_ASSERT(norm.w() == 0.0f);
 
 		Vec4 eye = triVspace[0].xyz0();
-		if(norm.dot(eye) >= 0.0)
+		if(norm.dot(eye) >= 0.0f)
 		{
 			continue;
 		}
@@ -214,7 +223,7 @@ void SoftwareRasterizer::draw(const F32* verts, U vertCount, U stride)
 			for(U k = 0; k < 3; k++)
 			{
 				clip[k] = m_p * clippedTrisVspace[j + k].xyz1();
-				ANKI_ASSERT(clip[k].w() > 0.0);
+				ANKI_ASSERT(clip[k].w() > 0.0f);
 			}
 
 			rasterizeTriangle(&clip[0]);
@@ -240,7 +249,7 @@ Bool SoftwareRasterizer::computeBarycetrinc(
 	{
 		uvw = Vec3(1.0 - (k.x() + k.y()) / k.z(), k.y() / k.z(), k.x() / k.z());
 
-		if(uvw.x() < 0.0 || uvw.y() < 0.0 || uvw.z() < 0.0)
+		if(uvw.x() < 0.0f || uvw.y() < 0.0f || uvw.z() < 0.0f)
 		{
 			skip = true;
 		}
@@ -300,4 +309,68 @@ void SoftwareRasterizer::rasterizeTriangle(const Vec4* tri)
 	}
 }
 
+//==============================================================================
+Bool SoftwareRasterizer::visibilityTest(
+	const CollisionShape& cs, const Aabb& aabb) const
+{
+	// Set the AABB points
+	const Vec4& minv = aabb.getMin();
+	const Vec4& maxv = aabb.getMax();
+	Array<Vec4, 8> boxPoints;
+	boxPoints[0] = minv.xyz1();
+	boxPoints[1] = Vec4(minv.x(), maxv.y(), minv.z(), 1.0f);
+	boxPoints[2] = Vec4(minv.x(), maxv.y(), maxv.z(), 1.0f);
+	boxPoints[3] = Vec4(minv.x(), minv.y(), maxv.z(), 1.0f);
+	boxPoints[4] = maxv.xyz1();
+	boxPoints[5] = Vec4(maxv.x(), minv.y(), maxv.z(), 1.0f);
+	boxPoints[6] = Vec4(maxv.x(), minv.y(), minv.z(), 1.0f);
+	boxPoints[7] = Vec4(maxv.x(), maxv.y(), minv.z(), 1.0f);
+
+	// Compute bounding box
+	const Vec2 windowSize(m_width, m_height);
+
+	Vec2 bboxMin(MAX_F32), bboxMax(MIN_F32);
+	F32 minZ = MAX_F32;
+	for(Vec4& p : boxPoints)
+	{
+		p = m_mvp * p;
+		if(p.w() <= 0.0f)
+		{
+			// Don't bother clipping. Just mark it as visible.
+			return true;
+		}
+
+		p = p.perspectiveDivide();
+
+		for(U i = 0; i < 2; ++i)
+		{
+			F32 a = (p[i] / 2.0f + 0.5f) * windowSize[i];
+
+			bboxMin[i] = min(bboxMin[i], floorf(a));
+			bboxMin[i] = clamp(bboxMin[i], 0.0f, windowSize[i]);
+
+			bboxMax[i] = max(bboxMax[i], ceilf(a));
+			bboxMax[i] = clamp(bboxMax[i], 0.0f, windowSize[i]);
+		}
+
+		minZ = min(minZ, p.z() / 2.0f + 0.5f);
+	}
+
+	for(U y = bboxMin.y(); y < bboxMax.y(); y += 1.0f)
+	{
+		for(U x = bboxMin.x(); x < bboxMax.x(); x += 1.0f)
+		{
+			U idx = U(y) * m_width + U(x);
+			U32 depthi = m_zbuffer[idx].get();
+			F32 depthf = depthi / F32(MAX_U32);
+			if(minZ < depthf)
+			{
+				return true;
+			}
+		}
+	}
+
+	return false;
+}
+
 } // end namespace anki