GLUSvoid GLUSAPIENTRY glusVector3Refractf(GLUSfloat result[3], const GLUSfloat incident[3], const GLUSfloat normal[3], const float eta) { // see http://www.opengl.org/sdk/docs/manglsl/xhtml/refract.xml // see http://en.wikipedia.org/wiki/Snell%27s_law // see http://www.hugi.scene.org/online/coding/hugi%2023%20-%20torefrac.htm for a and b vector. // In this implementation, the incident vector points into the interface. So the sings do change. GLUSfloat nDotI = glusVector3Dotf(normal, incident); GLUSfloat k = 1.0f - eta * eta * (1.0f - nDotI * nDotI); if (k < 0.0f) { result[0] = 0.0f; result[1] = 0.0f; result[2] = 0.0f; } else { GLUSfloat a[3]; GLUSfloat b[3]; glusVector3MultiplyScalarf(a, incident, eta); glusVector3MultiplyScalarf(b, normal, eta * nDotI + sqrtf(k)); glusVector3SubtractVector3f(result, a, b); } }
GLUSfloat GLUSAPIENTRY glusVector3Fresnelf(const GLUSfloat incident[3], const GLUSfloat normal[3], const GLUSfloat R0) { // see http://en.wikipedia.org/wiki/Schlick%27s_approximation GLUSfloat negIncident[3]; glusVector3MultiplyScalarf(negIncident, incident, -1.0f); return R0 + (1.0f - R0) * powf(1.0f - glusVector3Dotf(negIncident, normal), 5.0f); }
GLUSboolean GLUSAPIENTRY glusVector3GramSchmidtOrthof(GLUSfloat result[3], const GLUSfloat u[3], const GLUSfloat v[3]) { GLUSfloat uProjV[3]; GLUSfloat vDotU; GLUSfloat uDotU = glusVector3Dotf(u, u); if (uDotU == 0.0f) { return GLUS_FALSE; } vDotU = glusVector3Dotf(v, u); uProjV[0] = u[0] * vDotU / uDotU; uProjV[1] = u[1] * vDotU / uDotU; uProjV[2] = u[2] * vDotU / uDotU; glusVector3SubtractVector3f(result, v, uProjV); return GLUS_TRUE; }
GLUSvoid GLUSAPIENTRY glusPlaneCreatef(GLUSfloat result[4], const GLUSfloat point[4], const GLUSfloat normal[3]) { GLUSfloat normalized[3]; glusVector3Copyf(normalized, normal); glusVector3Normalizef(normalized); result[0] = normalized[0]; result[1] = normalized[1]; result[2] = normalized[2]; // D = -N*P result[3] = -glusVector3Dotf(normalized, point); }
GLUSvoid GLUSAPIENTRY glusVector2Reflectf(GLUSfloat result[2], const GLUSfloat incident[2], const GLUSfloat normal[2]) { glusVector2MultiplyScalarf(result, normal, 2.0f * glusVector3Dotf(normal, incident)); glusVector2SubtractVector2f(result, incident, result); }
static GLvoid march(GLfloat pixelColor[4], const GLfloat rayPosition[4], const GLfloat rayDirection[3], const GLint depth) { GLint i, k, m, o; Primitive* primitiveNear = 0; GLfloat marchPosition[4]; GLfloat marchDirection[3]; GLfloat hitPosition[4]; GLfloat hitDirection[3]; GLfloat eyeDirection[3]; GLfloat t = 0.0f; // pixelColor[0] = 0.0f; pixelColor[1] = 0.0f; pixelColor[2] = 0.0f; pixelColor[3] = 1.0f; // for (i = 0; i < MAX_STEPS; i++) { GLfloat distance = INFINITY; GLfloat currentDistance; Primitive* closestPrimitive = 0; glusVector3MultiplyScalarf(marchDirection, rayDirection, t); glusPoint4AddVector3f(marchPosition, rayPosition, marchDirection); for (k = 0; k < NUM_SPHERES + NUM_BOXES; k++) { Primitive* currentPrimitive = &g_allPrimitives[k]; currentDistance = currentPrimitive->distanceFunction(marchPosition, currentPrimitive); if (currentDistance < distance) { distance = currentDistance; closestPrimitive = currentPrimitive; } } if (distance < EPSILON) { GLfloat samplePoints[4 * 6]; // Copy hit position ... glusPoint4Copyf(hitPosition, marchPosition); // ... and calculate normal by sampling around the hit position. for (k = 0; k < 6; k++) { samplePoints[k*4+0] = hitPosition[0]; samplePoints[k*4+1] = hitPosition[1]; samplePoints[k*4+2] = hitPosition[2]; samplePoints[k*4+3] = hitPosition[3]; samplePoints[k*4+k/2] += GAMMA * (k%2 == 0 ? 1.0f : -1.0f); } for (k = 0; k < 3; k++) { hitDirection[k] = closestPrimitive->distanceFunction(&samplePoints[k*2*4 + 0], closestPrimitive) - closestPrimitive->distanceFunction(&samplePoints[k*2*4 + 4], closestPrimitive); } glusVector3Normalizef(hitDirection); primitiveNear = closestPrimitive; break; } // If t is larger than a given distance, assume that there is the nothing. if (t > MAX_DISTANCE) { break; } t += distance; } // // No intersection, return background color / ambient light. if (!primitiveNear) { pixelColor[0] = 0.8f; pixelColor[1] = 0.8f; pixelColor[2] = 0.8f; return; } // glusVector3MultiplyScalarf(eyeDirection, rayDirection, -1.0f); // Diffuse and specular color for (i = 0; i < NUM_LIGHTS; i++) { PointLight* pointLight = &g_allLights[i]; GLboolean obstacle = GL_FALSE; GLfloat lightDirection[3]; GLfloat incidentLightDirection[3]; glusPoint4SubtractPoint4f(lightDirection, pointLight->position, hitPosition); glusVector3Normalizef(lightDirection); glusVector3MultiplyScalarf(incidentLightDirection, lightDirection, -1.0f); // Check for obstacles between current hit point surface and point light. for (k = 0; k < NUM_SPHERES + NUM_BOXES; k++) { Primitive* obstaclePrimitive = &g_allPrimitives[k]; if (obstaclePrimitive == primitiveNear) { continue; } t = 0.0f; for (m = 0; m < MAX_STEPS; m++) { GLfloat distance = INFINITY; GLfloat currentDistance; Primitive* closestPrimitive = 0; glusVector3MultiplyScalarf(marchDirection, lightDirection, -t); glusPoint4AddVector3f(marchPosition, pointLight->position, marchDirection); for (o = 0; o < NUM_SPHERES + NUM_BOXES; o++) { Primitive* currentPrimitive = &g_allPrimitives[o]; currentDistance = currentPrimitive->distanceFunction(marchPosition, currentPrimitive); if (currentDistance < distance && currentDistance >= 0.0f) { distance = currentDistance; closestPrimitive = currentPrimitive; } else if (currentDistance > distance && currentDistance < 0.0f) { distance = currentDistance; closestPrimitive = currentPrimitive; } } if (distance < EPSILON) { if (closestPrimitive != primitiveNear) { obstacle = GL_TRUE; } break; } if (t > MAX_DISTANCE) { break; } t += distance; } } // If no obstacle, illuminate hit point surface. if (!obstacle) { GLfloat diffuseIntensity = glusMathMaxf(0.0f, glusVector3Dotf(hitDirection, lightDirection)); if (diffuseIntensity > 0.0f) { GLfloat specularReflection[3]; GLfloat eDotR; pixelColor[0] = pixelColor[0] + diffuseIntensity * primitiveNear->material.diffuseColor[0] * pointLight->color[0]; pixelColor[1] = pixelColor[1] + diffuseIntensity * primitiveNear->material.diffuseColor[1] * pointLight->color[1]; pixelColor[2] = pixelColor[2] + diffuseIntensity * primitiveNear->material.diffuseColor[2] * pointLight->color[2]; glusVector3Reflectf(specularReflection, incidentLightDirection, hitDirection); glusVector3Normalizef(specularReflection); eDotR = glusMathMaxf(0.0f, glusVector3Dotf(eyeDirection, specularReflection)); if (eDotR > 0.0f) { GLfloat specularIntensity = powf(eDotR, primitiveNear->material.shininess); pixelColor[0] = pixelColor[0] + specularIntensity * primitiveNear->material.specularColor[0] * pointLight->color[0]; pixelColor[1] = pixelColor[1] + specularIntensity * primitiveNear->material.specularColor[1] * pointLight->color[1]; pixelColor[2] = pixelColor[2] + specularIntensity * primitiveNear->material.specularColor[2] * pointLight->color[2]; } } } } // Emissive color pixelColor[0] = pixelColor[0] + primitiveNear->material.emissiveColor[0]; pixelColor[1] = pixelColor[1] + primitiveNear->material.emissiveColor[1]; pixelColor[2] = pixelColor[2] + primitiveNear->material.emissiveColor[2]; }
float Vector3::dot(const Vector3& other) const { return glusVector3Dotf(v, other.v); }
GLUSfloat GLUSAPIENTRY glusPlaneDistancePoint4f(const GLUSfloat plane[4], const GLUSfloat point[4]) { return glusVector3Dotf(plane, point) + plane[3]; }
static GLvoid trace(GLfloat pixelColor[4], const GLfloat rayPosition[4], const GLfloat rayDirection[3], const GLint depth) { const GLfloat bias = 1e-4f; GLint i, k; GLfloat tNear = INFINITY; Sphere* sphereNear = 0; GLboolean insideSphereNear = GL_FALSE; GLfloat ray[3]; GLfloat hitPosition[4]; GLfloat hitDirection[3]; GLfloat biasedPositiveHitPosition[4]; GLfloat biasedNegativeHitPosition[4]; GLfloat biasedHitDirection[3]; GLfloat eyeDirection[3]; // pixelColor[0] = 0.0f; pixelColor[1] = 0.0f; pixelColor[2] = 0.0f; pixelColor[3] = 1.0f; // for (i = 0; i < NUM_SPHERES; i++) { GLfloat t0 = INFINITY; GLfloat t1 = INFINITY; GLboolean insideSphere = GL_FALSE; Sphere* currentSphere = &g_allSpheres[i]; GLint numberIntersections = glusIntersectRaySpheref(&t0, &t1, &insideSphere, rayPosition, rayDirection, currentSphere->center, currentSphere->radius); if (numberIntersections) { // If intersection happened inside the sphere, take second intersection point, as this one is on the surface. if (insideSphere) { t0 = t1; } // Found a sphere, which is closer. if (t0 < tNear) { tNear = t0; sphereNear = currentSphere; insideSphereNear = insideSphere; } } } // // No intersection, return background color / ambient light. if (!sphereNear) { pixelColor[0] = 0.8f; pixelColor[1] = 0.8f; pixelColor[2] = 0.8f; return; } // Calculate ray hit position ... glusVector3MultiplyScalarf(ray, rayDirection, tNear); glusPoint4AddVector3f(hitPosition, rayPosition, ray); // ... and normal glusPoint4SubtractPoint4f(hitDirection, hitPosition, sphereNear->center); glusVector3Normalizef(hitDirection); // If inside the sphere, reverse hit vector, as ray comes from inside. if (insideSphereNear) { glusVector3MultiplyScalarf(hitDirection, hitDirection, -1.0f); } // // Biasing, to avoid artifacts. glusVector3MultiplyScalarf(biasedHitDirection, hitDirection, bias); glusPoint4AddVector3f(biasedPositiveHitPosition, hitPosition, biasedHitDirection); glusPoint4SubtractVector3f(biasedNegativeHitPosition, hitPosition, biasedHitDirection); // GLfloat reflectionColor[4] = {0.0f, 0.0f, 0.0f, 1.0f}; GLfloat refractionColor[4] = {0.0f, 0.0f, 0.0f, 1.0f}; GLfloat fresnel = glusVector3Fresnelf(rayDirection, hitDirection, R0); // Reflection ... if (sphereNear->material.reflectivity > 0.0f && depth < MAX_RAY_DEPTH) { GLfloat reflectionDirection[3]; glusVector3Reflectf(reflectionDirection, rayDirection, hitDirection); glusVector3Normalizef(reflectionDirection); trace(reflectionColor, biasedPositiveHitPosition, reflectionDirection, depth + 1); } // ... refraction. if (sphereNear->material.alpha < 1.0f && depth < MAX_RAY_DEPTH) { GLfloat refractionDirection[3]; // If inside, it is from glass to air. GLfloat eta = insideSphereNear ? 1.0f / Eta : Eta; glusVector3Refractf(refractionDirection, rayDirection, hitDirection, eta); glusVector3Normalizef(refractionDirection); trace(refractionColor, biasedNegativeHitPosition, refractionDirection, depth + 1); } else { fresnel = 1.0f; } // glusVector3MultiplyScalarf(eyeDirection, rayDirection, -1.0f); // Diffuse and specular color for (i = 0; i < NUM_LIGHTS; i++) { PointLight* pointLight = &g_allLights[i]; GLboolean obstacle = GL_FALSE; GLfloat lightDirection[3]; GLfloat incidentLightDirection[3]; glusPoint4SubtractPoint4f(lightDirection, pointLight->position, hitPosition); glusVector3Normalizef(lightDirection); glusVector3MultiplyScalarf(incidentLightDirection, lightDirection, -1.0f); // Check for obstacles between current hit point surface and point light. for (k = 0; k < NUM_SPHERES; k++) { Sphere* obstacleSphere = &g_allSpheres[k]; if (obstacleSphere == sphereNear) { continue; } if (glusIntersectRaySpheref(0, 0, 0, biasedPositiveHitPosition, lightDirection, obstacleSphere->center, obstacleSphere->radius)) { obstacle = GL_TRUE; break; } } // If no obstacle, illuminate hit point surface. if (!obstacle) { GLfloat diffuseIntensity = glusMaxf(0.0f, glusVector3Dotf(hitDirection, lightDirection)); if (diffuseIntensity > 0.0f) { GLfloat specularReflection[3]; GLfloat eDotR; pixelColor[0] = pixelColor[0] + diffuseIntensity * sphereNear->material.diffuseColor[0] * pointLight->color[0]; pixelColor[1] = pixelColor[1] + diffuseIntensity * sphereNear->material.diffuseColor[1] * pointLight->color[1]; pixelColor[2] = pixelColor[2] + diffuseIntensity * sphereNear->material.diffuseColor[2] * pointLight->color[2]; glusVector3Reflectf(specularReflection, incidentLightDirection, hitDirection); glusVector3Normalizef(specularReflection); eDotR = glusMaxf(0.0f, glusVector3Dotf(eyeDirection, specularReflection)); if (eDotR > 0.0f && !insideSphereNear) { GLfloat specularIntensity = powf(eDotR, sphereNear->material.shininess); pixelColor[0] = pixelColor[0] + specularIntensity * sphereNear->material.specularColor[0] * pointLight->color[0]; pixelColor[1] = pixelColor[1] + specularIntensity * sphereNear->material.specularColor[1] * pointLight->color[1]; pixelColor[2] = pixelColor[2] + specularIntensity * sphereNear->material.specularColor[2] * pointLight->color[2]; } } } } // Emissive color pixelColor[0] = pixelColor[0] + sphereNear->material.emissiveColor[0]; pixelColor[1] = pixelColor[1] + sphereNear->material.emissiveColor[1]; pixelColor[2] = pixelColor[2] + sphereNear->material.emissiveColor[2]; // Final color with reflection and refraction pixelColor[0] = (1.0f - fresnel) * refractionColor[0] * (1.0f - sphereNear->material.alpha) + pixelColor[0] * (1.0f - sphereNear->material.reflectivity) * sphereNear->material.alpha + fresnel * reflectionColor[0] * sphereNear->material.reflectivity; pixelColor[1] = (1.0f - fresnel) * refractionColor[1] * (1.0f - sphereNear->material.alpha) + pixelColor[1] * (1.0f - sphereNear->material.reflectivity) * sphereNear->material.alpha + fresnel * reflectionColor[1] * sphereNear->material.reflectivity; pixelColor[2] = (1.0f - fresnel) * refractionColor[2] * (1.0f - sphereNear->material.alpha) + pixelColor[2] * (1.0f - sphereNear->material.reflectivity) * sphereNear->material.alpha + fresnel * reflectionColor[2] * sphereNear->material.reflectivity; }