Below are images demonstrating refraction.
This is the image created during Wednesday's class. The rays hitting the
sphere are tweaked randomly, and thus produce a fuzzy transparent look.
scratchapixel refraction function
The image below on left "refracts" each ray upon hitting the sphere, using
the refract function provided on the Scratch-a-pixel web page.
The image to the right is a photograph of a real glass ball sitting on my desk.
Note:
To use the Scratch-a-pixel refract() function will be an exercise in refactoring
of source code. Try it yourself, then if you give up I will help you.
Indexes of refraction used in the image above:
air: 1.000293
glass: 1.52
Here is some code we did in class together.
clipping class
class Clip {
public:
Vec center;
Vec normal;
double radius;
bool inside;
Clip() { radius = 0.0; }
};
//Clip elements in the Object class.
Clip clip[12];
int nclips;
Pokeball bottom sphere definition (yours can differ)
o = &g.object[g.nobjects];
o->type = TYPE_SPHERE;
vecMake(0.0, 0.0, 0.0, o->center);
o->radius = 100.0;
vecMake(1.0, 1.0, 1.0, o->color);
o->specular = true;
vecMake(0.1, 0.1, 0.1, o->spec);
//clipping--------------------------
o->nclips = 0;
vecMake(0, -6., 0, o->clip[0].center);
vecMake(0, 1, 0, o->clip[0].normal);
vecNormalize(o->clip[0].normal);
++o->nclips;
//clip a hole in the sphere
vecMake(0, 0, 100, o->clip[o->nclips].center);
o->clip[o->nclips].radius = 20.0;
++o->nclips;
//----------------------------------
g.nobjects++;
Triangle definition (yours can differ)
o = &.object[g.nobjects];
o->type = TYPE_TRIANGLE;
vecMake(-100, 100, 100, o->tri[0]);
vecMake(-100, -100, 100, o->tri[1]);
vecMake( 100, -100, 100, o->tri[2]);
getTriangleNormal(o->tri, o->norm);
vecMake(0.1, 1.0, 0.1, o->color);
o->surface = SURF_NONE;
g.nobjects++;
Ray/Triangle intersection
int rayTriangleIntersect(Object *o, Ray *ray, Hit *hit)
{
//Does the ray intersect the triangle's plane?
if (rayPlaneIntersect(o->tri[0], o->norm, ray, hit)) {
//Yes.
double u, v, w;
if (pointInTriangle(o->tri, hit->p, &u, &v)) {
w = 1.0 - u - v;
(void)w;
return 1;
}
}
return 0;
}
In trace()
case TYPE_TRIANGLE:
if (rayTriangleIntersect(o, ray, &hit)) {
if (hit.t < closehit.t) {
closehit.t = hit.t;
vecCopy(hit.p, closehit.p);
vecCopy(o->color, closehit.color);
vecCopy(o->norm, closehit.norm);
h=i;
}
}
break;
In raySphereIntersect()
//quadratic solutions...
if (t0 > 0.0) {
hit->p[0] = ray->o[0] + ray->d[0] * t0;
hit->p[1] = ray->o[1] + ray->d[1] * t0;
hit->p[2] = ray->o[2] + ray->d[2] * t0;
sphereNormal(hit->p, o->center, hit->norm);
hit->t = t0;
//Is this clipped?
for (int i=0; i<o->nclips; i++) {
Vec v;
vecSub(hit->p, o->clip[i].center, v);
if (o->clip[i].radius > 0.0) {
//sphere clip
double dist = sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
if (o->clip[i].inside) {
if (dist <= o->clip[i].radius)
goto back_of_sphere;
} else {
if (dist > o->clip[i].radius)
goto back_of_sphere;
}
}
double dot = vecDotProduct(v, o->clip[i].normal);
if (dot > 0.0)
goto back_of_sphere;
}
return 1;
}
back_of_sphere:
if (t1 > 0.0) {
hit->p[0] = ray->o[0] + ray->d[0] * t1;
hit->p[1] = ray->o[1] + ray->d[1] * t1;
hit->p[2] = ray->o[2] + ray->d[2] * t1;
sphereNormal(hit->p, o->center, hit->norm);
hit->t = t1;
//Is this clipped?
for (int i=0; i<o->nclips; i++) {
Vec v;
vecSub(hit->p, o->clip[i].center, v);
if (o->clip[i].radius > 0.0) {
//sphere clip
double dist = sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
if (o->clip[i].inside) {
if (dist <= o->clip[i].radius)
return 0;
} else {
if (dist > o->clip[i].radius)
return 0;
}
}
//plane clip
double dot = vecDotProduct(v, o->clip[i].normal);
if (dot > 0.0)
return 0;
}
return 1;
}