reflected.currentMaterial = ray.prevMaterial;
getDirectLightAttenuation(scene, reflected, state);
Vector4d attenuation = state.attenuation;
if (attenuation.w > 0) {
double mult = QuickMath.abs(reflected.d.dot(ray.n));
directLightR = attenuation.x*attenuation.w * mult;
directLightG = attenuation.y*attenuation.w * mult;
directLightB = attenuation.z*attenuation.w * mult;
ray.hit = true;
}
}
reflected.diffuseReflection(ray, random);
pathTrace(scene, reflected, state, 0, false);
ray.hit = ray.hit || reflected.hit;
if (ray.hit) {
ray.color.x = ray.color.x
* (emittance + directLightR * scene.sun.emittance.x
+ (reflected.color.x + reflected.emittance.x));
ray.color.y = ray.color.y
* (emittance + directLightG * scene.sun.emittance.y
+ (reflected.color.y + reflected.emittance.y));
ray.color.z = ray.color.z
* (emittance + directLightB * scene.sun.emittance.z
+ (reflected.color.z + reflected.emittance.z));
}
} else {
reflected.diffuseReflection(ray, random);
pathTrace(scene, reflected, state, 0, false);
ray.hit = ray.hit || reflected.hit;
if (ray.hit) {
ray.color.x = ray.color.x
* (emittance + (reflected.color.x + reflected.emittance.x));
ray.color.y = ray.color.y
* (emittance + (reflected.color.y + reflected.emittance.y));
ray.color.z = ray.color.z
* (emittance + (reflected.color.z + reflected.emittance.z));
}
}
}
} else if (n1 != n2) {
boolean doRefraction =
currentBlock == Block.WATER ||
prevBlock == Block.WATER ||
currentBlock == Block.ICE ||
prevBlock == Block.ICE;
// refraction
float n1n2 = n1 / n2;
double cosTheta = - ray.n.dot(ray.d);
double radicand = 1 - n1n2*n1n2 * (1 - cosTheta*cosTheta);
if (doRefraction && radicand < Ray.EPSILON) {
// total internal reflection
reflected.specularReflection(ray);
if (!scene.kill(reflected, random)) {
pathTrace(scene, reflected, state, 1, false);
if (reflected.hit) {
ray.color.x = reflected.color.x;
ray.color.y = reflected.color.y;
ray.color.z = reflected.color.z;
ray.hit = true;
}
}
} else {
refracted.set(ray);
if (!scene.kill(refracted, random)) {
// Calculate angle-dependent reflectance using
// Fresnel equation approximation
// R(theta) = R0 + (1 - R0) * (1 - cos(theta))^5
float a = (n1n2 - 1);
float b = (n1n2 + 1);
double R0 = a*a/(b*b);
double c = 1 - cosTheta;
double Rtheta = R0 + (1-R0) * c*c*c*c*c;
if (random.nextDouble() < Rtheta) {
reflected.specularReflection(ray);
pathTrace(scene, reflected, state, 1, false);
if (reflected.hit) {
ray.color.x = reflected.color.x;
ray.color.y = reflected.color.y;
ray.color.z = reflected.color.z;
ray.hit = true;
}
} else {
if (doRefraction) {
double t2 = FastMath.sqrt(radicand);
if (cosTheta > 0) {
refracted.d.x = n1n2*ray.d.x + (n1n2*cosTheta - t2)*ray.n.x;
refracted.d.y = n1n2*ray.d.y + (n1n2*cosTheta - t2)*ray.n.y;
refracted.d.z = n1n2*ray.d.z + (n1n2*cosTheta - t2)*ray.n.z;
} else {
refracted.d.x = n1n2*ray.d.x - (-n1n2*cosTheta - t2)*ray.n.x;
refracted.d.y = n1n2*ray.d.y - (-n1n2*cosTheta - t2)*ray.n.y;
refracted.d.z = n1n2*ray.d.z - (-n1n2*cosTheta - t2)*ray.n.z;
}
refracted.d.normalize();
refracted.x.scaleAdd(Ray.OFFSET,
refracted.d, refracted.x);
}
pathTrace(scene, refracted, state, 1, false);
if (refracted.hit) {
ray.color.x = ray.color.x * pDiffuse + (1-pDiffuse);
ray.color.y = ray.color.y * pDiffuse + (1-pDiffuse);
ray.color.z = ray.color.z * pDiffuse + (1-pDiffuse);
ray.color.x *= refracted.color.x;
ray.color.y *= refracted.color.y;
ray.color.z *= refracted.color.z;
ray.hit = true;
}
}
}
}
} else {
transmitted.set(ray);
transmitted.x.scaleAdd(Ray.OFFSET, transmitted.d,
transmitted.x);
pathTrace(scene, transmitted, state, 1, false);
if (transmitted.hit) {
ray.color.x = ray.color.x * pDiffuse + (1-pDiffuse);
ray.color.y = ray.color.y * pDiffuse + (1-pDiffuse);
ray.color.z = ray.color.z * pDiffuse + (1-pDiffuse);
ray.color.x *= transmitted.color.x;
ray.color.y *= transmitted.color.y;
ray.color.z *= transmitted.color.z;
ray.hit = true;
}
}
}
// do water fog
if (!scene.clearWater && prevBlock == Block.WATER) {
double a = ray.distance / scene.waterVisibility;
double attenuation = 1 - QuickMath.min(1, a*a);
ray.color.scale(attenuation);
/*ray.color.x *= attenuation;
ray.color.y *= attenuation;
ray.color.z *= attenuation;
float[] wc = Texture.water.getAvgColorLinear();
ray.color.x += (1-attenuation) * wc[0];
ray.color.y += (1-attenuation) * wc[1];
ray.color.z += (1-attenuation) * wc[2];
ray.color.w = attenuation;*/
ray.hit = true;
}
break;
}
if (!ray.hit) {
ray.color.set(0, 0, 0, 1);
if (first)
s = ray.distance;
}
if (s > 0) {
if (scene.atmosphereEnabled) {
double Fex = scene.sun.extinction(s);
ray.color.x *= Fex;
ray.color.y *= Fex;
ray.color.z *= Fex;
if (!scene.volumetricFogEnabled) {
double Fin = scene.sun.inscatter(Fex, scene.sun.theta(ray.d));
ray.color.x += Fin * scene.sun.emittance.x * scene.sun.getIntensity();
ray.color.y += Fin * scene.sun.emittance.y * scene.sun.getIntensity();
ray.color.z += Fin * scene.sun.emittance.z * scene.sun.getIntensity();
}
}
if (scene.volumetricFogEnabled) {
s = (s - Ray.OFFSET) * random.nextDouble();
reflected.x.scaleAdd(s, od, ox);
scene.sun.getRandomSunDirection(reflected, random, state.vectorPool);
reflected.currentMaterial = 0;
getDirectLightAttenuation(scene, reflected, state);
Vector4d attenuation = state.attenuation;
double Fex = scene.sun.extinction(s);
double Fin = scene.sun.inscatter(Fex, scene.sun.theta(ray.d));
ray.color.x += 50 * attenuation.x*attenuation.w * Fin * scene.sun.emittance.x * scene.sun.getIntensity();