Browse Source

Preliminary support for deferred decals

Panagiotis Christopoulos Charitos 9 years ago
parent
commit
6c34ee67ea

+ 0 - 3
include/anki/collision/Frustum.h

@@ -222,9 +222,6 @@ public:
 	/// Implements Frustum::calculateProjectionMatrix
 	Mat4 calculateProjectionMatrix() const override;
 
-	static void calculateProjectionMatrix(
-		F32 fovX, F32 fovY, F32 near, F32 far, Mat4& proj);
-
 private:
 	/// @name Viewing variables
 	/// @{

+ 64 - 0
include/anki/math/Mat4.h

@@ -423,6 +423,70 @@ public:
 			m(1, 0) * v.x() + m(1, 1) * v.y() + m(1, 2) * v.z() + m(1, 3),
 			m(2, 0) * v.x() + m(2, 1) * v.y() + m(2, 2) * v.z() + m(2, 3));
 	}
+
+	static TMat4 calculatePerspectiveProjectionMatrix(
+		T fovX, T fovY, T near, T far)
+	{
+		ANKI_ASSERT(fovX > T(0) && fovY > T(0) && near > T(0) && far > T(0));
+		T g = near - far;
+
+		T f = T(1) / tan(fovY / T(2)); // f = cot(fovY/2)
+
+		TMat4 proj;
+		proj(0, 0) = f * (fovY / fovX); // = f/aspectRatio;
+		proj(0, 1) = T(0);
+		proj(0, 2) = T(0);
+		proj(0, 3) = T(0);
+		proj(1, 0) = T(0);
+		proj(1, 1) = f;
+		proj(1, 2) = T(0);
+		proj(1, 3) = T(0);
+		proj(2, 0) = T(0);
+		proj(2, 1) = T(0);
+		proj(2, 2) = (far + near) / g;
+		proj(2, 3) = (T(2) * far * near) / g;
+		proj(3, 0) = T(0);
+		proj(3, 1) = T(0);
+		proj(3, 2) = T(-1);
+		proj(3, 3) = T(0);
+
+		return proj;
+	}
+
+	static TMat4 calculateOrthographicProjectionMatrix(
+		T right, T left, T top, T bottom, T near, T far)
+	{
+		ANKI_ASSERT(right != T(0) && left != T(0) && top != T(0)
+			&& bottom != T(0)
+			&& near != T(0)
+			&& far != T(0));
+		T difx = right - left;
+		T dify = top - bottom;
+		T difz = far - near;
+		T tx = -(right + left) / difx;
+		T ty = -(top + bottom) / dify;
+		T tz = -(far + near) / difz;
+		TMat4 m;
+
+		m(0, 0) = T(2) / difx;
+		m(0, 1) = T(0);
+		m(0, 2) = T(0);
+		m(0, 3) = tx;
+		m(1, 0) = T(0);
+		m(1, 1) = T(2) / dify;
+		m(1, 2) = T(0);
+		m(1, 3) = ty;
+		m(2, 0) = T(0);
+		m(2, 1) = T(0);
+		m(2, 2) = T(-2) / difz;
+		m(2, 3) = tz;
+		m(3, 0) = T(0);
+		m(3, 1) = T(0);
+		m(3, 2) = T(0);
+		m(3, 3) = T(1);
+
+		return m;
+	}
 	/// @}
 };
 

+ 1 - 0
include/anki/resource/Common.h

@@ -70,6 +70,7 @@ ANKI_FORWARD(Script, ScriptResourcePtr)
 ANKI_FORWARD(DummyRsrc, DummyResourcePtr)
 ANKI_FORWARD(CollisionResource, CollisionResourcePtr)
 ANKI_FORWARD(GenericResource, GenericResourcePtr)
+ANKI_FORWARD(TextureAtlas, TextureAtlasResourcePtr)
 
 #undef ANKI_FORWARD
 

+ 2 - 1
include/anki/resource/ResourceManager.h

@@ -112,7 +112,8 @@ class ResourceManager : public TypeResourceManager<Animation>,
 						public TypeResourceManager<Script>,
 						public TypeResourceManager<DummyRsrc>,
 						public TypeResourceManager<CollisionResource>,
