RTRay RTRayTracer::genRefractRay(RTVector d, RTVector normal, RTVector closestPoint, double refractionIndex,bool isInside) { double n,nt,ni; if(isInside) { ni=refractionIndex; nt=AIR_REFRA; normal=-normal; } else { ni=AIR_REFRA; nt=refractionIndex; } n = ni / nt; double cosI = -normal.dot(d); double sinT2 = n * n * (1.0 - cosI * cosI); if (sinT2 > 1.0) { exit(EXIT_FAILURE); } double cosT = sqrt(1.0 - sinT2); RTVector refracVector= d * n + normal * (n * cosI - cosT); double bias = 1e-4; RTVector ori = (closestPoint-normal)*bias; // RTVector ori=closestPoint; RTPoint vertice(ori.getX(),ori.getY(),ori.getZ()); RTRay refracRay(vertice,refracVector); return refracRay; }
bool Scene::traceRay(Ray& ray, RenderOption option, float refractiveIndex, int level, Color* acc, HitInfo* hitInfo) { if (level > kMaxTraceLevel) { return false; } *acc = kColorBlack; if (m_rootGroup->hit(ray, hitInfo)) { Vector3 hitPosition = hitInfo->position; Vector3 hitNormal = hitInfo->normal; MaterialRef hitMaterial = hitInfo->material; if (option & RenderMaterialAmbience) { Color materialColor; if (hitMaterial->texture()) { materialColor = hitMaterial->texture()->texelAt(hitInfo->uv); } else { materialColor = hitMaterial->color(); } *acc += hitMaterial->ambient() * materialColor * (1.0f - hitMaterial->transparency()); } for (unsigned int i = 0; i < m_lights.size(); i++) { LightRef light = m_lights[i]; *acc += light->luminanceOfMaterialAt(*hitInfo, this, option) * (1.0f - hitMaterial->transparency()); if (option & RenderReflection) { if (hitMaterial->reflectivity() > 0.0f && level < kMaxTraceLevel) { float reflection = 2.0 * ray.direction().dot(hitNormal); Vector3 reflectionDirection = (ray.direction() - (hitNormal * reflection)).normalize(); Ray reflectedRay(hitPosition, reflectionDirection); HitInfo reflectionInfo; Color reflectedColor = kColorBlack; if (traceRay(reflectedRay, option, refractiveIndex, level + 1, &reflectedColor, &reflectionInfo)) { reflectedColor = reflectedColor * hitMaterial->reflectivity(); *acc += reflectedColor * (1.0f - hitMaterial->transparency()); } } } if (option & RenderTransparency) { if (hitMaterial->transparency() > 0.0f && level < kMaxTraceLevel) { float n = refractiveIndex / hitMaterial->refractiveIndex(); float cosA = -ray.direction().dot(hitNormal); float cosB = sqrtf(1.0f - n * n * (1 - cosA * cosA)); if (cosB > 0.0f) { Vector3 refracDirection = (n * ray.direction()) + (n * cosA - cosB) * hitNormal; Vector3 refracRayOrigin = hitPosition + refracDirection * EPSILON; Ray refracRay(refracRayOrigin, refracDirection); HitInfo refracInfo; Color refracColor = kColorBlack; if (traceRay(refracRay, option, refractiveIndex, level + 1, &refracColor, &refracInfo)) { refracColor = refracColor * hitMaterial->transparency(); Color absorbance = hitMaterial->color() * 0.15f * -refracInfo.distance; Color transparency = Color(expf(absorbance.red), expf(absorbance.green), expf(absorbance.blue)); refracColor = refracColor * transparency; *acc += refracColor; } } } } } } return true; }