inline Vec3fa AnisotropicBlinn__eval(const AnisotropicBlinn* This, const Vec3fa& wo, const Vec3fa& wi) { const float cosThetaI = dot(wi,This->dz); /* reflection */ if (cosThetaI > 0.0f) { const Vec3fa wh = normalize(wi + wo); return This->Kr * AnisotropicBlinn__eval(This,wh) * abs(cosThetaI); } /* transmission */ else { const Vec3fa wh = normalize(reflect(wi,This->dz) + wo); return This->Kt * AnisotropicBlinn__eval(This,wh) * abs(cosThetaI); } }
inline Vec3fa AnisotropicBlinn__sample(const AnisotropicBlinn* This, const Vec3fa& wo, Vec3fa& wi, const float sx, const float sy, const float sz) { //wi = Vec3fa(reflect(normalize(wo),normalize(dz)),1.0f); return Kr; //wi = Vec3fa(neg(wo),1.0f); return Kt; const Vec3fa wh = AnisotropicBlinn__sample(This,sx,sy); //if (dot(wo,wh) < 0.0f) return Vec3fa(0.0f,0.0f); /* reflection */ if (sz < This->side) { wi = Vec3fa(reflect(wo,Vec3fa(wh)),wh.w*This->side); const float cosThetaI = dot(Vec3fa(wi),This->dz); return This->Kr * AnisotropicBlinn__eval(This,Vec3fa(wh)) * abs(cosThetaI); } /* transmission */ else { wi = Vec3fa(reflect(reflect(wo,Vec3fa(wh)),This->dz),wh.w*(1-This->side)); const float cosThetaI = dot(Vec3fa(wi),This->dz); return This->Kt * AnisotropicBlinn__eval(This,Vec3fa(wh)) * abs(cosThetaI); } }
/* 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; }
/* 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) { int seed = 21344*x+121233*y+234532*g_accu_count; float time = frand(seed); /* 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 = NULL; 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)); // FIXME: use (RTCRay&) cast /* 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; if (ray.geomID < g_ispc_scene->numHairSets) { /* 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 { int meshID = ray.geomID-g_ispc_scene->numHairSets; ISPCMesh* mesh = g_ispc_scene->meshes[meshID]; ISPCTriangle* triangle = &mesh->triangles[ray.primID]; ISPCMaterial* material = &g_ispc_scene->materials[triangle->materialID]; if (material->illum == 1) { /* calculate tangent space */ const Vec3fa dx = normalize(Vec3fa(mesh->normals[triangle->v0])); 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; tnear_eps = 1.1f*mesh->texcoords[triangle->v0].x; } else { 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); // FIXME: use += operator #if 1 /* sample BRDF */ Vec3fa wi; c = AnisotropicBlinn__sample(&brdf,neg(ray.dir),wi,frand(seed),frand(seed),frand(seed)); 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 = NULL; weight = weight * c/wi.w; // FIXME: use *= operator #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; }