/* task that renders a single screen tile */ Vec3fa renderPixelStandard(float x, float y, const ISPCCamera& camera, RayStats& stats) { /* initialize sampler */ RandomSampler sampler; RandomSampler_init(sampler, (int)x, (int)y, 0); /* initialize ray */ Ray ray(Vec3fa(camera.xfm.p), Vec3fa(normalize(x*camera.xfm.l.vx + y*camera.xfm.l.vy + camera.xfm.l.vz)), 0.0f, inf, RandomSampler_get1D(sampler)); /* intersect ray with scene */ RTCIntersectContext context; rtcInitIntersectContext(&context); context.flags = g_iflags_coherent; rtcIntersect1(g_scene,&context,RTCRayHit_(ray)); RayStats_addRay(stats); /* shade background black */ if (ray.geomID == RTC_INVALID_GEOMETRY_ID) { return Vec3fa(0.0f); } /* shade all rays that hit something */ Vec3fa color = Vec3fa(0.5f); /* compute differential geometry */ DifferentialGeometry dg; dg.geomID = ray.geomID; dg.primID = ray.primID; dg.u = ray.u; dg.v = ray.v; dg.P = ray.org+ray.tfar*ray.dir; dg.Ng = ray.Ng; dg.Ns = ray.Ng; if (g_use_smooth_normals) if (ray.geomID != RTC_INVALID_GEOMETRY_ID) // FIXME: workaround for ISPC bug, location reached with empty execution mask { Vec3fa dPdu,dPdv; unsigned int geomID = ray.geomID; { rtcInterpolate1(rtcGetGeometry(g_scene,geomID),ray.primID,ray.u,ray.v,RTC_BUFFER_TYPE_VERTEX,0,nullptr,&dPdu.x,&dPdv.x,3); } dg.Ns = cross(dPdv,dPdu); } int materialID = postIntersect(ray,dg); dg.Ng = face_forward(ray.dir,normalize(dg.Ng)); dg.Ns = face_forward(ray.dir,normalize(dg.Ns)); /* shade */ if (g_ispc_scene->materials[materialID]->type == MATERIAL_OBJ) { ISPCOBJMaterial* material = (ISPCOBJMaterial*) g_ispc_scene->materials[materialID]; color = Vec3fa(material->Kd); } return color*dot(neg(ray.dir),dg.Ns); }
Vec3fa renderPixelTestEyeLight(float x, float y, const Vec3fa& vx, const Vec3fa& vy, const Vec3fa& vz, const Vec3fa& p) { RandomSampler sampler; RandomSampler_init(sampler, x, y, g_accu_count); x += RandomSampler_get1D(sampler); y += RandomSampler_get1D(sampler); /* initialize ray */ RTCRay2 ray; ray.org = p; ray.dir = normalize(x*vx + y*vy + vz); Vec3fa dir1 = normalize((x+1)*vx + (y+1)*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; Vec3fa color = Vec3fa(0.0f); float weight = 1.0f; rtcIntersect(g_scene,*((RTCRay*)&ray)); ray.filter = nullptr; if (ray.primID == -1) return Vec3fa(0.0f); Vec3fa Ng; ISPCGeometry* geometry = g_ispc_scene->geometries[ray.geomID]; if (geometry->type == HAIR_SET) { const Vec3fa dx = normalize(ray.Ng); const Vec3fa dy = normalize(cross(ray.dir,dx)); const Vec3fa dz = normalize(cross(dy,dx)); Ng = dz; } else { if (dot(ray.dir,ray.Ng) > 0) ray.Ng = neg(ray.Ng); const Vec3fa dz = normalize(ray.Ng); const Vec3fa dx = normalize(cross(dz,ray.dir)); const Vec3fa dy = normalize(cross(dz,dx)); Ng = dz; } color = color + Vec3fa(0.2f + 0.5f * abs(dot(ray.dir,Ng))); return color; }
/* task that renders a single screen tile */ Vec3fa renderPixelPathTrace(float x, float y, const Vec3fa& vx, const Vec3fa& vy, const Vec3fa& vz, const Vec3fa& p) { RandomSampler sampler; RandomSampler_init(sampler, x, y, g_accu_count); x += RandomSampler_get1D(sampler); y += RandomSampler_get1D(sampler); float time = RandomSampler_get1D(sampler); /* initialize ray */ RTCRay2 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 = time; ray.filter = nullptr; Vec3fa color = Vec3fa(0.0f); Vec3fa weight = Vec3fa(1.0f); size_t depth = 0; while (true) { /* terminate ray path */ if (reduce_max(weight) < 0.01 || depth > 20) return color; /* intersect ray with scene and gather all hits */ rtcIntersect(g_scene,*((RTCRay*)&ray)); /* exit if we hit environment */ if (ray.geomID == RTC_INVALID_GEOMETRY_ID) return color + weight*Vec3fa(g_ambient_intensity); /* calculate transmissivity of hair */ AnisotropicBlinn brdf; float tnear_eps = 0.0001f; ISPCGeometry* geometry = g_ispc_scene->geometries[ray.geomID]; if (geometry->type == HAIR_SET) { /* calculate tangent space */ const Vec3fa dx = normalize(ray.Ng); const Vec3fa dy = normalize(cross(ray.dir,dx)); const Vec3fa dz = normalize(cross(dy,dx)); /* generate anisotropic BRDF */ AnisotropicBlinn__Constructor(&brdf,hair_Kr,hair_Kt,dx,20.0f,dy,2.0f,dz); brdf.Kr = hair_Kr; Vec3fa p = evalBezier(ray.geomID,ray.primID,ray.u); tnear_eps = 1.1f*p.w; } else if (geometry->type == TRIANGLE_MESH) { ISPCTriangleMesh* mesh = (ISPCTriangleMesh*) geometry; ISPCTriangle* triangle = &mesh->triangles[ray.primID]; OBJMaterial* material = (OBJMaterial*) &g_ispc_scene->materials[triangle->materialID]; if (dot(ray.dir,ray.Ng) > 0) ray.Ng = neg(ray.Ng); /* calculate tangent space */ const Vec3fa dz = normalize(ray.Ng); const Vec3fa dx = normalize(cross(dz,ray.dir)); const Vec3fa dy = normalize(cross(dz,dx)); /* generate isotropic BRDF */ AnisotropicBlinn__Constructor(&brdf,Vec3fa(1.0f),Vec3fa(0.0f),dx,1.0f,dy,1.0f,dz); } /* sample directional light */ RTCRay2 shadow; shadow.org = ray.org + ray.tfar*ray.dir; shadow.dir = neg(Vec3fa(g_dirlight_direction)); shadow.tnear = tnear_eps; shadow.tfar = inf; shadow.time = time; Vec3fa T = occluded(g_scene,shadow); Vec3fa c = AnisotropicBlinn__eval(&brdf,neg(ray.dir),neg(Vec3fa(g_dirlight_direction))); color = color + weight*c*T*Vec3fa(g_dirlight_intensity); #if 1 /* sample BRDF */ Vec3fa wi; float ru = RandomSampler_get1D(sampler); float rv = RandomSampler_get1D(sampler); float rw = RandomSampler_get1D(sampler); c = AnisotropicBlinn__sample(&brdf,neg(ray.dir),wi,ru,rv,rw); if (wi.w <= 0.0f) return color; /* calculate secondary ray and offset it out of the hair */ float sign = dot(Vec3fa(wi),brdf.dz) < 0.0f ? -1.0f : 1.0f; ray.org = ray.org + ray.tfar*ray.dir + sign*tnear_eps*brdf.dz; ray.dir = Vec3fa(wi); ray.tnear = 0.001f; ray.tfar = inf; ray.geomID = RTC_INVALID_GEOMETRY_ID; ray.primID = RTC_INVALID_GEOMETRY_ID; ray.mask = -1; ray.time = time; ray.filter = nullptr; weight = weight * c/wi.w; #else /* continue with transparency ray */ ray.geomID = RTC_INVALID_GEOMETRY_ID; ray.tnear = 1.001f*ray.tfar; ray.tfar = inf; weight *= brdf.Kt; #endif depth++; } return color; }
/* renders a single screen tile */ void renderTileStandard(int taskIndex, int* pixels, const int width, const int height, const float time, const ISPCCamera& camera, 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); RTCRay rays[TILE_SIZE_X*TILE_SIZE_Y]; /* generate stream of primary rays */ int N = 0; for (int y=y0; y<y1; y++) for (int x=x0; x<x1; x++) { /* ISPC workaround for mask == 0 */ if (all(1 == 0)) continue; RandomSampler sampler; RandomSampler_init(sampler, x, y, 0); /* initialize ray */ RTCRay& ray = rays[N++]; ray.org = Vec3fa(camera.xfm.p); ray.dir = Vec3fa(normalize(x*camera.xfm.l.vx + y*camera.xfm.l.vy + camera.xfm.l.vz)); bool mask = 1; { // invalidates inactive rays ray.tnear = mask ? 0.0f : (float)(pos_inf); ray.tfar = mask ? (float)(inf) : (float)(neg_inf); } ray.geomID = RTC_INVALID_GEOMETRY_ID; ray.primID = RTC_INVALID_GEOMETRY_ID; ray.mask = -1; ray.time = RandomSampler_get1D(sampler); } RTCIntersectContext context; context.flags = RAYN_FLAGS; /* trace stream of rays */ #if USE_INTERFACE == 0 rtcIntersect1M(g_scene,&context,rays,N,sizeof(RTCRay)); #elif USE_INTERFACE == 1 for (size_t i=0; i<N; i++) rtcIntersect(g_scene,rays[i]); #else for (size_t i=0; i<N; i++) rtcIntersect1M(g_scene,&context,&rays[i],1,sizeof(RTCRay)); #endif /* shade stream of rays */ N = 0; for (int y=y0; y<y1; y++) for (int x=x0; x<x1; x++) { /* ISPC workaround for mask == 0 */ if (all(1 == 0)) continue; RTCRay& ray = rays[N++]; /* eyelight shading */ Vec3fa color = Vec3fa(0.0f); if (ray.geomID != RTC_INVALID_GEOMETRY_ID) //color = Vec3fa(abs(dot(ray.dir,normalize(ray.Ng)))); color = ambientOcclusionShading(x,y,ray); /* write color to framebuffer */ unsigned int r = (unsigned int) (255.0f * clamp(color.x,0.0f,1.0f)); unsigned int g = (unsigned int) (255.0f * clamp(color.y,0.0f,1.0f)); unsigned int b = (unsigned int) (255.0f * clamp(color.z,0.0f,1.0f)); pixels[y*width+x] = (b << 16) + (g << 8) + r; } }
/* renders a single pixel casting with ambient occlusion */ Vec3fa ambientOcclusionShading(int x, int y, RTCRay& ray) { RTCRay rays[AMBIENT_OCCLUSION_SAMPLES]; Vec3fa Ng = normalize(ray.Ng); if (dot(ray.dir,Ng) > 0.0f) Ng = neg(Ng); Vec3fa col = Vec3fa(min(1.0f,0.3f+0.8f*abs(dot(Ng,normalize(ray.dir))))); /* calculate hit point */ float intensity = 0; Vec3fa hitPos = ray.org + ray.tfar * ray.dir; RandomSampler sampler; RandomSampler_init(sampler,x,y,0); /* enable only valid rays */ for (int i=0; i<AMBIENT_OCCLUSION_SAMPLES; i++) { /* sample random direction */ Vec2f s = RandomSampler_get2D(sampler); Sample3f dir; dir.v = cosineSampleHemisphere(s); dir.pdf = cosineSampleHemispherePDF(dir.v); dir.v = frame(Ng) * dir.v; /* initialize shadow ray */ RTCRay& shadow = rays[i]; shadow.org = hitPos; shadow.dir = dir.v; bool mask = 1; { // invalidate inactive rays shadow.tnear = mask ? 0.001f : (float)(pos_inf); shadow.tfar = mask ? (float)(inf) : (float)(neg_inf); } shadow.geomID = RTC_INVALID_GEOMETRY_ID; shadow.primID = RTC_INVALID_GEOMETRY_ID; shadow.mask = -1; shadow.time = 0; // FIXME: invalidate inactive rays } RTCIntersectContext context; context.flags = RAYN_FLAGS; /* trace occlusion rays */ #if USE_INTERFACE == 0 rtcOccluded1M(g_scene,&context,rays,AMBIENT_OCCLUSION_SAMPLES,sizeof(RTCRay)); #elif USE_INTERFACE == 1 for (size_t i=0; i<AMBIENT_OCCLUSION_SAMPLES; i++) rtcOccluded(g_scene,rays[i]); #else for (size_t i=0; i<AMBIENT_OCCLUSION_SAMPLES; i++) rtcOccluded1M(g_scene,&context,&rays[i],1,sizeof(RTCRay)); #endif /* accumulate illumination */ for (int i=0; i<AMBIENT_OCCLUSION_SAMPLES; i++) { if (rays[i].geomID == RTC_INVALID_GEOMETRY_ID) intensity += 1.0f; } /* shade pixel */ return col * (intensity/AMBIENT_OCCLUSION_SAMPLES); }