Browse Source

Reflections work

Panagiotis Christopoulos Charitos 10 years ago
parent
commit
2d74a90f83
46 changed files with 400 additions and 207 deletions
  1. 1 3
      include/anki/collision/Obb.h
  2. 3 0
      include/anki/gr/GrManager.h
  3. 1 1
      include/anki/renderer/Sm.h
  4. 2 0
      include/anki/renderer/Sslr.h
  5. 10 1
      include/anki/resource/MeshLoader.h
  6. 6 4
      include/anki/scene/ReflectionProxy.h
  7. 22 14
      include/anki/scene/ReflectionProxyComponent.h
  8. 2 0
      include/anki/scene/SceneComponent.h
  9. 12 2
      include/anki/scene/SceneGraph.h
  10. 3 6
      include/anki/util/Assert.h
  11. 2 1
      shaders/IsLp.frag.glsl
  12. 2 0
      shaders/Pack.glsl
  13. 1 1
      shaders/PpsSslr.frag.glsl
  14. 2 2
      shaders/PpsTmAverageLuminance.comp.glsl
  15. 4 4
      shaders/TilerMinMax.comp.glsl
  16. 11 11
      src/collision/Obb.cpp
  17. 2 2
      src/core/App.cpp
  18. 1 0
      src/core/Config.cpp
  19. 6 0
      src/gr/gl/GrManager.cpp
  20. 2 3
      src/gr/gl/PipelineImpl.cpp
  21. 1 1
      src/gr/gl/ShaderImpl.cpp
  22. 1 0
      src/renderer/Bloom.cpp
  23. 38 31
      src/renderer/Dbg.cpp
  24. 8 5
      src/renderer/DebugDrawer.cpp
  25. 1 0
      src/renderer/Fs.cpp
  26. 48 19
      src/renderer/Ir.cpp
  27. 1 0
      src/renderer/Is.cpp
  28. 1 0
      src/renderer/Lf.cpp
  29. 2 0
      src/renderer/Ms.cpp
  30. 1 0
      src/renderer/Pps.cpp
  31. 1 0
      src/renderer/Sm.cpp
  32. 1 0
      src/renderer/Ssao.cpp
  33. 1 0
      src/renderer/Sslf.cpp
  34. 15 1
      src/renderer/Sslr.cpp
  35. 1 0
      src/renderer/Tm.cpp
  36. 54 20
      src/scene/ReflectionProxy.cpp
  37. 34 14
      src/scene/ReflectionProxyComponent.cpp
  38. 6 0
      src/scene/SceneComponent.cpp
  39. 7 2
      src/scene/SceneGraph.cpp
  40. 4 10
      src/script/Scene.cpp
  41. 2 4
      src/script/Scene.xml
  42. 9 8
      testapp/Main.cpp
  43. 1 1
      thirdparty
  44. 50 24
      tools/scene/Exporter.cpp
  45. 5 6
      tools/scene/Exporter.h
  46. 12 6
      tools/scene/ExporterMesh.cpp

+ 1 - 3
include/anki/collision/Obb.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_COLLISION_OBB_H
-#define ANKI_COLLISION_OBB_H
+#pragma once
 
 #include <anki/collision/ConvexShape.h>
 #include <anki/collision/Aabb.h>
@@ -136,4 +135,3 @@ public:
 
 } // end namespace anki
 
-#endif

+ 3 - 0
include/anki/gr/GrManager.h

@@ -66,6 +66,9 @@ public:
 	/// Swap buffers
 	void swapBuffers();
 
+	/// Wait for all work to finish.
+	void finish();
+
 	/// Create a new graphics object.
 	template<typename T, typename... Args>
 	IntrusivePtr<T> newInstance(Args&&... args);

+ 1 - 1
include/anki/renderer/Sm.h

@@ -100,7 +100,7 @@ private:
 	Bool8 m_enabled;
 
 	/// Enable Poisson for all the levels
-	Bool8 m_poissonEnabled;
+	Bool8 m_poissonEnabled = false;
 
 	/// Shadowmap bilinear filtering for the first level. Better quality
 	Bool8 m_bilinearEnabled;

+ 2 - 0
include/anki/renderer/Sslr.h

@@ -41,6 +41,8 @@ private:
 	FramebufferPtr m_isFb;
 	ShaderResourcePtr m_blitFrag;
 	PipelinePtr m_blitPpline;
+
+	ANKI_USE_RESULT Error initInternal(const ConfigSet& config);
 };
 /// @}
 

+ 10 - 1
include/anki/resource/MeshLoader.h

@@ -7,6 +7,7 @@
 
 #include <anki/resource/Common.h>
 #include <anki/Math.h>
+#include <anki/util/Enum.h>
 
 namespace anki {
 
@@ -62,6 +63,13 @@ public:
 		FormatTransform m_transform = FormatTransform::NONE;
 	};
 