-						public TypeResourceManager<GenericResource>
+						public TypeResourceManager<GenericResource>,
+						public TypeResourceManager<TextureAtlas>
 {
 	template<typename T>
 	friend class ResourcePtrDeleter;

+ 76 - 0
include/anki/resource/TextureAtlas.h

@@ -0,0 +1,76 @@
+// Copyright (C) 2009-2016, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma once
+
+#include <anki/resource/ResourceObject.h>
+#include <anki/resource/TextureResource.h>
+#include <anki/Gr.h>
+
+namespace anki
+{
+
+/// @addtogroup resource
+/// @{
+
+/// Texture atlas resource class.
+///
+/// XML format:
+/// @code
+/// <textureAtlas>
+/// 	<texture>path/to/tex.ankitex</texture>
+/// 	<subTextures>
+/// 		<subTexture>
+/// 			<name>name</name>
+/// 			<uv>0.1 0.2 0.5 0.6</uv>
+/// 		</subTexture>
+/// 		<subTexture>...</subTexture>
+/// 	</subTextures>
+/// </textureAtlas>
+/// @endcode
+class TextureAtlas : public ResourceObject
+{
+public:
+	TextureAtlas(ResourceManager* manager);
+
+	~TextureAtlas();
+
+	/// Load a texture atlas.
+	ANKI_USE_RESULT Error load(const ResourceFilename& filename);
+
+	TexturePtr getGrTexture() const
+	{
+		return m_tex->getGrTexture();
+	}
+
+	U getWidth() const
+	{
+		return m_size[0];
+	}
+
+	U getHeight() const
+	{
+		return m_size[1];
+	}
+
+	/// Get the UV coordinates of a sub texture.
+	ANKI_USE_RESULT Error getSubTextureInfo(CString name, F32 uv[4]) const;
+
+private:
+	class SubTex
+	{
+	public:
+		CString m_name; ///< Points to TextureAtlas::m_subTexNames.
+		Array<F32, 4> m_uv;
+	};
+
+	TextureResourcePtr m_tex;
+	DynamicArray<char> m_subTexNames;
+	DynamicArray<SubTex> m_subTexes;
+	Array<U32, 2> m_size;
+};
+/// @}
+
+} // end namespace anki

+ 0 - 1
include/anki/scene/BodyComponent.h

@@ -5,7 +5,6 @@
 
 #pragma once
 
-#include <anki/scene/Common.h>
 #include <anki/scene/SceneComponent.h>
 #include <anki/physics/PhysicsBody.h>
 

+ 91 - 0
include/anki/scene/DecalComponent.h

@@ -0,0 +1,91 @@
+// Copyright (C) 2009-2016, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma once
+
+#include <anki/scene/SceneComponent.h>
+#include <anki/resource/TextureAtlas.h>
+#include <anki/collision/Obb.h>
+
+namespace anki
+{
+
+/// @addtogroup scene
+/// @{
+
+/// Decal component. Contains all the relevant info for a deferred decal.
+class DecalComponent : public SceneComponent
+{
+public:
+	static const SceneComponentType CLASS_TYPE = SceneComponentType::DECAL;
+
+	static constexpr F32 FRUSTUM_NEAR_PLANE = 0.1 / 4.0;
+
+	DecalComponent(SceneNode* node)
+		: SceneComponent(CLASS_TYPE, node)
+	{
+	}
+
+	~DecalComponent();
+
+	ANKI_USE_RESULT Error setDiffuseDecal(
+		CString texAtlasFname, CString texAtlasSubtexName, F32 blendFactor)
+	{
+		return setLayer(
+			texAtlasFname, texAtlasSubtexName, blendFactor, LayerType::DIFFUSE);
+	}
+
+	/// Update the internal structures using a world space Obb.
+	void updateShape(const Obb& box)
+	{
+		m_obb = box;
+		m_markedForUpdate = true;
+	}
+
+	/// Implements SceneComponent::update.
+	ANKI_USE_RESULT Error update(SceneNode&, F32, F32, Bool& updated) override
+	{
+		updated = m_markedForUpdate;
+
+		if(m_markedForUpdate)
+		{
+			m_markedForUpdate = false;
+			updateMatrices(m_obb);
+		}
+
+		return ErrorCode::NONE;
+	}
+
+private:
+	enum class LayerType
+	{
+		DIFFUSE,
+		COUNT
+	};
+
+	class Layer
+	{
+	public:
+		TextureAtlasResourcePtr m_atlas;
+		Vec4 m_uv = Vec4(0.0f);
+		F32 m_blendFactor = 0.0f;
+	};
+
+	Array<Layer, U(LayerType::COUNT)> m_layers;
+	Mat4 m_biasProjViewMat;
+	Obb m_obb =
+		Obb(Vec4(0.0f), Mat3x4::getIdentity(), Vec4(1.0f, 1.0f, 1.0f, 0.0f));
+	Bool8 m_markedForUpdate = true;
+
+	ANKI_USE_RESULT Error setLayer(CString texAtlasFname,
+		CString texAtlasSubtexName,
+		F32 blendFactor,
+		LayerType type);
+
+	void updateMatrices(const Obb& box);
+};
+/// @}
+
+} // end namespace anki

+ 30 - 0
include/anki/scene/DecalNode.h

@@ -0,0 +1,30 @@
+// Copyright (C) 2009-2016, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma once
+
+#include <anki/scene/Common.h>
+
+namespace anki
+{
+
+/// @addtogroup scene
+/// @{
+
+/// Node that has a decal component.
+class DecalNode : public SceneNode
+{
+public:
+	DecalNode(SceneGraph* scene);
+
+	~DecalNode();
+
+	ANKI_USE_RESULT Error init(const CString& name);
+
+private:
+};
+/// @}
+
+} // end namespace anki

+ 1 - 0
include/anki/scene/SceneComponent.h

@@ -33,6 +33,7 @@ enum class SceneComponentType : U16
 	REFLECTION_PROBE,
 	REFLECTION_PROXY,
 	OCCLUDER,
+	DECAL,
 	PLAYER_CONTROLLER,
 
 	COUNT,

+ 4 - 60
src/collision/Frustum.cpp

@@ -201,39 +201,11 @@ void PerspectiveFrustum::recalculate()
 	m_pointsL[3] = Vec4(x, -y, z, 0.0); // bot right
 }
 
