diff -NurB a/cmake/Dependencies.cmake b/cmake/Dependencies.cmake
--- a/cmake/Dependencies.cmake	2021-02-01 20:58:54.868265188 +0100
+++ b/cmake/Dependencies.cmake	2021-02-01 16:10:11.299904056 +0100
@@ -167,7 +167,7 @@
 
 # Intel Embree
 set(EMBREE_ROOT                "${EMBREE_SEARCH_PATH}")
-find_package(Embree 2)
+find_package(Embree 3)
 
 if (Embree_FOUND)
 	message(STATUS              "Embree found: ${Embree_VERSION}")
diff -NurB a/include/luxrays/accelerators/embreeaccel.h b/include/luxrays/accelerators/embreeaccel.h
--- a/include/luxrays/accelerators/embreeaccel.h	2021-02-01 20:58:54.870265188 +0100
+++ b/include/luxrays/accelerators/embreeaccel.h	2021-02-01 16:10:11.304904056 +0100
@@ -19,8 +19,8 @@
 #ifndef _LUXRAYS_EMBREEACCEL_H
 #define	_LUXRAYS_EMBREEACCEL_H
 
-#include <embree2/rtcore.h>
-#include <embree2/rtcore_ray.h>
+#include <embree3/rtcore.h>
+#include <embree3/rtcore_ray.h>
 
 #include "luxrays/luxrays.h"
 #include "luxrays/core/accelerator.h"
@@ -48,9 +48,9 @@
 
 private:
 	static bool MeshPtrCompare(const Mesh *p0, const Mesh *p1);
-	
-	u_int ExportTriangleMesh(const RTCScene embreeScene, const Mesh *mesh) const;
-	u_int ExportMotionTriangleMesh(const RTCScene embreeScene, const MotionTriangleMesh *mtm) const;
+
+	void ExportTriangleMesh(const RTCScene embreeScene, const Mesh *mesh) const;
+	void ExportMotionTriangleMesh(const RTCScene embreeScene, const MotionTriangleMesh *mtm) const;
 
 	// Used for Embree initialization
 	static boost::mutex initMutex;
@@ -59,9 +59,12 @@
 
 	const Context *ctx;
 
+	RTCDevice embreeDevice;
 	RTCScene embreeScene;
 	std::map<const Mesh *, RTCScene, bool (*)(const Mesh *, const Mesh *)> uniqueRTCSceneByMesh;
-	// Used to normalize between 0.f and 1.f
+	std::map<const Mesh *, RTCGeometry, bool (*)(const Mesh *, const Mesh *)> uniqueGeomByMesh;
+	std::map<const Mesh *, Matrix4x4, bool (*)(const Mesh *, const Mesh *)> uniqueInstMatrixByMesh;
+		// Used to normalize between 0.f and 1.f
 	float minTime, maxTime, timeScale;
 };
 