+	enum class Flag: U32
+	{
+		NONE = 0,
+		QUADS = 1 << 0
+	};
+	ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(Flag, friend);
+
 	struct Header
 	{
 		Array<U8, 8> m_magic; ///< Magic word.
@@ -88,8 +96,9 @@ public:
 
 	static_assert(sizeof(Header) == 128, "Check size of struct");
 
-	struct SubMesh
+	class SubMesh
 	{
+	public:
 		U32 m_firstIndex = 0;
 		U32 m_indicesCount = 0;
 	};

+ 6 - 4
include/anki/scene/ReflectionProxy.h

@@ -25,15 +25,17 @@ public:
 	{}
 
 	~ReflectionProxy()
-	{}
+	{
+		m_quadsLSpace.destroy(getSceneAllocator());
+	}
 
 	/// Create the proxy. The points form a quad and they should be in local
 	/// space.
-	ANKI_USE_RESULT Error create(const CString& name, F32 width, F32 height,
-		F32 maxDistance);
+	ANKI_USE_RESULT Error create(const CString& name,
+		const CString& proxyMesh);
 
 private:
-	Array<Vec4, 4> m_quadLSpace; ///< Quad verts.
+	DArray<Array<Vec4, 4>> m_quadsLSpace; ///< Quads in local space.
 	Obb m_boxLSpace;
 	Obb m_boxWSpace;
 

+ 22 - 14
include/anki/scene/ReflectionProxyComponent.h

@@ -17,37 +17,45 @@ namespace anki {
 class ReflectionProxyComponent: public SceneComponent
 {
 public:
-	ReflectionProxyComponent(SceneNode* node)
-		: SceneComponent(SceneComponent::Type::REFLECTION_PROXY, node)
-	{}
+	/// Reflection proxy face. One out of many
+	class Face
+	{
+	public:
+		Array<Vec4, 4> m_vertices;
+		Plane m_plane;
+	};
 
-	static Bool classof(const SceneComponent& c)
+	ReflectionProxyComponent(SceneNode* node, U faceCount)
+		: SceneComponent(SceneComponent::Type::REFLECTION_PROXY, node)
 	{
-		return c.getType() == Type::REFLECTION_PROXY;
+		ANKI_ASSERT(faceCount > 0);
+		m_faces.create(getAllocator(), faceCount);
 	}
 
-	void setVertex(U idx, const Vec4& v)
+	~ReflectionProxyComponent()
 	{
-		m_quad[idx] = v;
-		m_dirty = true;
+		m_faces.destroy(getAllocator());
 	}
 
-	const Array<Vec4, 4>& getVertices() const
+	static Bool classof(const SceneComponent& c)
 	{
-		return m_quad;
+		return c.getType() == Type::REFLECTION_PROXY;
 	}
 
-	const Plane& getPlane() const
+	void setQuad(U index, const Vec4& a, const Vec4& b, const Vec4& c,
+		const Vec4& d);
+
+	const DArray<Face>& getFaces() const
 	{
-		return m_plane;
+		ANKI_ASSERT(m_faces.getSize() > 0);
+		return m_faces;
 	}
 
 	ANKI_USE_RESULT Error update(SceneNode& node, F32 prevTime, F32 crntTime,
 		Bool& updated) final;
 
 private:
-	Array<Vec4, 4> m_quad; ///< Quad verts.
-	Plane m_plane; ///< Caches some values.
+	DArray<Face> m_faces; ///< Quads.
 	Bool8 m_dirty = true;
 };
 /// @}

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

@@ -101,6 +101,8 @@ public:
 		return *m_node;
 	}
 
+	SceneAllocator<U8> getAllocator() const;
+
 	SceneGraph& getSceneGraph();
 	const SceneGraph& getSceneGraph() const;
 

+ 12 - 2
include/anki/scene/SceneGraph.h

@@ -24,6 +24,7 @@ class ResourceManager;
 class Camera;
 class Input;
 class SectorGroup;
+class ConfigSet;
 
 /// @addtogroup scene
 /// @{
@@ -38,14 +39,15 @@ public:
 
 	~SceneGraph();
 
-	ANKI_USE_RESULT Error create(
+	ANKI_USE_RESULT Error init(
 		AllocAlignedCallback allocCb,
 		void* allocCbData,
 		U32 frameAllocatorSize,
 		ThreadPool* threadpool,
 		ResourceManager* resources,
 		Input* input,
-		const Timestamp* globalTimestamp);
+		const Timestamp* globalTimestamp,
+		const ConfigSet& config);
 
 	Timestamp getGlobalTimestamp() const
 	{
@@ -187,6 +189,12 @@ anki_internal:
 		return *m_sectors;
 	}
 
+	F32 getMaxReflectionProxyDistance() const
+	{
+		ANKI_ASSERT(m_maxReflectionProxyDistance > 0.0);
+		return m_maxReflectionProxyDistance;
+	}
+
 private:
 	const Timestamp* m_globalTimestamp = nullptr;
 	Timestamp m_timestamp = 0; ///< Cached timestamp
@@ -215,6 +223,8 @@ private:
 
 	Atomic<U32> m_objectsMarkedForDeletionCount;
 
+	F32 m_maxReflectionProxyDistance = 0.0;
+
 	/// Put a node in the appropriate containers
 	ANKI_USE_RESULT Error registerNode(SceneNode* node);
 	void unregisterNode(SceneNode* node);

+ 3 - 6
include/anki/util/Assert.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_UTIL_ASSERT_H
-#define ANKI_UTIL_ASSERT_H
+#pragma once
 
 #include <anki/Config.h>
 
@@ -17,9 +16,8 @@
 
 namespace anki {
 
-/// Its separate so we will not include iostream
-void akassert(const char* exprTxt, const char* file,
-	int line, const char* func);
+void akassert(const char* exprTxt, const char* file, int line,
+	const char* func);
 
 } // end namespace
 
@@ -33,4 +31,3 @@ void akassert(const char* exprTxt, const char* file,
 
 #endif
 
-#endif

+ 2 - 1
shaders/IsLp.frag.glsl

@@ -191,7 +191,8 @@ void main()
 	{
 		out_color += vec3(1.0, 0.0, 0.0);
 	}
-
+#if IR == 1
 	out_color = out_color * 0.5 + readReflection(fragPos, normal) *0.5;
 #endif
+#endif
 }

+ 2 - 0
shaders/Pack.glsl

@@ -6,6 +6,8 @@
 #ifndef ANKI_SHADERS_PACK_GLSL
 #define ANKI_SHADERS_PACK_GLSL
 
+#pragma anki include "shaders/Common.glsl"
+
 /// Pack 3D normal to 2D vector
 /// See the clean code in comments in revision < r467
 vec2 packNormal(in vec3 normal)

+ 1 - 1
shaders/PpsSslr.frag.glsl

@@ -109,7 +109,7 @@ void main()
 
 	steps = min(steps, 300.0);
 
-	for(float i = 10.0; i < steps; i += 1.5)
+	for(float i = 0.0; i < steps; i += 1.0)
 	{
 		vec2 ndc = pp0 + dir * (i * stepInc);
 

+ 2 - 2
shaders/PpsTmAverageLuminance.comp.glsl

@@ -45,8 +45,8 @@ void main()
 	{
 		for(uint x = 0; x < PIXEL_READ_X; ++x)
 		{
-			vec3 color = texelFetchOffset(
-				u_isRt, ivec2(xStart, yStart), IS_RT_MIPMAP, ivec2(x, y)).rgb;
+			vec3 color = texelFetch(
+				u_isRt, ivec2(xStart, yStart) + ivec2(x, y), IS_RT_MIPMAP).rgb;
 			float lum = computeLuminance(color);
 			//avgLum += log(lum);
 			avgLum += lum / float(MIPMAP_WIDTH * MIPMAP_HEIGHT);

+ 4 - 4
shaders/TilerMinMax.comp.glsl

@@ -24,8 +24,8 @@ layout(std430, binding = 0) writeonly buffer _blk
 };
 
 layout(
-	local_size_x = WORKGROUP_SIZE_X, 
-	local_size_y = WORKGROUP_SIZE_Y, 
+	local_size_x = WORKGROUP_SIZE_X,
+	local_size_y = WORKGROUP_SIZE_Y,
 	local_size_z = 1) in;
 
 shared uint g_minDepth;
@@ -42,7 +42,7 @@ void main()
 	barrier();
 
 	// Get max/min depth
-	ivec2 coord = 
+	ivec2 coord =
 		ivec2(gl_GlobalInvocationID.xy) * ivec2(PIXEL_READ_X, PIXEL_READ_Y);
 
 	float mind = 10.0;
@@ -51,7 +51,7 @@ void main()
 	{
 		for(uint x = 0; x < PIXEL_READ_X; ++x)
 		{
-			float depth = texelFetchOffset(u_depthMap, coord, 0, ivec2(x, y)).r;
+			float depth = texelFetch(u_depthMap, coord + ivec2(x, y), 0).r;
 			mind = min(mind, depth);
 			maxd = max(maxd, depth);
 		}

+ 11 - 11
src/collision/Obb.cpp

@@ -11,27 +11,27 @@ namespace anki {
 
 //==============================================================================
 Obb::Obb()
-:	Base(Type::OBB),
-	m_center(Vec4(0.0)),
-	m_rotation(Mat3x4::getIdentity()),
-	m_transposedRotation(Mat3x4::getIdentity()),
-	m_extend(Vec3(getEpsilon<F32>()), 0.0)
+	: Base(Type::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(Type::OBB)
+	: Base(Type::OBB)
 {
 	operator=(b);
 }
 
 //==============================================================================
 Obb::Obb(const Vec4& center, const Mat3x4& rotation, const Vec4& extend)
-:	Base(Type::OBB),
-	m_center(center),
-	m_rotation(rotation),
-	m_transposedRotation(rotation),
-	m_extend(extend)
+	: Base(Type::OBB)
+	, m_center(center)
+	, m_rotation(rotation)
+	, m_transposedRotation(rotation)
+	, m_extend(extend)
 {
 	m_transposedRotation.transposeRotationPart();
 }

+ 2 - 2
src/core/App.cpp

@@ -292,9 +292,9 @@ Error App::createInternal(const ConfigSet& config_,
 	// Scene
 	m_scene = m_heapAlloc.newInstance<SceneGraph>();
 
-	ANKI_CHECK(m_scene->create(m_allocCb, m_allocCbData,
+	ANKI_CHECK(m_scene->init(m_allocCb, m_allocCbData,
 		config.getNumber("sceneFrameAllocatorSize"), m_threadpool, m_resources,
-		m_input, &m_globalTimestamp));
+		m_input, &m_globalTimestamp, config));
 
 	// Script
 	m_script = m_heapAlloc.newInstance<ScriptManager>();

+ 1 - 0
src/core/Config.cpp

@@ -78,6 +78,7 @@ Config::Config()
 	newOption("tessellation", true);
 	newOption("sceneFrameAllocatorSize", 1024 * 1024);
 	newOption("clusterSizeZ", 32);
+	newOption("imageReflectionMaxDistance", 30.0);
 
 	//
 	// GR

+ 6 - 0
src/gr/gl/GrManager.cpp

@@ -60,4 +60,10 @@ void* GrManager::allocateFrameHostVisibleMemory(PtrSize size, BufferUsage usage,
 	return data;
 }
 
+//==============================================================================
+void GrManager::finish()
+{
+	m_impl->getRenderingThread().syncClientServer();
+}
+
 } // end namespace anki

+ 2 - 3
src/gr/gl/PipelineImpl.cpp

@@ -202,12 +202,11 @@ Error PipelineImpl::createGlPipeline()
 	{
 		GLint infoLen = 0;
 		GLint charsWritten = 0;
-		DArray<char> infoLogTxt;
+		DArrayAuto<char> infoLogTxt(getAllocator());
 
 		glGetProgramPipelineiv(m_glName, GL_INFO_LOG_LENGTH, &infoLen);
 
-		auto alloc = getAllocator();
-		infoLogTxt.create(alloc, infoLen + 1);
+		infoLogTxt.create(infoLen + 1);
 
 		glGetProgramPipelineInfoLog(
 			m_glName, infoLen, &charsWritten, &infoLogTxt[0]);

+ 1 - 1
src/gr/gl/ShaderImpl.cpp

@@ -116,7 +116,7 @@ Error ShaderImpl::create(ShaderType type, const CString& source)
 
 		File file;
 		ANKI_CHECK(file.open(fname.toCString(), File::OpenFlag::WRITE));
-		ANKI_CHECK(file.writeText("%s", &fname[0]));
+		ANKI_CHECK(file.writeText("%s", &fullSrc[0]));
 	}
 #endif
 

+ 1 - 0
src/renderer/Bloom.cpp

@@ -145,6 +145,7 @@ Error Bloom::initInternal(const ConfigSet& config)
 	m_parameterUpdateTimestamp = getGlobalTimestamp();
 	m_commonUboUpdateTimestamp = getGlobalTimestamp();
 
+	getGrManager().finish();
 	return ErrorCode::NONE;
 }
 

+ 38 - 31
src/renderer/Dbg.cpp

@@ -71,6 +71,7 @@ Error Dbg::init(const ConfigSet& initializer)
 
 	m_sceneDrawer = getAllocator().newInstance<SceneDebugDrawer>(m_drawer);
 
+	getGrManager().finish();
 	return ErrorCode::NONE;
 }
 
@@ -152,17 +153,17 @@ Error Dbg::run(CommandBufferPtr& cmdb)
 	}
 #endif
 
-#if 0
+#if 1
 	{
 		CollisionDebugDrawer cd(m_drawer);
 
 		Array<Vec3, 4> poly;
 		poly[0] = Vec3(0.0, 0.0, 0.0);
 		poly[1] = Vec3(2.5, 0.0, 0.0);
-		poly[2] = Vec3(2.5, 3.9, 0.0);
-		poly[3] = Vec3(0.0, 3.9, 0.0);
+		poly[2] = Vec3(2.0, 4.9, 0.0);
+		poly[3] = Vec3(0.5, 3.9, 0.0);
 
-		Mat4 trf(Vec4(1.2, 14.0, 1.1, 1.0), Mat3(Euler(toRad(10.0), toRad(35.0),
+		Mat4 trf(Vec4(1.2, 14.0, 1.1, 1.0), Mat3(Euler(toRad(-120.0), toRad(35.0),
 			toRad(85.0))), 1.0);
 
 		Array<Vec3, 4> polyw;
@@ -173,43 +174,49 @@ Error Dbg::run(CommandBufferPtr& cmdb)
 
 		m_drawer->setModelMatrix(Mat4::getIdentity());
 		m_drawer->drawLine(polyw[0], polyw[1], Vec4(1.0));
-		m_drawer->drawLine(polyw[1], polyw[2], Vec4(0.9));
-		m_drawer->drawLine(polyw[2], polyw[3], Vec4(0.8));
-		m_drawer->drawLine(polyw[3], polyw[0], Vec4(0.7));
+		m_drawer->drawLine(polyw[1], polyw[2], Vec4(0.8));
+		m_drawer->drawLine(polyw[2], polyw[3], Vec4(0.6));
+		m_drawer->drawLine(polyw[3], polyw[0], Vec4(0.4));
 
-		SceneNode& node = scene.findSceneNode("Cube.001Material_003-materialnone1");
-		MoveComponent& movc = node.getComponent<MoveComponent>();
 
-		Vec3 p0(movc.getWorldTransform().getOrigin().xyz());
-		Vec3 r(-movc.getWorldTransform().getRotation().getColumn(2).xyz());
-		r.normalize();
 
-		m_drawer->drawLine(p0, p0 + r * 25.0, Vec4(1.0, 0.0, 0.0, 1.0));
+		Vec3 edge0 = polyw[2] - polyw[1];
+		Vec3 edge1 = polyw[3] - polyw[2];
 
-		Plane plane(polyw[0], polyw[1], polyw[2]);
-		plane.accept(cd);
-		m_drawer->setModelMatrix(Mat4::getIdentity());
+		Vec3 xAxis = edge0;
+		xAxis.normalize();
+		Vec3 zAxis = edge0.cross(edge1);
+		zAxis.normalize();
+		Vec3 yAxis = zAxis.cross(xAxis);
+
+		Mat3 rot;
+		rot.setColumns(xAxis.xyz(), yAxis.xyz(), zAxis.xyz());
 
-		Vec3 n = plane.getNormal().xyz();
-		F32 O = plane.getOffset();
-		Vec4 i;
-		Bool collides = plane.intersectRay(p0.xyz0(), r.xyz0(), i);
+		Mat3 invRot = rot.getInverse();
 
-		if(collides)
+		Array<Vec3, 8> polyl;
+		for(U i = 0; i < 4; ++i)
 		{
-			Vec4 dots;
-			dots[0] = n.cross(polyw[1] - polyw[0]).dot(i.xyz() - polyw[0]);
-			dots[1] = n.cross(polyw[2] - polyw[1]).dot(i.xyz() - polyw[1]);
-			dots[2] = n.cross(polyw[3] - polyw[2]).dot(i.xyz() - polyw[2]);
-			dots[3] = n.cross(polyw[0] - polyw[3]).dot(i.xyz() - polyw[3]);
-
-			if(dots > Vec4(0.0))
-				m_drawer->drawLine(p0, i.xyz(), Vec4(0.0, 1.0, 0.0, 1.0));
+			polyl[i] = invRot * polyw[i];
 		}
-		else
+
+		m_drawer->drawLine(polyl[0], polyl[1], Vec4(1.0));
+		m_drawer->drawLine(polyl[1], polyl[2], Vec4(0.8));
+		m_drawer->drawLine(polyl[2], polyl[3], Vec4(0.6));
+		m_drawer->drawLine(polyl[3], polyl[0], Vec4(0.4));
+
+
+		for(U i = 4; i < 8; ++i)
 		{
-			//m_drawer->drawLine(p0, i.xyz(), Vec4(0.0, 0.0, 1.0, 1.0));
+			polyl[i] = polyl[i - 4] + Vec3(0.0, 0.0, 10.0);
 		}
+
+		Obb obb;
+		obb.setFromPointCloud(&polyl[0], 8, sizeof(Vec3), sizeof(polyl));
+
+		obb.transform(Transform(Vec4(0.0), Mat3x4(rot), 1.0));
+
+		obb.accept(cd);
 	}
 #endif
 

+ 8 - 5
src/renderer/DebugDrawer.cpp

@@ -621,12 +621,15 @@ void SceneDebugDrawer::draw(const ReflectionProxyComponent& proxy) const
 {
 	m_dbg->setModelMatrix(Mat4::getIdentity());
 	m_dbg->begin(PrimitiveTopology::LINES);
-	for(U i = 0; i < 3; ++i)
+	for(const auto& face : proxy.getFaces())
 	{
-		m_dbg->setColor(Vec3(0.4, 0.4, 1.0));
-		m_dbg->pushBackVertex(proxy.getVertices()[i].xyz());
-		m_dbg->setColor(Vec3(1.0, 0.4, 0.4));
-		m_dbg->pushBackVertex(proxy.getVertices()[i + 1].xyz());
+		for(U i = 0; i < 3; ++i)
+		{
+			m_dbg->setColor(Vec3(0.4, 0.4, 1.0));
+			m_dbg->pushBackVertex(face.m_vertices[i].xyz());
+			m_dbg->setColor(Vec3(1.0, 0.4, 0.4));
+			m_dbg->pushBackVertex(face.m_vertices[i + 1].xyz());
+		}
 	}
 	m_dbg->end();
 }

+ 1 - 0
src/renderer/Fs.cpp

@@ -47,6 +47,7 @@ Error Fs::init(const ConfigSet&)
 		m_globalResources = getGrManager().newInstance<ResourceGroup>(init);
 	}
 
+	getGrManager().finish();
 	return ErrorCode::NONE;
 }
 

+ 48 - 19
src/renderer/Ir.cpp

@@ -102,6 +102,7 @@ Error Ir::init(const ConfigSet& initializer)
 
 	m_cubemapArr = getGrManager().newInstance<Texture>(texinit);
 
+	getGrManager().finish();
 	return ErrorCode::NONE;
 }
 
@@ -111,17 +112,37 @@ Error Ir::run(CommandBufferPtr cmdb)
 	FrustumComponent& frc = m_r->getActiveFrustumComponent();
 	VisibilityTestResults& visRez = frc.getVisibilityTestResults();
 
+	const VisibleNode* it;
+	const VisibleNode* end;
+
+	//
 	// Do the proxies
+	//
+
+	// Count them
+	U quadCount = 0;
+	it = visRez.getReflectionProxiesBegin();
+	end = visRez.getReflectionProxiesEnd();
+	while(it != end)
+	{
+		const ReflectionProxyComponent& proxyc =
+			it->m_node->getComponent<ReflectionProxyComponent>();
+
+		quadCount += proxyc.getFaces().getSize();
+		++it;
+	}
+
+	// Allocate
 	void* data = getGrManager().allocateFrameHostVisibleMemory(
-		sizeof(ShaderReflectionProxy) * visRez.getReflectionProxyCount()
+		sizeof(ShaderReflectionProxy) * quadCount
 		+ sizeof(UVec4), BufferUsage::STORAGE, m_proxiesToken);
 
 	UVec4* counts = reinterpret_cast<UVec4*>(data);
-	counts->x() = visRez.getReflectionProxyCount();
+	counts->x() = quadCount;
 	counts->y() = visRez.getReflectionProbeCount();
 
-	const VisibleNode* it = visRez.getReflectionProxiesBegin();
-	const VisibleNode* end = visRez.getReflectionProxiesEnd();
+	it = visRez.getReflectionProxiesBegin();
+	end = visRez.getReflectionProxiesEnd();
 	ShaderReflectionProxy* proxies = reinterpret_cast<ShaderReflectionProxy*>(
 		counts + 1);
 
@@ -129,30 +150,38 @@ Error Ir::run(CommandBufferPtr cmdb)
 	{
 		const ReflectionProxyComponent& proxyc =
 			it->m_node->getComponent<ReflectionProxyComponent>();
-		Plane plane = proxyc.getPlane();
-		plane.transform(Transform(frc.getViewMatrix()));
+		for(const auto& face : proxyc.getFaces())
+		{
+			Plane plane = face.m_plane;
+			plane.transform(Transform(frc.getViewMatrix()));
 
-		proxies->m_plane = Vec4(plane.getNormal().xyz(), plane.getOffset());
-		proxies->m_negPlane = Vec4(-plane.getNormal().xyz(), plane.getOffset());
+			proxies->m_plane =
+				Vec4(plane.getNormal().xyz(), plane.getOffset());
+			proxies->m_negPlane =
+				Vec4(-plane.getNormal().xyz(), plane.getOffset());
 
-		for(U i = 0; i < 4; ++i)
-		{
-			proxies->m_quadPoints[i] =
-				frc.getViewMatrix() * proxyc.getVertices()[i].xyz1();
-		}
+			for(U i = 0; i < 4; ++i)
+			{
+				proxies->m_quadPoints[i] =
+					frc.getViewMatrix() * face.m_vertices[i].xyz1();
+			}
 
-		for(U i = 0; i < 4; ++i)
-		{
-			U next = (i < 3) ? (i + 1) : 0;
-			proxies->m_edgeCrossProd[i] = plane.getNormal().cross(
-				proxies->m_quadPoints[next] - proxies->m_quadPoints[i]);
+			for(U i = 0; i < 4; ++i)
+			{
+				U next = (i < 3) ? (i + 1) : 0;
+				proxies->m_edgeCrossProd[i] = plane.getNormal().cross(
+					proxies->m_quadPoints[next] - proxies->m_quadPoints[i]);
+			}
+
+			++proxies;
 		}
 
 		++it;
-		++proxies;
 	}
 
+	//
 	// Do the probes
+	//
 	it = visRez.getReflectionProbesBegin();
 	end = visRez.getReflectionProbesEnd();
 

+ 1 - 0
src/renderer/Is.cpp

@@ -330,6 +330,7 @@ Error Is::initInternal(const ConfigSet& config)
 	m_barrier = getAllocator().newInstance<Barrier>(
 		threadPool.getThreadsCount());
 
+	getGrManager().finish();
 	return ErrorCode::NONE;
 }
 

+ 1 - 0
src/renderer/Lf.cpp

@@ -147,6 +147,7 @@ Error Lf::initInternal(const ConfigSet& config)
 	ANKI_CHECK(initSprite(config));
 	ANKI_CHECK(initOcclusion(config));
 
+	getGrManager().finish();
 	return ErrorCode::NONE;
 }
 

+ 2 - 0
src/renderer/Ms.cpp

@@ -97,6 +97,8 @@ Error Ms::initInternal(const ConfigSet& initializer)
 	m_secondLevelCmdbs.create(
 		getAllocator(), m_r->getThreadPool().getThreadsCount());
 
+	getGrManager().finish();
+
 	return ErrorCode::NONE;
 }
 

+ 1 - 0
src/renderer/Pps.cpp

@@ -146,6 +146,7 @@ Error Pps::initInternal(const ConfigSet& config)
 
 	m_rcGroup = getGrManager().newInstance<ResourceGroup>(rcInit);
 
+	getGrManager().finish();
 	return ErrorCode::NONE;
 }
 

