// ======================================================================== // // Copyright 2009-2014 Intel Corporation // // // // Licensed under the Apache License, Version 2.0 (the "License"); // // you may not use this file except in compliance with the License. // // You may obtain a copy of the License at // // // // http://www.apache.org/licenses/LICENSE-2.0 // // // // Unless required by applicable law or agreed to in writing, software // // distributed under the License is distributed on an "AS IS" BASIS, // // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // // See the License for the specific language governing permissions and // // limitations under the License. // // ======================================================================== // #include "../common/tutorial/tutorial_device.h" #include "../common/tutorial/scene_device.h" //#define FORCE_FIXED_EDGE_TESSELLATION #define FIXED_EDGE_TESSELLATION_VALUE 4 #define MAX_EDGE_LEVEL 64.0f #define MIN_EDGE_LEVEL 2.0f #define ENABLE_DISPLACEMENTS 0 #if ENABLE_DISPLACEMENTS # define LEVEL_FACTOR 256.0f #else # define LEVEL_FACTOR 64.0f #endif /* scene data */ extern "C" ISPCScene* g_ispc_scene; RTCScene g_scene = NULL; RTCScene g_embree_scene = NULL; RTCScene g_osd_scene = NULL; /* render function to use */ renderPixelFunc renderPixel; /* error reporting function */ void error_handler(const RTCError code, const int8* str) { printf("Embree: "); switch (code) { case RTC_UNKNOWN_ERROR : printf("RTC_UNKNOWN_ERROR"); break; case RTC_INVALID_ARGUMENT : printf("RTC_INVALID_ARGUMENT"); break; case RTC_INVALID_OPERATION: printf("RTC_INVALID_OPERATION"); break; case RTC_OUT_OF_MEMORY : printf("RTC_OUT_OF_MEMORY"); break; case RTC_UNSUPPORTED_CPU : printf("RTC_UNSUPPORTED_CPU"); break; default : printf("invalid error code"); break; } if (str) { printf(" ("); while (*str) putchar(*str++); printf(")\n"); } abort(); } Vec3fa renderPixelEyeLight(float x, float y, const Vec3fa& vx, const Vec3fa& vy, const Vec3fa& vz, const Vec3fa& p); /* called by the C++ code for initialization */ extern "C" void device_init (int8* cfg) { /* initialize ray tracing core */ rtcInit(cfg); /* set error handler */ rtcSetErrorFunction(error_handler); /* set start render mode */ renderPixel = renderPixelStandard; // renderPixel = renderPixelUV; } void updateEdgeLevelBuffer( ISPCMesh* mesh, const Vec3fa& cam_pos, size_t startID, size_t endID ) { for (size_t f=startID; fquads[f]; const Vec3fa v0 = mesh->positions[index[i]]; const Vec3fa v1 = mesh->positions[index[(i+1)%N]]; const Vec3fa edge = v1-v0; const Vec3fa P = 0.5f*(v1+v0); const Vec3fa dist = cam_pos - P; mesh->edge_level[f*4+i] = max(min(LEVEL_FACTOR*(0.5f*length(edge)/length(dist)),MAX_EDGE_LEVEL),MIN_EDGE_LEVEL); // FIXME: map mesh subdivlevel buffer assert( mesh->edge_level[f*4+i] >= 1.0f ); } } } #if defined(ISPC) task void updateEdgeLevelBufferTask( ISPCMesh* mesh, const Vec3fa& cam_pos ) { const size_t size = mesh->numQuads; const size_t startID = ((taskIndex+0)*size)/taskCount; const size_t endID = ((taskIndex+1)*size)/taskCount; updateEdgeLevelBuffer(mesh,cam_pos,startID,endID); } #endif void updateEdgeLevels(ISPCScene* scene_in, const Vec3fa& cam_pos) { for (int i=0; inumMeshes; i++) { ISPCMesh* mesh = g_ispc_scene->meshes[i]; if (mesh->numQuads == 0) continue; if (mesh->edge_level) { unsigned int geomID = mesh->geomID; #if defined(ISPC) launch[ getNumHWThreads() ] updateEdgeLevelBufferTask(mesh,cam_pos); #else updateEdgeLevelBuffer(mesh,cam_pos,0,mesh->numQuads); #endif rtcUpdateBuffer(g_scene,geomID,RTC_LEVEL_BUFFER); } } for (size_t g=0; gnumSubdivMeshes; g++) { ISPCSubdivMesh* mesh = g_ispc_scene->subdiv[g]; unsigned int geomID = mesh->geomID; for (size_t f=0, e=0; fnumFaces; e+=mesh->verticesPerFace[f++]) { int N = mesh->verticesPerFace[f]; for (size_t i=0; ipositions[mesh->position_indices[e+(i+0)]]; const Vec3fa v1 = mesh->positions[mesh->position_indices[e+(i+1)%N]]; const Vec3fa edge = v1-v0; const Vec3fa P = 0.5f*(v1+v0); const Vec3fa dist = cam_pos - P; mesh->subdivlevel[e+i] = max(min(LEVEL_FACTOR*(0.5f*length(edge)/length(dist)),MAX_EDGE_LEVEL),MIN_EDGE_LEVEL); } } } } void displacementFunction(void* ptr, unsigned int geomID, int unsigned primID, const float* u, /*!< u coordinates (source) */ const float* v, /*!< v coordinates (source) */ const float* nx, /*!< x coordinates of normal at point to displace (source) */ const float* ny, /*!< y coordinates of normal at point to displace (source) */ const float* nz, /*!< z coordinates of normal at point to displace (source) */ float* px, /*!< x coordinates of points to displace (source and target) */ float* py, /*!< y coordinates of points to displace (source and target) */ float* pz, /*!< z coordinates of points to displace (source and target) */ size_t N) { #if 0 for (size_t i = 0; inumMeshes; i++) { /* get ith mesh */ ISPCMesh* mesh = scene_in->meshes[i]; if (mesh->numQuads) { mesh->edge_level = new float[mesh->numQuads*4]; for (size_t i=0; i<4*mesh->numQuads; i++) mesh->edge_level[i] = FIXED_EDGE_TESSELLATION_VALUE; /* create a triangle mesh */ unsigned int geomID = rtcNewSubdivisionMesh (g_scene, RTC_GEOMETRY_STATIC, mesh->numQuads, mesh->numQuads*4, mesh->numVertices, 0, 0, 0); mesh->geomID = geomID; unsigned int* faces = (unsigned int*) rtcMapBuffer(g_scene, geomID, RTC_FACE_BUFFER); for (size_t i=0; inumQuads; i++) faces[i] = 4; rtcUnmapBuffer(g_scene,geomID,RTC_FACE_BUFFER); rtcSetBuffer(g_scene, geomID, RTC_VERTEX_BUFFER, mesh->positions , 0, sizeof(Vec3fa )); rtcSetBuffer(g_scene, geomID, RTC_INDEX_BUFFER, mesh->quads , 0, sizeof(unsigned int)); rtcSetBuffer(g_scene, geomID, RTC_LEVEL_BUFFER, mesh->edge_level, 0, sizeof(float)); #if ENABLE_DISPLACEMENTS == 1 rtcSetDisplacementFunction(g_scene,geomID,(RTCDisplacementFunc)&displacementFunction,NULL); #endif } else mesh->edge_level = NULL; } /* add all subdiv meshes to the scene */ for (size_t i=0; inumSubdivMeshes; i++) { ISPCSubdivMesh* mesh = scene_in->subdiv[i]; unsigned int geomID = rtcNewSubdivisionMesh(g_scene, RTC_GEOMETRY_STATIC, mesh->numFaces, mesh->numEdges, mesh->numVertices, mesh->numEdgeCreases, mesh->numVertexCreases, mesh->numHoles); mesh->geomID = geomID; rtcSetBuffer(g_scene, geomID, RTC_VERTEX_BUFFER, mesh->positions, 0, sizeof(Vec3fa )); rtcSetBuffer(g_scene, geomID, RTC_LEVEL_BUFFER, mesh->subdivlevel, 0, sizeof(float)); rtcSetBuffer(g_scene, geomID, RTC_INDEX_BUFFER, mesh->position_indices , 0, sizeof(unsigned int)); rtcSetBuffer(g_scene, geomID, RTC_FACE_BUFFER, mesh->verticesPerFace, 0, sizeof(unsigned int)); rtcSetBuffer(g_scene, geomID, RTC_HOLE_BUFFER, mesh->holes, 0, sizeof(unsigned int)); rtcSetBuffer(g_scene, geomID, RTC_EDGE_CREASE_INDEX_BUFFER, mesh->edge_creases, 0, 2*sizeof(unsigned int)); rtcSetBuffer(g_scene, geomID, RTC_EDGE_CREASE_WEIGHT_BUFFER, mesh->edge_crease_weights, 0, sizeof(float)); rtcSetBuffer(g_scene, geomID, RTC_VERTEX_CREASE_INDEX_BUFFER, mesh->vertex_creases, 0, sizeof(unsigned int)); rtcSetBuffer(g_scene, geomID, RTC_VERTEX_CREASE_WEIGHT_BUFFER, mesh->vertex_crease_weights, 0, sizeof(float)); #if ENABLE_DISPLACEMENTS == 1 //BBox3fa bounds(Vec3fa(-0.1f,-0.1f,-0.1f),Vec3fa(0.1f,0.1f,0.1f)); rtcSetDisplacementFunction(g_scene, geomID, (RTCDisplacementFunc)&displacementFunction,NULL); #endif } } #if defined(__USE_OPENSUBDIV__) #include using namespace OpenSubdiv; struct OSDVertex { // Minimal required interface ---------------------- OSDVertex() { } OSDVertex(OSDVertex const & src) { _position[0] = src._position[0]; _position[1] = src._position[1]; _position[1] = src._position[1]; } void Clear( void * =0 ) { _position[0]=_position[1]=_position[2]=0.0f; } void AddWithWeight(OSDVertex const & src, float weight) { _position[0]+=weight*src._position[0]; _position[1]+=weight*src._position[1]; _position[2]+=weight*src._position[2]; } void AddVaryingWithWeight(OSDVertex const &, float) { } // Public interface ------------------------------------ void SetPosition(float x, float y, float z) { _position[0]=x; _position[1]=y; _position[2]=z; } const float * GetPosition() const { return _position; } private: float _position[3]; }; RTCScene constructSceneOpenSubdiv() { if (!g_ispc_scene) return NULL; typedef Far::TopologyRefinerFactoryBase::TopologyDescriptor Descriptor; Sdc::Options options; options.SetVVarBoundaryInterpolation(Sdc::Options::VVAR_BOUNDARY_EDGE_ONLY); options.SetCreasingMethod(Sdc::Options::CREASE_CHAIKIN); RTCScene scene = rtcNewScene(RTC_SCENE_STATIC, RTC_INTERSECT1); for (size_t i=0; inumSubdivMeshes; i++) { ISPCSubdivMesh* mesh = g_ispc_scene->subdiv[i]; Descriptor desc; desc.numVertices = mesh->numVertices; desc.numFaces = mesh->numFaces; desc.vertsPerFace = mesh->verticesPerFace; desc.vertIndices = mesh->position_indices; desc.numCreases = mesh->numEdgeCreases; desc.creaseVertexIndexPairs = (int*) mesh->edge_creases; desc.creaseWeights = mesh->edge_crease_weights; desc.numCorners = mesh->numVertexCreases; desc.cornerVertexIndices = mesh->vertex_creases; desc.cornerWeights = mesh->vertex_crease_weights; size_t maxlevel = 5; Far::TopologyRefiner* refiner = Far::TopologyRefinerFactory::Create(OpenSubdiv::Sdc::TYPE_CATMARK, options, desc); refiner->RefineUniform(maxlevel); std::vector vbuffer(refiner->GetNumVerticesTotal()); OSDVertex* verts = &vbuffer[0]; for (int i=0; inumVertices; ++i) verts[i].SetPosition(mesh->positions[i].x,mesh->positions[i].y,mesh->positions[i].z); refiner->Interpolate(verts, verts + mesh->numVertices); for (int level=0; levelGetNumVertices(level); const size_t numVertices = refiner->GetNumVertices(maxlevel); const size_t numFaces = refiner->GetNumFaces(maxlevel); unsigned int meshID = rtcNewTriangleMesh(scene, RTC_GEOMETRY_STATIC, 2*numFaces, numVertices); rtcSetBuffer(scene, meshID, RTC_VERTEX_BUFFER, verts, 0, sizeof(Vec3fa)); Vec3i* tris = (Vec3i*) rtcMapBuffer(scene, meshID, RTC_INDEX_BUFFER); for (size_t i=0; iGetFaceVertices(maxlevel, i); assert(fverts.size() == 4); tris[2*i+0] = Vec3i(fverts[0],fverts[1],fverts[2]); tris[2*i+1] = Vec3i(fverts[2],fverts[3],fverts[0]); } rtcUnmapBuffer(scene,meshID,RTC_INDEX_BUFFER); } rtcCommit(scene); return scene; } #endif Vec3fa rndColor(const int ID) { int r = ((ID+13)*17*23) & 255; int g = ((ID+15)*11*13) & 255; int b = ((ID+17)* 7*19) & 255; const float oneOver255f = 1.f/255.f; return Vec3fa(r*oneOver255f,g*oneOver255f,b*oneOver255f); } /* task that renders a single screen tile */ Vec3fa renderPixelStandard(float x, float y, const Vec3fa& vx, const Vec3fa& vy, const Vec3fa& vz, const Vec3fa& p) { /* initialize ray */ RTCRay ray; ray.org = p; ray.dir = normalize(x*vx + y*vy + vz); ray.tnear = 0.0f; ray.tfar = inf; ray.geomID = RTC_INVALID_GEOMETRY_ID; ray.primID = RTC_INVALID_GEOMETRY_ID; ray.mask = -1; ray.time = 0; /* intersect ray with scene */ rtcIntersect(g_scene,ray); /* shade background black */ if (ray.geomID == RTC_INVALID_GEOMETRY_ID) return Vec3fa(0.0f,0.0f,1.0f); /* shade all rays that hit something */ Vec3fa color = Vec3fa(1.0f); #if 0 color = rndColor(ray.geomID); #else /* apply ambient light */ Vec3fa Ng = normalize(ray.Ng); color = color*abs(dot(ray.dir,Ng)); #endif return color; } /* task that renders a single screen tile */ void renderTile(int taskIndex, int* pixels, const int width, const int height, const float time, const Vec3fa& vx, const Vec3fa& vy, const Vec3fa& vz, const Vec3fa& p, const int numTilesX, const int numTilesY) { const int tileY = taskIndex / numTilesX; const int tileX = taskIndex - tileY * numTilesX; const int x0 = tileX * TILE_SIZE_X; const int x1 = min(x0+TILE_SIZE_X,width); const int y0 = tileY * TILE_SIZE_Y; const int y1 = min(y0+TILE_SIZE_Y,height); for (int y = y0; y