diff -NurB a/src/luxrays/accelerators/embreeaccel.cpp b/src/luxrays/accelerators/embreeaccel.cpp
--- a/src/luxrays/accelerators/embreeaccel.cpp	2021-02-01 20:58:54.858265188 +0100
+++ b/src/luxrays/accelerators/embreeaccel.cpp	2021-02-01 16:10:11.468904062 +0100
@@ -30,116 +30,83 @@
 
 namespace luxrays {
 
-void Embree_error_handler(const RTCError code, const char *str) {
-	std::string errType;
-
-	switch (code) {
-		case RTC_UNKNOWN_ERROR:
-			errType = "RTC_UNKNOWN_ERROR";
-			break;
-		case RTC_INVALID_ARGUMENT:
-			errType = "RTC_INVALID_ARGUMENT";
-			break;
-		case RTC_INVALID_OPERATION:
-			errType = "RTC_INVALID_OPERATION";
-			break;
-		case RTC_OUT_OF_MEMORY:
-			errType = "RTC_OUT_OF_MEMORY";
-			break;
-		case RTC_UNSUPPORTED_CPU:
-			errType = "RTC_UNSUPPORTED_CPU";
-			break;
-		default:
-			errType = "invalid error code";
-			break;
-	}
-
-	std::cout << "Embree error: " << str << "\n";
-
-	abort();
-}
-
-boost::mutex EmbreeAccel::initMutex;
-u_int EmbreeAccel::initCount = 0;
 
 EmbreeAccel::EmbreeAccel(const Context *context) : ctx(context),
-		uniqueRTCSceneByMesh(MeshPtrCompare) {
+		uniqueRTCSceneByMesh(MeshPtrCompare)
+		, uniqueGeomByMesh(MeshPtrCompare)
+		, uniqueInstMatrixByMesh(MeshPtrCompare){
+	embreeDevice = rtcNewDevice(NULL);
 	embreeScene = NULL;
 
-	// Initialize Embree
-	boost::unique_lock<boost::mutex> lock(initMutex);
-	if (initCount == 0) {
-		rtcInit(NULL);
-		rtcSetErrorFunction(Embree_error_handler);
-	}
-	++initCount;
 }
 
 EmbreeAccel::~EmbreeAccel() {
 	if (embreeScene) {
-		rtcDeleteScene(embreeScene);
+		rtcReleaseScene(embreeScene);
 
 		// I have to free all Embree scene used for instances
 		std::pair<const Mesh *, RTCScene> elem;
 		BOOST_FOREACH(elem, uniqueRTCSceneByMesh)
-			rtcDeleteScene(elem.second);
+			rtcReleaseScene(elem.second);
 	}
+	rtcReleaseDevice(embreeDevice);
 
-	// Shutdown Embree if I was the last one
-	boost::unique_lock<boost::mutex> lock(initMutex);
-	if (initCount == 1)
-		rtcExit();
-	--initCount;
 }
 
-u_int EmbreeAccel::ExportTriangleMesh(const RTCScene embreeScene, const Mesh *mesh) const {
-	const u_int geomID = rtcNewTriangleMesh(embreeScene, RTC_GEOMETRY_STATIC,
-			mesh->GetTotalTriangleCount(), mesh->GetTotalVertexCount(), 1);
+void EmbreeAccel::ExportTriangleMesh(const RTCScene embreeScene, const Mesh *mesh) const {
+	const RTCGeometry geom = rtcNewGeometry(embreeDevice, RTC_GEOMETRY_TYPE_TRIANGLE);
 
 	// Share with Embree the mesh vertices
 	Point *meshVerts = mesh->GetVertices();
-	rtcSetBuffer(embreeScene, geomID, RTC_VERTEX_BUFFER, meshVerts, 0, 3 * sizeof(float));
+	rtcSetSharedGeometryBuffer(geom, RTC_BUFFER_TYPE_VERTEX, 0, RTC_FORMAT_FLOAT3, meshVerts,
+			0, sizeof(Point), mesh->GetTotalVertexCount());
+
 
 	// Share with Embree the mesh triangles
 	Triangle *meshTris = mesh->GetTriangles();
-	rtcSetBuffer(embreeScene, geomID, RTC_INDEX_BUFFER, meshTris, 0, 3 * sizeof(int));
-	
-	return geomID;
-}
+	rtcSetSharedGeometryBuffer(geom, RTC_BUFFER_TYPE_INDEX, 0, RTC_FORMAT_UINT3, meshTris,
+			0, sizeof(Triangle), mesh->GetTotalTriangleCount());
 
-u_int EmbreeAccel::ExportMotionTriangleMesh(const RTCScene embreeScene, const MotionTriangleMesh *mtm) const {
-	const u_int geomID = rtcNewTriangleMesh(embreeScene, RTC_GEOMETRY_STATIC,
-			mtm->GetTotalTriangleCount(), mtm->GetTotalVertexCount(), 2);
+	rtcCommitGeometry(geom);
 
-	const MotionSystem &ms = mtm->GetMotionSystem();
+	rtcAttachGeometry(embreeScene, geom);
 
-	// Copy the mesh start position vertices
-	float *vertices0 = (float *)rtcMapBuffer(embreeScene, geomID, RTC_VERTEX_BUFFER0);
-	for (u_int i = 0; i < mtm->GetTotalVertexCount(); ++i) {
-		const Point v = mtm->GetVertex(ms.StartTime(), i);
-		*vertices0++ = v.x;
-		*vertices0++ = v.y;
-		*vertices0++ = v.z;
-		++vertices0;
-	}
-	rtcUnmapBuffer(embreeScene, geomID, RTC_VERTEX_BUFFER0);
+	rtcReleaseGeometry(geom);
+}
+
+void EmbreeAccel::ExportMotionTriangleMesh(const RTCScene embreeScene, const MotionTriangleMesh *mtm) const {
+	const MotionSystem &ms = mtm->GetMotionSystem();
 
-	// Copy the mesh end position vertices
-	float *vertices1 = (float *)rtcMapBuffer(embreeScene, geomID, RTC_VERTEX_BUFFER1);
-	for (u_int i = 0; i < mtm->GetTotalVertexCount(); ++i) {
-		const Point v = mtm->GetVertex(ms.EndTime(), i);
-		*vertices1++ = v.x;
-		*vertices1++ = v.y;
-		*vertices1++ = v.z;
-		++vertices1;
+	// Check if I would need more than the max. number of steps (i.e. 129) supported by Embree
+	if (ms.times.size() > RTC_MAX_TIME_STEP_COUNT)
+		throw std::runtime_error("Embree accelerator supports up to " + ToString(RTC_MAX_TIME_STEP_COUNT) +
+				" motion blur steps, unable to use " + ToString(ms.times.size()));
+
+	const RTCGeometry geom = rtcNewGeometry(embreeDevice, RTC_GEOMETRY_TYPE_TRIANGLE);
+	rtcSetGeometryTimeStepCount(geom, ms.times.size());
+
+	for (u_int step = 0; step < ms.times.size(); ++step) {
+		// Copy the mesh start position vertices
+		Point *vertices = (Point *)rtcSetNewGeometryBuffer(geom, RTC_BUFFER_TYPE_VERTEX, step, RTC_FORMAT_FLOAT3,
+				sizeof(Point), mtm->GetTotalVertexCount());
+
+		Transform local2World;
+//		mtm->GetLocal2World(ms.times[step], local2World);
+		for (u_int i = 0; i < mtm->GetTotalVertexCount(); ++i)
+			vertices[i] = mtm->GetVertex(ms.EndTime(), i);
 	}
-	rtcUnmapBuffer(embreeScene, geomID, RTC_VERTEX_BUFFER1);
 
 	// Share the mesh triangles
 	Triangle *meshTris = mtm->GetTriangles();
-	rtcSetBuffer(embreeScene, geomID, RTC_INDEX_BUFFER, meshTris, 0, 3 * sizeof(int));
-	
-	return geomID;
+	rtcSetSharedGeometryBuffer(geom, RTC_BUFFER_TYPE_INDEX, 0, RTC_FORMAT_UINT3, (RTCBuffer)meshTris,
+			0, sizeof(Triangle), mtm->GetTotalTriangleCount());
+
+	rtcCommitGeometry(geom);
+
+	rtcAttachGeometry(embreeScene, geom);
+
+	rtcReleaseGeometry(geom);
+
 }
 
 void EmbreeAccel::Init(const std::deque<const Mesh *> &meshes,
@@ -155,7 +122,7 @@
 	maxTime = std::numeric_limits<float>::min();
 	BOOST_FOREACH(const Mesh *mesh, meshes) {
 		const MotionTriangleMesh *mtm = dynamic_cast<const MotionTriangleMesh *>(mesh);
-		
+
 		if (mtm) {
 			minTime = Min(minTime, mtm->GetMotionSystem().StartTime());
 			maxTime = Min(maxTime, mtm->GetMotionSystem().EndTime());
@@ -174,7 +141,9 @@
 	// Convert the meshes to an Embree Scene
 	//--------------------------------------------------------------------------
 
-	embreeScene = rtcNewScene(RTC_SCENE_STATIC, RTC_INTERSECT1);
+	embreeScene = rtcNewScene(embreeDevice);
+	rtcSetSceneBuildQuality(embreeScene, RTC_BUILD_QUALITY_HIGH);
+	rtcSetSceneFlags(embreeScene, RTC_SCENE_FLAG_DYNAMIC);
 
 	BOOST_FOREACH(const Mesh *mesh, meshes) {
 		switch (mesh->GetType()) {
@@ -195,18 +164,28 @@
 					TriangleMesh *instancedMesh = itm->GetTriangleMesh();
 
 					// Create a new RTCScene
-					instScene = rtcNewScene(RTC_SCENE_STATIC, RTC_INTERSECT1);
+					instScene = rtcNewScene(embreeDevice);
 					ExportTriangleMesh(instScene, instancedMesh);
-					rtcCommit(instScene);
+					rtcCommitScene(instScene);
 
 					uniqueRTCSceneByMesh[instancedMesh] = instScene;
 				} else
 					instScene = it->second;
 
-				const u_int instID = rtcNewInstance(embreeScene, instScene);
-				rtcSetTransform(embreeScene, instID, RTC_MATRIX_ROW_MAJOR, &(itm->GetTransformation().m.m[0][0]));
-				break;
-			}
+				RTCGeometry geom = rtcNewGeometry(embreeDevice, RTC_GEOMETRY_TYPE_INSTANCE);
+				rtcSetGeometryInstancedScene(geom, instScene);
+				rtcSetGeometryTransform(geom, 0, RTC_FORMAT_FLOAT3X4_ROW_MAJOR, &(itm->GetTransformation().m.m[0][0]));
+				rtcCommitGeometry(geom);
+
+				rtcAttachGeometry(embreeScene, geom);
+
+				rtcReleaseGeometry(geom);
+
+				// Save the instance ID
+				uniqueGeomByMesh[mesh] = geom;
+				// Save the matrix
+				uniqueInstMatrixByMesh[mesh] = itm->GetTransformation().m;
+				break;			}
 			case TYPE_TRIANGLE_MOTION:
 			case TYPE_EXT_TRIANGLE_MOTION: {
 				const MotionTriangleMesh *mtm = dynamic_cast<const MotionTriangleMesh *>(mesh);
@@ -218,7 +197,7 @@
 		}
 	}
 
-	rtcCommit(embreeScene);
+	rtcCommitScene(embreeScene);
 
 	LR_LOG(ctx, "EmbreeAccel build time: " << int((WallClockTime() - t0) * 1000) << "ms");
 }
@@ -228,35 +207,37 @@
 }
 
 bool EmbreeAccel::Intersect(const Ray *ray, RayHit *hit) const {
-	RTCRay embreeRay;
+	RTCRayHit embreeRay;
+	RTCIntersectContext embreeContext;
+	rtcInitIntersectContext(&embreeContext);
 
-	embreeRay.org[0] = ray->o.x;
-	embreeRay.org[1] = ray->o.y;
-	embreeRay.org[2] = ray->o.z;
+	embreeRay.ray.org_x = ray->o.x;
+	embreeRay.ray.org_y = ray->o.y;
+	embreeRay.ray.org_z = ray->o.z;
 
-	embreeRay.dir[0] = ray->d.x;
-	embreeRay.dir[1] = ray->d.y;
-	embreeRay.dir[2] = ray->d.z;
+	embreeRay.ray.dir_x = ray->d.x;
+	embreeRay.ray.dir_y = ray->d.y;
+	embreeRay.ray.dir_z = ray->d.z;
 
-	embreeRay.tnear = ray->mint;
-	embreeRay.tfar = ray->maxt;
+	embreeRay.ray.tnear = ray->mint;
+	embreeRay.ray.tfar = ray->maxt;
 
-	embreeRay.geomID = RTC_INVALID_GEOMETRY_ID;
-	embreeRay.primID = RTC_INVALID_GEOMETRY_ID;
-	embreeRay.instID = RTC_INVALID_GEOMETRY_ID;
-	embreeRay.mask = 0xFFFFFFFF;
-	embreeRay.time = (ray->time - minTime) * timeScale;
+	embreeRay.hit.geomID = RTC_INVALID_GEOMETRY_ID;
+	embreeRay.hit.primID = RTC_INVALID_GEOMETRY_ID;
+	embreeRay.hit.instID[0] = RTC_INVALID_GEOMETRY_ID;
+	embreeRay.ray.mask = 0xFFFFFFFF;
+	embreeRay.ray.time = (ray->time - minTime) * timeScale;
 
-	rtcIntersect(embreeScene, embreeRay);
+	rtcIntersect1(embreeScene, &embreeContext, &embreeRay);
 
-	if (embreeRay.geomID != RTC_INVALID_GEOMETRY_ID) {
-		hit->meshIndex = (embreeRay.instID == RTC_INVALID_GEOMETRY_ID) ? embreeRay.geomID : embreeRay.instID;
-		hit->triangleIndex = embreeRay.primID;
+	if (embreeRay.hit.geomID != RTC_INVALID_GEOMETRY_ID) {
+		hit->meshIndex = (embreeRay.hit.instID[0] == RTC_INVALID_GEOMETRY_ID) ? embreeRay.hit.geomID : embreeRay.hit.instID[0];
+		hit->triangleIndex = embreeRay.hit.primID;
 
-		hit->t = embreeRay.tfar;
+		hit->t = embreeRay.ray.tfar;
 
-		hit->b1 = embreeRay.u;
-		hit->b2 = embreeRay.v;
+		hit->b1 = embreeRay.hit.u;
+		hit->b2 = embreeRay.hit.v;
 
 		return true;
 	} else
