Vec3f RayTracer::shadow(const Vec3f &point, const Vec3f &pointOnLight, const Face *f, const Ray &ray, const Hit &hit) const { const Vec3f normal(hit.getNormal()); const Material *m = hit.getMaterial(); Vec3f dirToLight = pointOnLight - point; dirToLight.Normalize(); /* If dot product < 0, surface is not facing light */ if (normal.Dot3(dirToLight) > 0) { Ray rayToLight(point, dirToLight); Hit hLight; bool blocked = CastRay(rayToLight, hLight, false); while (std::fabs(hLight.getT()) < SURFACE_EPSILON && std::fabs((pointOnLight - point).Length()) > SURFACE_EPSILON) { rayToLight = Ray(rayToLight.pointAtParameter(SURFACE_EPSILON), dirToLight); blocked = CastRay(rayToLight, hLight, false); } if (hLight.getT() == FLT_MAX || hLight.getMaterial() != f->getMaterial()) { return Vec3f(0, 0, 0); } const Vec3f lightColor = 0.2 * f->getMaterial()->getEmittedColor() * f->getArea(); return m->Shade(ray,hit,dirToLight,lightColor,args); } return Vec3f(0, 0, 0); }
static void TestSingleLightFace (entity_t *light, lightinfo_t *l, const vec3_t faceoffset) { vec_t dist; vec_t add; vec_t *surf; vec3_t rel; int surf_r; int surf_g; int surf_b; int c; VectorSubtract (light->origin, bsp_origin, rel); dist = scaledDistance((DotProduct(rel, l->facenormal) - l->facedist), light); // don't bother with lights behind the surface if (dist <= 0) return; // don't bother with light too far away if (dist > abs(light->light)) { return; } // mfah - find the light color based on the surface name FindTexlightColor (&surf_r, &surf_g, &surf_b, l->texname); surf = l->surfpt[0]; // we could speed the whole thing up drastically by checking only // the first and last point of each face - trouble is, any large // faces may have a light that only hits the middle. for (c = 0 ; c < l->numsurfpt ; c++, surf+=3) { if (surf > l->surfpt[SINGLEMAP - 1]) COM_Error ("%s: surf out of bounds (numsurfpt=%d)", __thisfunc__, l->numsurfpt); dist = scaledDistance(CastRay(light->origin, surf), light); if (dist < 0) continue; // light doesn't reach add = scaledLight(CastRay(light->origin, surf), light); if (add < (light->light / 3)) continue; // normal light - other lights already have a color assigned // to them from when they were initially loaded // this will give madly high color values here so we will // scale them down later on light->lightcolor[0] = light->lightcolor[0] + surf_r; light->lightcolor[1] = light->lightcolor[1] + surf_g; light->lightcolor[2] = light->lightcolor[2] + surf_b; // speed up the checking process some more - if we have one hit // on a face, all other hits on the same face are just going to // give the same result - so we can return now. return; } }
void Camera::Render(Scene scene) { // Compute upper left corner of frame Point UpperLeftCorner(CameraRay.Location); UpperLeftCorner = UpperLeftCorner.Translate(CameraRay.Direction.Normalize() * FrameDistance); // Currently in center of frame Vector UpUnit = UprightDir.Normalize(); UpperLeftCorner = UpperLeftCorner.Translate(UpUnit*(Height / 2)); // Currently in top center of frame // Compute the perpendicular, leftward facing vector and move the point to the upper left corner Vector LeftUnit = UprightDir.Cross(CameraRay.Direction).Normalize() * -1; UpperLeftCorner = UpperLeftCorner.Translate(LeftUnit*(Width / 2)); Vector HorzInc = LeftUnit * (-1 * Width/ static_cast<double>(Resolution.width)); // Progress to the right Vector VertInc = UpUnit * (-1 * Height/ static_cast<double>(Resolution.height)); // Progress downwards // Position upper left corner to be in the center of the pixel UpperLeftCorner = UpperLeftCorner.Translate((HorzInc * (0.5)) + (VertInc * (0.5))); Point PixelLocation(0,0,0); // Iterate over the image space and render each occupied pixel for (int YPixel = 0; YPixel < Resolution.height; YPixel++) { for (int XPixel = 0; XPixel < Resolution.width; XPixel++) { PixelLocation = UpperLeftCorner.Translate((VertInc * YPixel) + (HorzInc * XPixel)); Ray CameraToPixel(CameraRay.Location, CameraRay.Location.FromThisToThat(PixelLocation)); cv::Vec3b PixelValue = CastRay(scene, CameraToPixel); Image.at<cv::Vec3b>(YPixel, XPixel) = PixelValue; } } }
// does the recursive (shadow rays & recursive/glossy rays) work Vec3f RayTracer::TraceRay(const Ray &ray, Hit &hit, int bounce_count) const { hit = Hit(); bool intersect = CastRay(ray,hit,false); Vec3f answer(args->background_color_linear); if (intersect == true) { const Material *m = hit.getMaterial(); assert (m != NULL); // rays coming from the light source are set to white, don't bother to ray trace further. if (m->getEmittedColor().Length() > 0.001) { answer = Vec3f(1,1,1); } else { // ambient light answer = args->ambient_light_linear * m->getDiffuseColor(hit.get_s(),hit.get_t()); // Shadows answer += shadows(ray, hit); // Reflections Vec3f reflectiveColor = m->getReflectiveColor(); double roughness = m->getRoughness(); if (bounce_count > 0 && reflectiveColor.Length() > MIN_COLOR_LEN) { answer += reflectiveColor * reflections(ray, hit, bounce_count, roughness); } } } return answer; }
bool TracingInstance::IsPointOccluded(const KRay& ray, float len) { IntersectContext ctx; if (CastRay(ray, ctx)) { double diff = ctx.ray_t - len; float epsilon = mpScene->GetSceneEpsilon(); if (diff > epsilon) return false; else return true; } else return false; }
/* ================ SingleLightFace ================ */ void SingleLightFace (lightentity_t *light, lightinfo_t *l) { vec_t dist; vec3_t incoming; vec_t angle; vec_t add; vec_t *surf; qboolean hit; int mapnum; int size; int c, i; vec3_t rel; vec3_t spotvec; vec_t falloff; vec3_t *lightsamp; float intensity; VectorSubtract (light->origin, bsp_origin, rel); dist = scaledist * (DotProduct (rel, l->facenormal) - l->facedist); // don't bother with lights behind the surface if (dist <= 0) return; // don't bother with light too far away intensity = ( light->light[ 0 ] + light->light[ 1 ] + light->light[ 2 ] ) / 3.0; if( dist > intensity ) { c_culldistplane++; return; } if (light->targetent) { VectorSubtract (light->targetorigin, light->origin, spotvec); VectorNormalize (spotvec); if (!light->angle) falloff = -cos(20*Q_PI/180); else falloff = -cos(light->angle/2*Q_PI/180); } else falloff = 0; // shut up compiler warnings mapnum = 0; for (mapnum=0 ; mapnum<l->numlightstyles ; mapnum++) if (l->lightstyles[mapnum] == light->style) break; lightsamp = l->lightmaps[mapnum]; if (mapnum == l->numlightstyles) { // init a new light map if (mapnum == MAXLIGHTMAPS) { printf ("WARNING: Too many light styles on a face\n"); return; } size = (l->texsize[1]+1)*(l->texsize[0]+1); for (i=0 ; i<size ; i++) { lightsamp[i][0] = 0; lightsamp[i][1] = 0; lightsamp[i][2] = 0; } } // // check it for real // hit = false; c_proper++; surf = l->surfpt[0]; for (c=0 ; c<l->numsurfpt ; c++, surf+=3) { dist = CastRay(light->origin, surf)*scaledist; if (dist < 0) continue; // light doesn't reach VectorSubtract (light->origin, surf, incoming); VectorNormalize (incoming); angle = DotProduct (incoming, l->facenormal); if (light->targetent) { // spotlight cutoff if (DotProduct (spotvec, incoming) > falloff) continue; } angle = (1.0-scalecos) + scalecos*angle; for( i=0; i<3; i++ ) { add = light->light[i] - dist; add *= angle; if (add < 0) continue; lightsamp[c][i] += add; } // check intensity intensity = ( lightsamp[ c ][ 0 ] + lightsamp[ c ][ 1 ] + lightsamp[ c ][ 2 ] ) / 3.0; if( intensity > 1 ) // ignore real tiny lights hit = true; } if (mapnum == l->numlightstyles && hit) { l->lightstyles[mapnum] = light->style; l->numlightstyles++; // the style has some real data now } }
void CalcPoints (lightinfo_t *l) { int i; int s, t, j; int w, h, step; vec_t starts, startt, us, ut; vec_t *surf; vec_t mids, midt; vec3_t facemid, move; // // fill in surforg // the points are biased towards the center of the surface // to help avoid edge cases just inside walls // surf = l->surfpt[0]; mids = (l->exactmaxs[0] + l->exactmins[0])/2; midt = (l->exactmaxs[1] + l->exactmins[1])/2; for (j=0 ; j<3 ; j++) facemid[j] = l->texorg[j] + l->textoworld[0][j]*mids + l->textoworld[1][j]*midt; if (extrasamples) { // extra filtering h = (l->texsize[1]+1)*2; w = (l->texsize[0]+1)*2; starts = (l->texmins[0]-0.5)*16; startt = (l->texmins[1]-0.5)*16; step = 8; } else { h = l->texsize[1]+1; w = l->texsize[0]+1; starts = l->texmins[0]*16; startt = l->texmins[1]*16; step = 16; } l->numsurfpt = w * h; for (t=0 ; t<h ; t++) { for (s=0 ; s<w ; s++, surf+=3) { us = starts + s*step; ut = startt + t*step; // if a line can be traced from surf to facemid, the point is good for (i=0 ; i<6 ; i++) { // calculate texture point for (j=0 ; j<3 ; j++) surf[j] = l->texorg[j] + l->textoworld[0][j]*us + l->textoworld[1][j]*ut; if (CastRay (facemid, surf) != -1) break; // got it if (i & 1) { if (us > mids) { us -= 8; if (us < mids) us = mids; } else { us += 8; if (us > mids) us = mids; } } else { if (ut > midt) { ut -= 8; if (ut < midt) ut = midt; } else { ut += 8; if (ut > midt) ut = midt; } } // move surf 8 pixels towards the center VectorSubtract (facemid, surf, move); VectorNormalize (move); VectorMA (surf, 8, move, surf); } if (i == 2) c_bad++; } } }
/* ================ SingleLightFace ================ */ static void SingleLightFace (entity_t *light, lightinfo_t *l, const vec3_t faceoffset) { vec_t dist; vec3_t incoming; vec_t angle; vec_t add; vec_t *surf; qboolean hit; int mapnum; int size; int c, i; vec3_t rel; vec3_t spotvec; vec_t falloff; vec_t *lightsamp; /* Colored lighting */ vec3_t *lightcolorsamp; VectorSubtract (light->origin, bsp_origin, rel); dist = scaledDistance((DotProduct(rel, l->facenormal) - l->facedist), light); // don't bother with lights behind the surface if (dist <= 0) return; // don't bother with light too far away //if (dist > light->light) if (dist > abs(light->light)) { return; } if (light->targetent) { VectorSubtract (light->targetent->origin, light->origin, spotvec); VectorNormalize (spotvec); if (!light->angle) falloff = -cos(20*Q_PI/180); else falloff = -cos(light->angle/2*Q_PI/180); } else if (light->use_mangle) { VectorCopy (light->mangle, spotvec); if (!light->angle) falloff = -cos(20*Q_PI/180); else falloff = -cos(light->angle/2*Q_PI/180); } else { falloff = 0; // shut up compiler warnings VectorClear (spotvec); // shut up static analyzers } for (mapnum = 0; mapnum < l->numlightstyles; mapnum++) { if (l->lightstyles[mapnum] == light->style) break; } lightsamp = l->lightmaps[mapnum]; lightcolorsamp = l->lightmapcolors[mapnum]; if (mapnum == l->numlightstyles) { // init a new light map if (mapnum == MAXLIGHTMAPS) { printf ("WARNING: Too many light styles on a face\n"); return; } size = (l->texsize[1]+1)*(l->texsize[0]+1); for (i = 0 ; i < size ; i++) { lightcolorsamp[i][0] = 0; lightcolorsamp[i][1] = 0; lightcolorsamp[i][2] = 0; lightsamp[i] = 0; } } // // check it for real // hit = false; surf = l->surfpt[0]; for (c = 0 ; c < l->numsurfpt ; c++, surf+=3) { if (surf > l->surfpt[SINGLEMAP - 1]) COM_Error ("%s: surf out of bounds (numsurfpt=%d)", __thisfunc__, l->numsurfpt); dist = scaledDistance(CastRay(light->origin, surf), light); if (dist < 0) continue; // light doesn't reach VectorSubtract (light->origin, surf, incoming); VectorNormalize (incoming); angle = DotProduct (incoming, l->facenormal); if (light->targetent || light->use_mangle) { // spotlight cutoff if (DotProduct (spotvec, incoming) > falloff) continue; } angle = (1.0-scalecos) + scalecos*angle; add = scaledLight(CastRay(light->origin, surf), light); add *= angle; lightsamp[c] += add; if (lightsamp[c] > 255) lightsamp[c] = 255; add /= 255.0; lightcolorsamp[c][0] += add * light->lightcolor[0]; lightcolorsamp[c][1] += add * light->lightcolor[1]; lightcolorsamp[c][2] += add * light->lightcolor[2]; if (abs((int) lightsamp[c]) > 1) // ignore really tiny lights hit = true; } if (mapnum == l->numlightstyles && hit) { if (mapnum == MAXLIGHTMAPS-1) { printf ("WARNING: Too many light styles on a face\n"); return; } l->lightstyles[mapnum] = light->style; l->numlightstyles++; // the style has some real data now } }