-//==============================================================================
-void PerspectiveFrustum::calculateProjectionMatrix(
-	F32 fovX, F32 fovY, F32 near, F32 far, Mat4& proj)
-{
-	ANKI_ASSERT(fovX > 0.0 && fovY > 0.0 && near > 0.0 && far > 0.0);
-	F32 g = near - far;
-
-	F32 f = 1.0 / tan(fovY / 2.0); // f = cot(m_fovY/2)
-
-	proj(0, 0) = f * (fovY / fovX); // = f/aspectRatio;
-	proj(0, 1) = 0.0;
-	proj(0, 2) = 0.0;
-	proj(0, 3) = 0.0;
-	proj(1, 0) = 0.0;
-	proj(1, 1) = f;
-	proj(1, 2) = 0.0;
-	proj(1, 3) = 0.0;
-	proj(2, 0) = 0.0;
-	proj(2, 1) = 0.0;
-	proj(2, 2) = (far + near) / g;
-	proj(2, 3) = (2.0 * far * near) / g;
-	proj(3, 0) = 0.0;
-	proj(3, 1) = 0.0;
-	proj(3, 2) = -1.0;
-	proj(3, 3) = 0.0;
-}
-
 //==============================================================================
 Mat4 PerspectiveFrustum::calculateProjectionMatrix() const
 {
-	Mat4 projectionMat;
-	calculateProjectionMatrix(m_fovX, m_fovY, m_near, m_far, projectionMat);
-	return projectionMat;
+	return Mat4::calculatePerspectiveProjectionMatrix(
+		m_fovX, m_fovY, m_near, m_far);
 }
 
 //==============================================================================
