Index: include/core_api/material.h =================================================================== --- include/core_api/material.h (revision 456) +++ include/core_api/material.h (working copy) @@ -85,6 +85,8 @@ */ 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;} + virtual float getIOR ()const{return 1.0;} + /*! 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! 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,7 @@ 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 getIOR (); 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) @@ -23,6 +23,7 @@ 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 getIOR (); virtual bool isTransparent() const; virtual color_t getTransparency(const renderState_t &state, const surfacePoint_t &sp, const vector3d_t &wo)const; virtual color_t volumeTransmittance(const renderState_t &state, const surfacePoint_t &sp1, const surfacePoint_t &sp2) 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; //!getIOR(); +} bool maskMat_t::isTransparent() const { Index: src/materials/blendmat.cc =================================================================== --- src/materials/blendmat.cc (revision 456) +++ src/materials/blendmat.cc (working copy) @@ -171,6 +171,11 @@ return pdf; } +float blendMat_t::getIOR() +{ + return (mat1->getIOR()+mat2->getIOR())/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) @@ -43,7 +43,17 @@ virtual bool volumeTransmittance(const renderState_t &state, const surfacePoint_t &sp, const ray_t &ray, color_t &col)const; // virtual bool scatterPhoton(const renderState_t &state, const surfacePoint_t &sp, const vector3d_t &wi, vector3d_t &wo, pSample_t &s) const; static material_t* factory(paraMap_t &, std::list< paraMap_t > &, renderEnvironment_t &); + virtual PFLOAT getIOR()const{return ior;} protected: + inline PFLOAT getCurrentChromaticIOR (const renderState_t &state, const surfacePoint_t &sp) const + { + return yafaray::getIOR(state.wavelength, CauchyA, CauchyB)/sp.previousIOR; + } + inline PFLOAT getCurrentIOR (const surfacePoint_t &sp) const + { + return ior/sp.previousIOR; + } + shaderNode_t* bumpS; shaderNode_t *mirColS; color_t filterCol, specRefCol; @@ -104,7 +114,7 @@ // we need to sample dispersion if(disperse && state.chromatic) { - PFLOAT cur_ior = getIOR(state.wavelength, CauchyA, CauchyB); + PFLOAT cur_ior = getCurrentChromaticIOR (state, sp); if( refract(N, wo, refdir, cur_ior) ) { CFLOAT Kr, Kt; @@ -138,11 +148,11 @@ } else // no dispersion calculation necessary, regardless of material settings { - PFLOAT cur_ior = disperse ? getIOR(state.wavelength, CauchyA, CauchyB) : ior; + PFLOAT cur_ior = disperse ? getCurrentChromaticIOR(state, sp) : getCurrentIOR(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)) { @@ -188,9 +198,10 @@ color_t glassMat_t::getTransparency(const renderState_t &state, const surfacePoint_t &sp, const vector3d_t &wo)const { + PFLOAT cur_ior = getCurrentIOR(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; } @@ -218,7 +229,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 ? getCurrentChromaticIOR(state, sp): getCurrentIOR(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 @@ -704,6 +705,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; @@ -711,23 +713,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->getIOR(); + } + } + 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); }