Index: include/core_api/material.h =================================================================== --- include/core_api/material.h (revision 456) +++ include/core_api/material.h (working copy) @@ -85,6 +85,7 @@ */ virtual float pdf(const renderState_t &state, const surfacePoint_t &sp, const vector3d_t &wo, const vector3d_t &wi, BSDF_t bsdfs)const {return 0.f;} + /*! indicate whether light can (partially) pass the material without getting refracted, e.g. a curtain or even very thin foils approximated as single non-refractive layer. used to trace transparent shadows. Note that in this case, initBSDF was NOT called before! @@ -135,9 +136,13 @@ returns the required amount of "userdata" memory for all the functions that require a render state */ size_t getReqMem() const { return reqMem; } - /*! Get materials IOR (for refracted photons) */ + /*! Get materials IOR (For material interfaces) */ + virtual float getMatIOR () const { return 1.5f; } + + /*! Get materials IOR (for refraction, takes into account the IOR of adjoining surface) */ - virtual float getMatIOR() const { return 1.5f; } + virtual float getEffectiveIOR(const renderState_t &state, const surfacePoint_t &sp) const { return 1.5f; } + virtual float getEffectiveChromaticIOR (const renderState_t &state, const surfacePoint_t &sp) const { return 1.5f; } protected: /* small function to apply bump mapping to a surface point Index: include/core_api/surface.h =================================================================== --- include/core_api/surface.h (revision 456) +++ include/core_api/surface.h (working copy) @@ -121,6 +121,8 @@ //GFLOAT dudNV; //GFLOAT dvdNU; //GFLOAT dvdNV; + // + PFLOAT previousIOR; //!< In the case of two meshes being back to back, this is the IOR of the other mesh }; /*! computes and stores the additional data for surface intersections for Index: include/materials/maskmat.h =================================================================== --- include/materials/maskmat.h (revision 456) +++ include/materials/maskmat.h (working copy) @@ -17,6 +17,9 @@ virtual color_t eval(const renderState_t &state, const surfacePoint_t &sp, const vector3d_t &wo, const vector3d_t &wi, BSDF_t bsdfs)const; virtual color_t sample(const renderState_t &state, const surfacePoint_t &sp, const vector3d_t &wo, vector3d_t &wi, sample_t &s)const; virtual float pdf(const renderState_t &state, const surfacePoint_t &sp, const vector3d_t &wo, const vector3d_t &wi, BSDF_t bsdfs)const; + virtual float getMatIOR () const; + virtual float getEffectiveIOR(const renderState_t &state, const surfacePoint_t &sp) const; + virtual float getEffectiveChromaticIOR (const renderState_t &state, const surfacePoint_t &sp) const; virtual bool isTransparent() const; virtual color_t getTransparency(const renderState_t &state, const surfacePoint_t &sp, const vector3d_t &wo)const; virtual void getSpecular(const renderState_t &state, const surfacePoint_t &sp, const vector3d_t &wo, Index: include/materials/blendmat.h =================================================================== --- include/materials/blendmat.h (revision 456) +++ include/materials/blendmat.h (working copy) @@ -24,6 +24,9 @@ virtual color_t eval(const renderState_t &state, const surfacePoint_t &sp, const vector3d_t &wo, const vector3d_t &wl, BSDF_t bsdfs)const; virtual color_t sample(const renderState_t &state, const surfacePoint_t &sp, const vector3d_t &wo, vector3d_t &wi, sample_t &s)const; virtual float pdf(const renderState_t &state, const surfacePoint_t &sp, const vector3d_t &wo, const vector3d_t &wi, BSDF_t bsdfs)const; + virtual float getMatIOR ()const; + virtual float getEffectiveIOR(const renderState_t &state, const surfacePoint_t &sp) const; + virtual float getEffectiveChromaticIOR (const renderState_t &state, const surfacePoint_t &sp) const; virtual bool isTransparent() const; virtual color_t getTransparency(const renderState_t &state, const surfacePoint_t &sp, const vector3d_t &wo)const; virtual bool volumeTransmittance(const renderState_t &state, const surfacePoint_t &sp, const ray_t &ray, color_t &col)const; Index: include/yafraycore/kdtree.h =================================================================== --- include/yafraycore/kdtree.h (revision 456) +++ include/yafraycore/kdtree.h (working copy) @@ -128,8 +128,31 @@ { public: triKdTree_t(const triangle_t **v, int np, int depth=-1, int leafSize=2, - float cost_ratio=0.35, float emptyBonus=0.33); - bool Intersect(const ray_t &ray, PFLOAT dist, triangle_t **tr, PFLOAT &Z, void *udat) const; + float cost_ratio=0.35, float emptyBonus=0.33, double doubleIntersectDistance = 0.0001); + struct intersectData_t + { + triangle_t *tr; + PFLOAT Z; + void *udat; + }; + struct intersectDataPair_t + { + intersectData_t data[3]; + unsigned char udat[3][PRIM_DAT_SIZE]; + intersectData_t *first, *second, *spare; + intersectDataPair_t() + { + first = &data[0]; + second = &data[1]; + spare = &data[2]; + for (int i = 0; i < 3; i++) + data[i].udat = udat[i]; + } + }; + + + int Intersect(const ray_t &ray, PFLOAT dist, intersectDataPair_t * intersectPair) const; //!getMatIOR()); + spDiff.refractedRay(ray, refRay, material->getEffectiveIOR(state,sp)); colorA_t integ = integrate(state, refRay); if((bsdfs&BSDF_VOLUMETRIC) && material->volumeTransmittance(state, sp, refRay, vcol)) integ *= vcol; Index: src/materials/maskmat.cc =================================================================== --- src/materials/maskmat.cc (revision 456) +++ src/materials/maskmat.cc (working copy) @@ -81,7 +81,22 @@ state.userdata = PTR_ADD(state.userdata, -sizeof(bool)); return pdf; } + //The following 3 funcs ignore the 2nd material, but masking between different IORs doesn't make sense anyway, because the mask only applies + //to the surface whereas refracton in real life depends on the IOR throughout the material, not just at the surface +float maskMat_t::getMatIOR() const +{ + return mat1->getMatIOR(); +} +float maskMat_t::getEffectiveIOR(const renderState_t &state, const surfacePoint_t &sp) const +{ + return mat1->getEffectiveIOR(state,sp); +} +float maskMat_t::getEffectiveChromaticIOR(const renderState_t &state, const surfacePoint_t &sp) const +{ + return mat1->getEffectiveChromaticIOR(state,sp); +} + bool maskMat_t::isTransparent() const { return mat1->isTransparent() || mat2->isTransparent(); Index: src/materials/blendmat.cc =================================================================== --- src/materials/blendmat.cc (revision 456) +++ src/materials/blendmat.cc (working copy) @@ -213,6 +213,19 @@ return pdf1; } +float blendMat_t::getMatIOR() const +{ + return (mat1->getMatIOR()+mat2->getMatIOR())/2.0; +} +float blendMat_t::getEffectiveIOR(const renderState_t &state, const surfacePoint_t &sp) const +{ + return (mat1->getEffectiveIOR(state,sp)+mat2->getEffectiveIOR(state,sp))/2.0; +} +float blendMat_t::getEffectiveChromaticIOR(const renderState_t &state, const surfacePoint_t &sp) const +{ + return (mat1->getEffectiveChromaticIOR(state,sp)+mat2->getEffectiveChromaticIOR(state,sp))/2.0; +} + bool blendMat_t::isTransparent() const { return mat1->isTransparent() || mat2->isTransparent(); Index: src/materials/glass.cc =================================================================== --- src/materials/glass.cc (revision 456) +++ src/materials/glass.cc (working copy) @@ -42,7 +42,17 @@ virtual bool volumeTransmittance(const renderState_t &state, const surfacePoint_t &sp, const ray_t &ray, color_t &col)const; virtual float getMatIOR() const; static material_t* factory(paraMap_t &, std::list< paraMap_t > &, renderEnvironment_t &); + virtual PFLOAT getIOR()const{return ior;} protected: + virtual float getEffectiveChromaticIOR (const renderState_t &state, const surfacePoint_t &sp) const + { + return yafaray::getIOR(state.wavelength, CauchyA, CauchyB)/sp.previousIOR; + } + virtual float getEffectiveIOR (const surfacePoint_t &sp) const + { + return ior/sp.previousIOR; + } + shaderNode_t* bumpS; shaderNode_t *mirColS; color_t filterCol, specRefCol; @@ -103,7 +113,7 @@ // we need to sample dispersion if(disperse && state.chromatic) { - PFLOAT cur_ior = getIOR(state.wavelength, CauchyA, CauchyB); + PFLOAT cur_ior = getEffectiveChromaticIOR (state, sp); if( refract(N, wo, refdir, cur_ior) ) { CFLOAT Kr, Kt; @@ -137,11 +147,11 @@ } else // no dispersion calculation necessary, regardless of material settings { - PFLOAT cur_ior = disperse ? getIOR(state.wavelength, CauchyA, CauchyB) : ior; + PFLOAT cur_ior = disperse ? getEffectiveChromaticIOR(state, sp) : getEffectiveIOR(sp); if( refract(N, wo, refdir, cur_ior) ) { CFLOAT Kr, Kt; - fresnel(wo, N, ior, Kr, Kt); + fresnel(wo, N, cur_ior, Kr, Kt); float pKr = 0.01+0.99*Kr, pKt = 0.01+0.99*Kt; if(s.s1 < pKt && matches(s.flags, tmFlags)) { @@ -187,9 +197,10 @@ color_t glassMat_t::getTransparency(const renderState_t &state, const surfacePoint_t &sp, const vector3d_t &wo)const { + PFLOAT cur_ior = getEffectiveIOR(sp); vector3d_t N = FACE_FORWARD(sp.Ng, sp.N, wo); CFLOAT Kr, Kt; - fresnel(wo, N, ior, Kr, Kt); + fresnel(wo, N, cur_ior, Kr, Kt); return Kt*filterCol; } @@ -217,7 +228,7 @@ // vector3d_t N = FACE_FORWARD(sp.Ng, sp.N, wo); vector3d_t refdir; - PFLOAT cur_ior = disperse ? getIOR(state.wavelength, CauchyA, CauchyB) : ior; + PFLOAT cur_ior = disperse ? getEffectiveChromaticIOR(state, sp): getEffectiveIOR(sp); if( refract(N, wo, refdir, cur_ior) ) { CFLOAT Kr, Kt; Index: src/yafraycore/scene.cc =================================================================== --- src/yafraycore/scene.cc (revision 456) +++ src/yafraycore/scene.cc (working copy) @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -851,6 +852,7 @@ bool scene_t::intersect(const ray_t &ray, surfacePoint_t &sp) const { PFLOAT dis, Z; + int numOfIntersects = 0; unsigned char udat[PRIM_DAT_SIZE]; if(ray.tmax<0) dis=std::numeric_limits::infinity(); else dis=ray.tmax; @@ -858,23 +860,57 @@ if(mode == 0) { if(!tree) return false; - triangle_t *hitt=0; - if( ! tree->Intersect(ray, dis, &hitt, Z, (void*)&udat[0]) ){ return false; } - point3d_t h=ray.from + Z*ray.dir; - hitt->getSurface(sp, h, (void*)&udat[0]); - sp.origin = hitt; + + //TODO - this doesn't need to be initialized everytime, but static wouldn't be threadsafe, thread local storage would work + triKdTree_t::intersectDataPair_t intersectPair; + + numOfIntersects = tree->Intersect(ray, dis, &intersectPair); + if (numOfIntersects == 0) + return 0; + + surfacePoint_t otherSp; + point3d_t h=ray.from + intersectPair.first->Z*ray.dir; + intersectPair.first->tr->getSurface(sp, h, intersectPair.first->udat); + sp.origin = intersectPair.first->tr; + if (numOfIntersects == 2) + { + point3d_t h=ray.from + intersectPair.second->Z*ray.dir; + intersectPair.second->tr->getSurface(otherSp, h, intersectPair.second->udat); + otherSp.origin = intersectPair.second->tr; + if (std::abs (-1.0 - (sp.Ng * otherSp.Ng)) > 0.001) + numOfIntersects = 1; //ignore the second one as they're not really coplanar + else + { + if(ray.dir*sp.Ng > ray.dir*otherSp.Ng) + { + std::swap(sp,otherSp); + Z = intersectPair.second->Z; + } + else + Z = intersectPair.first->Z; + + sp.previousIOR = otherSp.material->getMatIOR(); + } + } + if (numOfIntersects == 1) + { + Z = intersectPair.first->Z; + sp.previousIOR = 1.0; + } } else { + //TODO - multiple intersects for primitive trees as well if(!vtree) return false; primitive_t *hitprim=0; if( ! vtree->Intersect(ray, dis, &hitprim, Z, (void*)&udat[0]) ){ return false; } + numOfIntersects = 1; point3d_t h=ray.from + Z*ray.dir; hitprim->getSurface(sp, h, (void*)&udat[0]); sp.origin = hitprim; } ray.tmax = Z; - return true; + return numOfIntersects > 0; } bool scene_t::isShadowed(renderState_t &state, const ray_t &ray) const Index: src/yafraycore/kdtree.cc =================================================================== --- src/yafraycore/kdtree.cc (revision 456) +++ src/yafraycore/kdtree.cc (working copy) @@ -62,8 +62,8 @@ //int triBoxClip(const double b_min[3], const double b_max[3], const double triverts[3][3], bound_t &box); triKdTree_t::triKdTree_t(const triangle_t **v, int np, int depth, int leafSize, - float cost_ratio, float emptyBonus) - : costRatio(cost_ratio), eBonus(emptyBonus), maxDepth(depth) + float cost_ratio, float emptyBonus, double doubleIntersectDistance) + : costRatio(cost_ratio), eBonus(emptyBonus), maxDepth(depth), doubleIntersectDistance(doubleIntersectDistance) { std::cout << "starting build of kd-tree ("<= 1) + { + *tr = intersectPair.first->tr; + Z = intersectPair.first->Z; + memcpy (udat,intersectPair.first->udat,PRIM_DAT_SIZE); + return true; + } + return false; +} +//============================ +/*! The double intersect function, + returns one or two intersect points in intersectPair. The second intersect point is only included if + it is less the doubleIntersectDistance from the first intersection. +*/ + +int triKdTree_t::Intersect(const ray_t &ray, PFLOAT dist, intersectDataPair_t * intersectPair) const +{ + intersectData_t * & first = intersectPair->first; + intersectData_t * & second = intersectPair->second; + intersectData_t * & spare = intersectPair->spare; + first->Z = dist; + second->Z = dist; // std::cout << "kdTree_t::Intersect: Z="<onePrimitive; // if (mp->lastMailboxId != rayId) { // mp->lastMailboxId = rayId; - if (mp->intersect(ray, &t_hit, t_udat)) + if (hit == 0 || (hit == 1 && mp != first->tr) || (hit == 2 && mp != first->tr && mp != second->tr)) + { + if (mp->intersect(ray, &spare->Z, spare->udat) && spare->Z >= ray.tmin) { // std::cout<<"kdTree_t: hit! t="<= ray.tmin /*0.f*/ /*stack[enPt].t*/) + if(spare->Z < first->Z/*0.f*/ /*stack[enPt].t*/) { - Z = t_hit; - *tr = mp; - std::swap(t_udat, c_udat); - hit = true; + spare->tr = mp; + std::swap(spare, second); + std::swap(second, first); + hit++; } + else if (spare->Z < second->Z) + { + spare->tr = mp; + std::swap(spare, second); + hit++; + } } + } // } } else { triangle_t **prims = currNode->primitives; - for (u_int32 i = 0; i < nPrimitives; ++i) { - triangle_t *mp = prims[i]; + for (u_int32 i = 0; i < nPrimitives; ++i,++prims) { + triangle_t *mp = *prims; // if (mp->lastMailboxId != rayId) { // mp->lastMailboxId = rayId; - if (mp->intersect(ray, &t_hit, t_udat)) + if (hit == 0 || (hit == 1 && mp != first->tr) || (hit == 2 && mp != first->tr && mp != second->tr)) + { + if (mp->intersect(ray, &spare->Z, spare->udat) && spare->Z >= ray.tmin) { -// std::cout<<"kdTree_t: hit! t="<= ray.tmin /*0.f*/ /*stack[enPt].t*/) + // std::cout<<"kdTree_t: hit! t="<Z < first->Z/*0.f*/ /*stack[enPt].t*/) { - Z = t_hit; - *tr = mp; - std::swap(t_udat, c_udat); - hit = true; + spare->tr = mp; + std::swap(spare, second); + std::swap(second, first); + hit++; } + else if (spare->Z < second->Z) + { + spare->tr = mp; + std::swap(spare, second); + hit++; + } } + } // } } } + + if (hit>=1) + { + if ((hit != 0 && first->Z <= stack[exPt].t - doubleIntersectDistance ) || (hit == 2 && second->Z <= stack[exPt].t)) + { + if (hit == 1 || second->Z - first->Z > doubleIntersectDistance) + return 1; + else + return 2; + } + + dist = std::min(dist,first->Z + doubleIntersectDistance); + } - if(hit && Z <= stack[exPt].t){ memcpy(udat, c_udat, PRIM_DAT_SIZE); return true;} - enPt = exPt; currNode = stack[exPt].node; exPt = stack[enPt].prev; } // while -// if(hit) return true; - memcpy(udat, c_udat, PRIM_DAT_SIZE); - return hit; //false; + + return std::min(2,hit); }