@@ -264,36 +236,8 @@ OrthographicFrustum& OrthographicFrustum::operator=(
 //==============================================================================
 Mat4 OrthographicFrustum::calculateProjectionMatrix() const
 {
-	ANKI_ASSERT(m_right != 0.0 && m_left != 0.0 && m_top != 0.0
-		&& m_bottom != 0.0
-		&& m_near != 0.0
-		&& m_far != 0.0);
-	F32 difx = m_right - m_left;
-	F32 dify = m_top - m_bottom;
-	F32 difz = m_far - m_near;
-	F32 tx = -(m_right + m_left) / difx;
-	F32 ty = -(m_top + m_bottom) / dify;
-	F32 tz = -(m_far + m_near) / difz;
-	Mat4 m;
-
-	m(0, 0) = 2.0 / difx;
-	m(0, 1) = 0.0;
-	m(0, 2) = 0.0;
-	m(0, 3) = tx;
-	m(1, 0) = 0.0;
-	m(1, 1) = 2.0 / dify;
-	m(1, 2) = 0.0;
-	m(1, 3) = ty;
-	m(2, 0) = 0.0;
-	m(2, 1) = 0.0;
-	m(2, 2) = -2.0 / difz;
-	m(2, 3) = tz;
-	m(3, 0) = 0.0;
-	m(3, 1) = 0.0;
-	m(3, 2) = 0.0;
-	m(3, 3) = 1.0;
-
-	return m;
+	return Mat4::calculateOrthographicProjectionMatrix(
+		m_right, m_left, m_top, m_bottom, m_near, m_far);
 }
 
 //==============================================================================

+ 1 - 1
src/renderer/LightBin.cpp

@@ -19,7 +19,7 @@ namespace anki
 // Misc                                                                        =
 //==============================================================================
 
-/// This should be the number of light types. For now it's spots & points & 
+/// This should be the number of light types. For now it's spots & points &
 /// probes.
 const U SIZE_IDX_COUNT = 3;
 

+ 2 - 0
src/resource/ResourceManager.cpp

@@ -15,6 +15,7 @@
 #include <anki/resource/ParticleEmitterResource.h>
 #include <anki/resource/TextureResource.h>
 #include <anki/resource/GenericResource.h>
+#include <anki/resource/TextureAtlas.h>
 #include <anki/util/Logger.h>
 #include <anki/misc/ConfigSet.h>
 
@@ -69,6 +70,7 @@ Error ResourceManager::create(ResourceManagerInitInfo& init)
 	ANKI_RESOURCE(DummyRsrc)
 	ANKI_RESOURCE(CollisionResource)
 	ANKI_RESOURCE(GenericResource)
+	ANKI_RESOURCE(TextureAtlas)
 
 #undef ANKI_RESOURCE
 

+ 127 - 0
src/resource/TextureAtlas.cpp

@@ -0,0 +1,127 @@
+// Copyright (C) 2009-2016, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include <anki/resource/TextureAtlas.h>
+#include <anki/resource/ResourceManager.h>
+#include <anki/misc/Xml.h>
+
+namespace anki
+{
+
+//==============================================================================
+TextureAtlas::TextureAtlas(ResourceManager* manager)
+	: ResourceObject(manager)
+{
+}
+
+//==============================================================================
+TextureAtlas::~TextureAtlas()
+{
+	m_subTexes.destroy(getAllocator());
+	m_subTexNames.destroy(getAllocator());
+}
+
+//==============================================================================
+Error TextureAtlas::load(const ResourceFilename& filename)
+{
+	XmlDocument doc;
+	ANKI_CHECK(openFileParseXml(filename, doc));
+
+	XmlElement rootel, el;
+
+	//
+	// <textureAtlas>
+	//
+	ANKI_CHECK(doc.getChildElement("textureAtlas", rootel));
+
+	//
+	// <texture>
+	//
+	ANKI_CHECK(rootel.getChildElement("texture", el));
+	CString texFname;
+	ANKI_CHECK(el.getText(texFname));
+	ANKI_CHECK(getManager().loadResource<TextureResource>(texFname, m_tex));
+
+	//
+	// <subTextures>
+	//
+
+	// Get counts
+	PtrSize namesSize = 0;
+	PtrSize subTexesCount = 0;
+	XmlElement subTexesEl, subTexEl;
+	ANKI_CHECK(rootel.getChildElement("subTextures", subTexesEl));
+	ANKI_CHECK(subTexesEl.getChildElement("subTexture", subTexEl));
+	do
+	{
+		ANKI_CHECK(subTexEl.getChildElement("name", el));
+		CString name;
+		ANKI_CHECK(el.getText(name));
+
+		if(name.getLength() < 1)
+		{
+			ANKI_LOGE("Something wrong with the <name> tag. Probably empty");
+			return ErrorCode::USER_DATA;
+		}
+
+		namesSize += name.getLength() + 1;
+		++subTexesCount;
+
+		ANKI_CHECK(subTexEl.getNextSiblingElement("subTexture", subTexEl));
+	} while(el);
+
+	// Allocate
+	m_subTexNames.create(getAllocator(), namesSize);
+	m_subTexes.create(getAllocator(), subTexesCount);
+
+	// Iterate again and populate
+	subTexesCount = 0;
+	char* names = &m_subTexNames[0];
+	ANKI_CHECK(subTexesEl.getChildElement("subTexture", subTexEl));
+	do
+	{
+		ANKI_CHECK(subTexEl.getChildElement("name", el));
+		CString name;
+		ANKI_CHECK(el.getText(name));
+
+		memcpy(names, &name[0], name.getLength() + 1);
+
+		m_subTexes[subTexesCount].m_name = names;
+
+		Vec4 uv;
+		ANKI_CHECK(el.getVec4(uv));
+		m_subTexes[subTexesCount].m_uv = {{uv[0], uv[1], uv[2], uv[3]}};
+
+		names += name.getLength() + 1;
+		++subTexesCount;
+
+		ANKI_CHECK(subTexEl.getNextSiblingElement("subTexture", subTexEl));
+	} while(el);
+
+	return ErrorCode::NONE;
+}
+
+//==============================================================================
+Error TextureAtlas::getSubTextureInfo(CString name, F32 uv[4]) const
+{
+	for(const SubTex& st : m_subTexes)
+	{
+		if(st.m_name == name)
+		{
+			uv[0] = st.m_uv[0];
+			uv[1] = st.m_uv[1];
+			uv[2] = st.m_uv[2];
+			uv[3] = st.m_uv[3];
+			return ErrorCode::NONE;
+		}
+	}
+
+	ANKI_LOGE("Texture atlas %s doesn't have sub texture named: %s",
+		&getFilename()[0],
+		&name[0]);
+	return ErrorCode::USER_DATA;
+}
+
+} // end namespace anki

+ 71 - 0
src/scene/DecalComponent.cpp

@@ -0,0 +1,71 @@
+// Copyright (C) 2009-2016, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include <anki/scene/DecalComponent.h>
+#include <anki/scene/SceneGraph.h>
+#include <anki/resource/ResourceManager.h>
+
+namespace anki
+{
+
+//==============================================================================
+DecalComponent::~DecalComponent()
+{
+}
+
+//==============================================================================
+Error DecalComponent::setLayer(CString texAtlasFname,
+	CString texAtlasSubtexName,
+	F32 blendFactor,
+	LayerType type)
+{
+	Layer& l = m_layers[type];
+
+	ANKI_CHECK(getSceneGraph().getResourceManager().loadResource(
+		texAtlasFname, l.m_atlas));
+
+	ANKI_CHECK(l.m_atlas->getSubTextureInfo(texAtlasSubtexName, &l.m_uv[0]));
+	l.m_blendFactor = blendFactor;
+
+	return ErrorCode::NONE;
+}
+
+//==============================================================================
+void DecalComponent::updateMatrices(const Obb& box)
+{
+	Mat4 worldTransform(
+		box.getCenter().xyz1(), box.getRotation().getRotationPart(), 1.0f);
+
+	Mat4 viewMat = worldTransform.getInverse();
+
+	const Vec4& extend = box.getExtend();
+	Mat4 projMat = Mat4::calculateOrthographicProjectionMatrix(extend.x(),
+		-extend.x(),
+		extend.y(),
+		-extend.y(),
+		FRUSTUM_NEAR_PLANE,
+		extend.z() * 2.0);
+
+	static const Mat4 biasMat4(0.5,
+		0.0,
+		0.0,
+		0.5,
+		0.0,
+		0.5,
+		0.0,
+		0.5,
+		0.0,
+		0.0,
+		0.5,
+		0.5,
+		0.0,
+		0.0,
+		0.0,
+		1.0);
+
+	m_biasProjViewMat = biasMat4 * projMat * viewMat;
+}
+
+} // end namespace anki

+ 1 - 2
tests/gr/Gr.cpp

@@ -8,7 +8,6 @@
 #include <anki/core/NativeWindow.h>
 #include <anki/core/Config.h>
 #include <anki/util/HighRezTimer.h>
-#include <anki/collision/Frustum.h>
 
 namespace anki
 {
@@ -997,7 +996,7 @@ static void drawOffscreenDrawcalls(GrManager& gr,
 	viewMat.invert();
 
 	Mat4 projMat;
-	PerspectiveFrustum::calculateProjectionMatrix(
+	Mat4::calculatePerspectiveProjectionMatrix(
 		toRad(60.0), toRad(60.0), 0.1f, 100.0f, projMat);
 
 	TransientMemoryInfo transientInfo;