+ 1 - 0
src/renderer/Sm.cpp

@@ -98,6 +98,7 @@ Error Sm::init(const ConfigSet& config)
 		++layer;
 	}
 
+	getGrManager().finish();
 	return ErrorCode::NONE;
 }
 

+ 1 - 0
src/renderer/Ssao.cpp

@@ -244,6 +244,7 @@ Error Ssao::initInternal(const ConfigSet& config)
 	rcinit.m_textures[0].m_texture = m_hblurRt;
 	m_vblurRc = getGrManager().newInstance<ResourceGroup>(rcinit);
 
+	getGrManager().finish();
 	return ErrorCode::NONE;
 }
 

+ 1 - 0
src/renderer/Sslf.cpp

@@ -75,6 +75,7 @@ Error Sslf::initInternal(const ConfigSet& config)
 
 	m_rcGroup = getGrManager().newInstance<ResourceGroup>(rcInit);
 
+	getGrManager().finish();
 	return ErrorCode::NONE;
 }
 

+ 15 - 1
src/renderer/Sslr.cpp

@@ -14,7 +14,7 @@
 namespace anki {
 
 //==============================================================================
-Error Sslr::init(const ConfigSet& config)
+Error Sslr::initInternal(const ConfigSet& config)
 {
 	m_enabled = config.getNumber("pps.sslr.enabled");
 
@@ -97,9 +97,23 @@ Error Sslr::init(const ConfigSet& config)
 		AttachmentLoadOperation::LOAD;
 	m_isFb = getGrManager().newInstance<Framebuffer>(fbInit);
 
+	getGrManager().finish();
 	return ErrorCode::NONE;
 }
 
+//==============================================================================
+Error Sslr::init(const ConfigSet& config)
+{
+	Error err = initInternal(config);
+
+	if(err)
+	{
+		ANKI_LOGE("Failed to init PPS SSLR");
+	}
+
+	return err;
+}
+
 //==============================================================================
 void Sslr::run(CommandBufferPtr& cmdBuff)
 {

+ 1 - 0
src/renderer/Tm.cpp

@@ -52,6 +52,7 @@ Error Tm::create(const ConfigSet& initializer)
 
 	m_rcGroup = getGrManager().newInstance<ResourceGroup>(rcinit);
 
+	getGrManager().finish();
 	return ErrorCode::NONE;
 }
 

+ 54 - 20
src/scene/ReflectionProxy.cpp

@@ -7,6 +7,7 @@
 #include <anki/scene/ReflectionProxyComponent.h>
 #include <anki/scene/MoveComponent.h>
 #include <anki/scene/SpatialComponent.h>
+#include <anki/resource/MeshLoader.h>
 
 namespace anki {
 
@@ -43,8 +44,7 @@ public:
 //==============================================================================
 
 //==============================================================================
-Error ReflectionProxy::create(const CString& name, F32 width, F32 height,
-	F32 maxDistance)
+Error ReflectionProxy::create(const CString& name, const CString& proxyMesh)
 {
 	ANKI_CHECK(SceneNode::create(name));
 
@@ -57,25 +57,51 @@ Error ReflectionProxy::create(const CString& name, F32 width, F32 height,
 		newInstance<ReflectionProxyMoveFeedbackComponent>(this);
 	addComponent(comp, true);
 
+	// Load vertices
+	MeshLoader loader(&getResourceManager());
+	ANKI_CHECK(loader.load(proxyMesh));
+
+	if((loader.getHeader().m_flags & MeshLoader::Flag::QUADS)
+		== MeshLoader::Flag::NONE)
+	{
+		ANKI_LOGE("Expecting quad mesh");
+		return ErrorCode::USER_DATA;
+	}
+
+	const U indexCount = loader.getHeader().m_totalIndicesCount;
+	const U quadCount = indexCount / 4;
+	m_quadsLSpace.create(getSceneAllocator(), quadCount);
+
+	const U8* buff = loader.getVertexData();
+	const U8* buffEnd = loader.getVertexData() + loader.getVertexDataSize();
+	SArray<const U16> indices(
+		reinterpret_cast<const U16*>(loader.getIndexData()), indexCount);
+	for(U i = 0; i < quadCount; ++i)
+	{
+		Array<Vec4, 4>& quad = m_quadsLSpace[i];
+
+		for(U j = 0; j < 4; ++j)
+		{
+			U index = indices[i * 4 + j];
+
+			const Vec3* vert = reinterpret_cast<const Vec3*>(
+				buff + loader.getVertexSize() * index);
+			ANKI_ASSERT(vert + 1 < reinterpret_cast<const Vec3*>(buffEnd));
+			(void)buffEnd;
+
+			quad[j] = vert->xyz0();
+		}
+	}
+
 	// Proxy component
-	ReflectionProxyComponent* proxyc =
-		getSceneAllocator().newInstance<ReflectionProxyComponent>(this);
-	m_quadLSpace[0] = Vec4(-width / 2.0, -height / 2.0, 0.0, 0.0);
-	m_quadLSpace[1] = Vec4(width / 2.0, -height / 2.0, 0.0, 0.0);
-	m_quadLSpace[2] = Vec4(width / 2.0, height / 2.0, 0.0, 0.0);
-	m_quadLSpace[3] = Vec4(-width / 2.0, height / 2.0, 0.0, 0.0);
-	proxyc->setVertex(0, m_quadLSpace[0]);
-	proxyc->setVertex(1, m_quadLSpace[1]);
-	proxyc->setVertex(2, m_quadLSpace[2]);
-	proxyc->setVertex(3, m_quadLSpace[3]);
-
-	addComponent(proxyc, true);
+	comp = getSceneAllocator().newInstance<ReflectionProxyComponent>(this,
+		quadCount);
+	addComponent(comp, true);
 
 	// Spatial component
-	m_boxLSpace.setCenter(Vec4(0.0, 0.0, maxDistance / 2.0, 0.0));
-	m_boxLSpace.setRotation(Mat3x4::getIdentity());
-	m_boxLSpace.setExtend(Vec4(width / 2.0 + maxDistance,
-		height / 2.0 + maxDistance, maxDistance / 2.0, 0.0));
+	m_boxLSpace.setFromPointCloud(loader.getVertexData(),
+		loader.getHeader().m_totalVerticesCount,
+		loader.getVertexSize(), loader.getVertexDataSize());
 
 	m_boxWSpace = m_boxLSpace;
 
@@ -93,15 +119,23 @@ void ReflectionProxy::onMoveUpdate(const MoveComponent& move)
 
 	// Update proxy comp
 	ReflectionProxyComponent& proxyc = getComponent<ReflectionProxyComponent>();
-	for(U i = 0; i < 4; ++i)
+	for(U i = 0; i < m_quadsLSpace.getSize(); ++i)
 	{
-		proxyc.setVertex(i, trf.transform(m_quadLSpace[i]));
+		Array<Vec4, 4> quadWSpace;
+		for(U j = 0; j < 4; ++j)
+		{
+			quadWSpace[j] = trf.transform(m_quadsLSpace[i][j]);
+		}
+
+		proxyc.setQuad(i, quadWSpace[0], quadWSpace[1], quadWSpace[2],
+			quadWSpace[3]);
 	}
 
 	// Update spatial
 	m_boxWSpace = m_boxLSpace;
 	m_boxWSpace.transform(trf);
 	SpatialComponent& spatial = getComponent<SpatialComponent>();
+	spatial.setSpatialOrigin(move.getWorldTransform().getOrigin());
 	spatial.markForUpdate();
 }
 

+ 34 - 14
src/scene/ReflectionProxyComponent.cpp

@@ -7,6 +7,18 @@
 
 namespace anki {
 
+//==============================================================================
+void ReflectionProxyComponent::setQuad(U index, const Vec4& a, const Vec4& b,
+	const Vec4& c, const Vec4& d)
+{
+	m_dirty = true;
+
+	m_faces[index].m_vertices[0] = a;
+	m_faces[index].m_vertices[1] = b;
+	m_faces[index].m_vertices[2] = c;
+	m_faces[index].m_vertices[3] = d;
+}
+
 //==============================================================================
 Error ReflectionProxyComponent::update(SceneNode& node, F32 prevTime,
 	F32 crntTime, Bool& updated)
@@ -16,23 +28,31 @@ Error ReflectionProxyComponent::update(SceneNode& node, F32 prevTime,
 		m_dirty = false;
 		updated = true;
 
-		// Update the plane
-		m_plane.setFrom3Points(m_quad[0], m_quad[1], m_quad[2]);
+		for(Face& face : m_faces)
+		{
+			const Vec4& a = face.m_vertices[0];
+			const Vec4& b = face.m_vertices[1];
+			const Vec4& c = face.m_vertices[2];
+			const Vec4& d = face.m_vertices[3];
+			(void)d;
+
+			// Update the plane
+			face.m_plane.setFrom3Points(a, b, c);
 
 #if ANKI_ASSERTIONS == 1
-		// Make sure that all points are co-planar
-		Vec4 n0 = (m_quad[1] - m_quad[0]).cross(m_quad[2] - m_quad[1]);
-		Vec4 n1 = (m_quad[2] - m_quad[1]).cross(m_quad[3] - m_quad[2]);
-		Vec4 n2 = (m_quad[3] - m_quad[2]).cross(m_quad[0] - m_quad[3]);
-		n0.normalize();
-		n1.normalize();
-		n2.normalize();
-		ANKI_ASSERT(isZero(n0.dot(n1) - n1.dot(n2))
-			&& isZero(n0.dot(n2) - n0.dot(n1)));
-#endif
+			// Make sure that all points are co-planar
+			Vec4 n0 = (b - a).cross(c - b);
+			Vec4 n1 = (c - b).cross(d - c);
+			Vec4 n2 = (d - c).cross(a - d);
+			n0.normalize();
+			n1.normalize();
+			n2.normalize();
 
-		updated = false;
-		return ErrorCode::NONE;
+			F32 dota = abs(n0.dot(n1) - n1.dot(n2));
+			F32 dotb = abs(n0.dot(n2) - n0.dot(n1));
+			ANKI_ASSERT(dota < 0.001 && dotb < 0.001);
+#endif
+		}
 	}
 	else
 	{

+ 6 - 0
src/scene/SceneComponent.cpp

@@ -44,4 +44,10 @@ const SceneGraph& SceneComponent::getSceneGraph() const
 	return m_node->getSceneGraph();
 }
 
+//==============================================================================
+SceneAllocator<U8> SceneComponent::getAllocator() const
+{
+	return m_node->getSceneAllocator();
+}
+
 } // end namespace anki

+ 7 - 2
src/scene/SceneGraph.cpp

@@ -12,6 +12,7 @@
 #include <anki/resource/ResourceManager.h>
 #include <anki/renderer/MainRenderer.h>
 #include <anki/renderer/Renderer.h>
+#include <anki/misc/ConfigSet.h>
 
 namespace anki {
 
@@ -146,14 +147,15 @@ SceneGraph::~SceneGraph()
 }
 
 //==============================================================================
-Error SceneGraph::create(
+Error SceneGraph::init(
 	AllocAlignedCallback allocCb,
 	void* allocCbData,
 	U32 frameAllocatorSize,
 	ThreadPool* threadpool,
 	ResourceManager* resources,
 	Input* input,
-	const Timestamp* globalTimestamp)
+	const Timestamp* globalTimestamp,
+	const ConfigSet& config)
 {
 	Error err = ErrorCode::NONE;
 
@@ -183,6 +185,9 @@ Error SceneGraph::create(
 
 	m_sectors = m_alloc.newInstance<SectorGroup>(this);
 
+	m_maxReflectionProxyDistance = config.getNumber(
+		"imageReflectionMaxDistance");
+
 	return err;
 }
 

+ 4 - 10
src/script/Scene.cpp

@@ -2380,7 +2380,7 @@ static inline int pwrapSceneGraphnewReflectionProxy(lua_State* l)
 	PtrSize size;
 	(void)size;
 	
-	LuaBinder::checkArgsCount(l, 5);
+	LuaBinder::checkArgsCount(l, 3);
 	
 	// Get "this" as "self"
 	if(LuaBinder::checkUserData(l, 1, classnameSceneGraph, -7754439619132389154, ud)) return -1;
@@ -2390,17 +2390,11 @@ static inline int pwrapSceneGraphnewReflectionProxy(lua_State* l)
 	const char* arg0;
 	if(LuaBinder::checkString(l, 2, arg0)) return -1;
 	
-	F32 arg1;
-	if(LuaBinder::checkNumber(l, 3, arg1)) return -1;
-	
-	F32 arg2;
-	if(LuaBinder::checkNumber(l, 4, arg2)) return -1;
-	
-	F32 arg3;
-	if(LuaBinder::checkNumber(l, 5, arg3)) return -1;
+	const char* arg1;
+	if(LuaBinder::checkString(l, 3, arg1)) return -1;
 	
 	// Call the method
-	ReflectionProxy* ret = newSceneNode<ReflectionProxy>(self, arg0, arg1, arg2, arg3);
+	ReflectionProxy* ret = newSceneNode<ReflectionProxy>(self, arg0, arg1);
 	
 	// Push return value
 	if(ANKI_UNLIKELY(ret == nullptr))

+ 2 - 4
src/script/Scene.xml

@@ -318,12 +318,10 @@ static SceneGraph* getSceneGraph(lua_State* l)
 					<return>ReflectionProbe*</return>
 				</method>
 				<method name="newReflectionProxy">
-					<overrideCall><![CDATA[ReflectionProxy* ret = newSceneNode<ReflectionProxy>(self, arg0, arg1, arg2, arg3);]]></overrideCall>
+					<overrideCall><![CDATA[ReflectionProxy* ret = newSceneNode<ReflectionProxy>(self, arg0, arg1);]]></overrideCall>
 					<args>
 						<arg>const CString&amp;</arg>
-						<arg>F32</arg>
-						<arg>F32</arg>
-						<arg>F32</arg>
+						<arg>const CString&amp;</arg>
 					</args>
 					<return>ReflectionProxy*</return>
 				</method>

+ 9 - 8
testapp/Main.cpp

@@ -88,14 +88,14 @@ Error init()
 #if !PLAYER
 	cam->getComponent<MoveComponent>().
 		setLocalTransform(Transform(
-		Vec4(147.392776, -10.132728, 16.607138, 0.0),
-		//Vec4(0.0, 10, 0, 0),
-		Mat3x4(Euler(toRad(0.0), toRad(90.0), toRad(0.0))),
-		//Mat3x4::getIdentity(),
+		//Vec4(147.392776, -10.132728, 16.607138, 0.0),
+		Vec4(0.0, 10, 0, 0),
+		//Mat3x4(Euler(toRad(0.0), toRad(90.0), toRad(0.0))),
+		Mat3x4::getIdentity(),
 		1.0));
 #endif
 
-	if(0)
+#if 0
 	{
 		ReflectionProbe* refl;
 		scene.newSceneNode<ReflectionProbe>("refl", refl, 68.0f);
@@ -107,6 +107,7 @@ Error init()
 		move = proxy->tryGetComponent<MoveComponent>();
 		move->setLocalOrigin(Vec4(0.0, 12, -15, 0));
 	}
+#endif
 
 #if 0
 	PointLight* plight;
@@ -507,14 +508,14 @@ Error initSubsystems(int argc, char* argv[])
 	config.set("pps.sslf.enabled", true);
 	config.set("pps.sharpen", true);
 	config.set("renderingQuality", 1.0);
-	config.set("width", 128);
-	config.set("height", 128);
+	config.set("width", 1280);
+	config.set("height", 1024);
 	config.set("lodDistance", 20.0);
 	config.set("samples", 1);
 	config.set("tessellation", true);
 	//config.set("maxTextureSize", 256);
 	config.set("ir.rendererSize", 64);
-	config.set("fullscreenDesktopResolution", true);
+	config.set("fullscreenDesktopResolution", false);
 	config.set("debugContext", false);
 	if(getenv("ANKI_DATA_PATH"))
 	{

+ 1 - 1
thirdparty

@@ -1 +1 @@
-Subproject commit da77260c80833a9153df4f6ed71a3c96ed6791e9
+Subproject commit 5eef03ab77372d30bc073f4b318453aba558239c

+ 50 - 24
tools/scene/Exporter.cpp

@@ -756,21 +756,23 @@ void Exporter::load()
 {
 	LOGI("Loading file %s", &m_inputFilename[0]);
 
-	//Assimp::DefaultLogger::create("", Logger::VERBOSE);
+	const int smoothAngle = 170;
 
-	m_importer.SetPropertyFloat(AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE, 170);
+	m_importer.SetPropertyFloat(AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE,
+		smoothAngle);
 
-	const aiScene* scene = m_importer.ReadFile(m_inputFilename, 0
+	unsigned flags = 0
 		//| aiProcess_FindInstances
-		| aiProcess_Triangulate
 		| aiProcess_JoinIdenticalVertices
 		//| aiProcess_SortByPType
 		| aiProcess_ImproveCacheLocality
 		| aiProcess_OptimizeMeshes
 		| aiProcess_RemoveRedundantMaterials
 		| aiProcess_CalcTangentSpace
-		| aiProcess_GenSmoothNormals
-		);
+		| aiProcess_GenSmoothNormals;
+
+	const aiScene* scene = m_importer.ReadFile(m_inputFilename,
+		flags | aiProcess_Triangulate);
 
 	if(!scene)
 	{
@@ -778,6 +780,19 @@ void Exporter::load()
 	}
 
 	m_scene = scene;
+
+	// Load without triangulation
+	m_importerNoTriangles.SetPropertyFloat(
+		AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE, smoothAngle);
+
+	scene = m_importerNoTriangles.ReadFile(m_inputFilename, flags);
+
+	if(!scene)
+	{
+		ERROR("%s", m_importerNoTriangles.GetErrorString());
+	}
+
+	m_sceneNoTriangles = scene;
 }
 
 //==============================================================================
@@ -850,20 +865,29 @@ void Exporter::visitNode(const aiNode* ainode)
 
 				special = true;
 			}
-			else if(prop.first == "reflection_proxy_distance")
+			else if(prop.first == "reflection_proxy" && prop.second == "true")
 			{
 				ReflectionProxy proxy;
 
-				aiMatrix4x4 trf = toAnkiMatrix(ainode->mTransformation);
-				aiVector3D xAxis(trf.a1, trf.b1, trf.c1);
-				aiVector3D yAxis(trf.a2, trf.b2, trf.c2);
-
-				proxy.m_width = xAxis.Length() * 2.0;
-				proxy.m_height = yAxis.Length() * 2.0;
-				proxy.m_maxDistance = std::stof(prop.second);
-				proxy.m_transform = trf;
-				removeScale(proxy.m_transform);
-
+				// Find proxy in the other scene
+				proxy.m_meshIndex = 0xFFFFFFFF;
+				for(unsigned i = 0; i < m_sceneNoTriangles->mNumMeshes; ++i)
+				{
+					if(m_sceneNoTriangles->mMeshes[i]->mName
+						== m_scene->mMeshes[meshIndex]->mName)
+					{
+						// Found
+						proxy.m_meshIndex = i;
+						break;
+					}
+				}
+
+				if(proxy.m_meshIndex == 0xFFFFFFFF)
+				{
+					ERROR("Reflection proxy mesh not found");
+				}
+
+				proxy.m_transform = toAnkiMatrix(ainode->mTransformation);
 				m_reflectionProxies.push_back(proxy);
 
 				special = true;
@@ -975,7 +999,7 @@ void Exporter::exportAll()
 	//
 	for(auto n : m_staticCollisionNodes)
 	{
-		exportMesh(*m_scene->mMeshes[n.m_meshIndex], nullptr);
+		exportMesh(*m_scene->mMeshes[n.m_meshIndex], nullptr, 3);
 		exportCollisionMesh(n.m_meshIndex);
 
 		file << "\n";
@@ -994,7 +1018,7 @@ void Exporter::exportAll()
 	for(const Portal& portal : m_portals)
 	{
 		uint32_t meshIndex = portal.m_meshIndex;
-		exportMesh(*m_scene->mMeshes[meshIndex], nullptr);
+		exportMesh(*m_scene->mMeshes[meshIndex], nullptr, 3);
 
 		std::string name = getMeshName(getMeshAt(meshIndex));
 		std::string fname = m_rpath + name + ".ankimesh";
@@ -1012,7 +1036,7 @@ void Exporter::exportAll()
 	for(const Sector& sector : m_sectors)
 	{
 		uint32_t meshIndex = sector.m_meshIndex;
-		exportMesh(*m_scene->mMeshes[meshIndex], nullptr);
+		exportMesh(*m_scene->mMeshes[meshIndex], nullptr, 3);
 
 		std::string name = getMeshName(getMeshAt(meshIndex));
 		std::string fname = m_rpath + name + ".ankimesh";
@@ -1060,10 +1084,12 @@ void Exporter::exportAll()
 	i = 0;
 	for(const ReflectionProxy& proxy : m_reflectionProxies)
 	{
+		const aiMesh& mesh = *m_sceneNoTriangles->mMeshes[proxy.m_meshIndex];
+		exportMesh(mesh, nullptr, 4);
+
 		std::string name = "reflproxy" + std::to_string(i);
-		file << "\nnode = scene:newReflectionProxy(\"" << name << "\", "
-			<< proxy.m_width << ", " << proxy.m_height << ", "
-			<< proxy.m_maxDistance << ")\n";
+		file << "\nnode = scene:newReflectionProxy(\"" << name << "\", \""
+			<< m_rpath << mesh.mName.C_Str() << ".ankimesh\")\n";
 
 		writeNodeTransform("node", proxy.m_transform);
 		++i;
@@ -1078,7 +1104,7 @@ void Exporter::exportAll()
 		Model& model = m_models[node.m_modelIndex];
 
 		// TODO If not instanced bake transform
-		exportMesh(*m_scene->mMeshes[model.m_meshIndex], nullptr);
+		exportMesh(*m_scene->mMeshes[model.m_meshIndex], nullptr, 3);
 
 		exportMaterial(*m_scene->mMaterials[model.m_materialIndex],
 			model.m_instancesCount);

+ 5 - 6
tools/scene/Exporter.h

@@ -81,9 +81,7 @@ class ReflectionProxy
 {
 public:
 	aiMatrix4x4 m_transform;
-	float m_width;
-	float m_height;
-	float m_maxDistance;
+	uint32_t m_meshIndex; ///< Points to the scene that is not triangulated.
 };
 
 /// AnKi exporter.
@@ -98,7 +96,9 @@ public:
 	bool m_flipyz = false;
 
 	const aiScene* m_scene = nullptr;
+	const aiScene* m_sceneNoTriangles = nullptr;
 	Assimp::Importer m_importer;
+	Assimp::Importer m_importerNoTriangles;
 
 	std::vector<Model> m_models;
 	std::vector<Node> m_nodes;
@@ -145,9 +145,8 @@ private:
 
 	/// Export a mesh.
 	/// @param transform If not nullptr then transform the vertices using that.
-	void exportMesh(
-		const aiMesh& mesh,
-		const aiMatrix4x4* transform) const;
+	void exportMesh(const aiMesh& mesh, const aiMatrix4x4* transform,
+		unsigned vertCountPerFace) const;
 
 	/// Export a skeleton.
 	void exportSkeleton(const aiMesh& mesh) const;

+ 12 - 6
tools/scene/ExporterMesh.cpp

@@ -50,6 +50,8 @@ struct Format
 	FormatTransform m_transform = FormatTransform::NONE;
 };
 
+const uint32_t FLAG_QUADS = 1;
+
 struct Header
 {
 	char m_magic[8]; ///< Magic word.
@@ -187,9 +189,8 @@ uint32_t toR10G10B10A2Sint(float r, float g, float b, float a)
 }
 
 //==============================================================================
-void Exporter::exportMesh(
-	const aiMesh& mesh,
-	const aiMatrix4x4* transform) const
+void Exporter::exportMesh(const aiMesh& mesh, const aiMatrix4x4* transform,
+	unsigned vertCountPerFace) const
 {
 	std::string name = mesh.mName.C_Str();
 	std::fstream file;
@@ -237,6 +238,11 @@ void Exporter::exportMesh(
 	static const char* magic = "ANKIMES3";
 	memcpy(&header.m_magic, magic, 8);
 
+	if(vertCountPerFace == 4)
+	{
+		header.m_flags = FLAG_QUADS;
+	}
+
 	header.m_positionsFormat.m_components = ComponentFormat::R32G32B32;
 	header.m_positionsFormat.m_transform = FormatTransform::FLOAT;
 
@@ -252,7 +258,7 @@ void Exporter::exportMesh(
 	header.m_indicesFormat.m_components = ComponentFormat::R16;
 	header.m_indicesFormat.m_transform = FormatTransform::UINT;
 
-	header.m_totalIndicesCount = mesh.mNumFaces * 3;
+	header.m_totalIndicesCount = mesh.mNumFaces * vertCountPerFace;
 	header.m_totalVerticesCount = mesh.mNumVertices;
 	header.m_uvsChannelCount = 1;
 	header.m_subMeshCount = 1;
@@ -270,14 +276,14 @@ void Exporter::exportMesh(
 	{
 		const aiFace& face = mesh.mFaces[i];
 
-		if(face.mNumIndices != 3)
+		if(face.mNumIndices != vertCountPerFace)
 		{
 			ERROR("For some reason assimp returned wrong number of verts "
 				"for a face (face.mNumIndices=%d). Probably degenerates in "
 				"input file", face.mNumIndices);
 		}
 
-		for(unsigned j = 0; j < 3; j++)
+		for(unsigned j = 0; j < vertCountPerFace; j++)
 		{
 			uint32_t index32 = face.mIndices[j];
 			if(index32 > 0xFFFF)