Text archives Help
- From: cgribble@sci.utah.edu
- To: manta@sci.utah.edu
- Subject: [MANTA] r1097 - in trunk: Engine/Control Model/Primitives
- Date: Sun, 4 Jun 2006 14:14:26 -0600 (MDT)
Author: cgribble
Date: Sun Jun 4 14:14:24 2006
New Revision: 1097
Modified:
trunk/Engine/Control/DynPLTWorker.cc
trunk/Engine/Control/DynPLTWorker.h
trunk/Model/Primitives/DynPLTGridSpheres.cc
trunk/Model/Primitives/DynPLTGridSpheres.h
trunk/Model/Primitives/GridSpheres.cc
trunk/Model/Primitives/GridSpheres.h
Log:
Engine/Control/DynPLTWorker.cc
Engine/Control/DynPLTWorker.h
Added render{Ambient,Global} functions to generate ambient occlusion or full
global illumination textures based on DynPLTGridSphere's texture mode
Lots of redundancy between the two functions that could be refactored
Model/Primitives/DynPLTGridSpheres.cc
Model/Primitives/DynPLTGridSpheres.h
Added textureMode for controlling use of ambient occlusion vs. full global
illumination textures
Added accessors for textureMode
Added vector<bool> allocated indicating whether or not the memory for a
texture
has been allocated; used to be vector<bool> valid, but will eventually
need
to invalidate textures (switching between ambient occlusion and global
illumination or when lighting changes, etc.) without having to
free/realloc
them
Added shade{Ambient,Global}(...) functions for using textures appropriately
(either interpolating both ambient/direct component or just the ambient
component)
Added computeLuminance(...) function to remove some code redundancy
Model/Primitives/GridSpheres.cc
Model/Primitives/GridSpheres.h
Added lambertianShade(...) function that takes an already computed ambient
term as input
Changed shade(...) call to reflect new lambertianShade(...) function
Now facilitates ambient occlusion textures
Modified: trunk/Engine/Control/DynPLTWorker.cc
==============================================================================
--- trunk/Engine/Control/DynPLTWorker.cc (original)
+++ trunk/Engine/Control/DynPLTWorker.cc Sun Jun 4 14:14:24 2006
@@ -83,275 +83,459 @@
void DynPLTWorker::run(void)
{
- // Grab useful information from the DynPLT context
- unsigned int ngroups=context->ngroups;
- unsigned int nsamples=context->nsamples;
- unsigned int max_depth=context->max_depth;
- Real inv_nsamples=1/static_cast<Real>(nsamples);
-
- // Create a render context for direct lighting computations
- Scene* scene=context->scene;
+ // Create a render context for computing ray intersections
vector<string> args;
- HardShadows shadowAlgorithm(args);
+ HardShadows shadows(args);
// RenderContext(MantaInterface*, int, int, int, const FrameState*,
// LoadBalancer*, PixelSampler*, Renderer*, ShadowAlgorithm*,
// const Camera*, const Scene*, ThreadStorage*);
- RenderContext rctx(0, 0, 0, 0, 0, 0, 0, 0, &shadowAlgorithm, 0, scene, 0);
+ RenderContext rctx(0, 0, 0, 0, 0, 0, 0, 0, &shadows, 0, context->scene, 0);
DynPLTMessage msg=context->queue->receive();
while (msg.particle>=0) {
// Grab message data
int particle=msg.particle;
const DynPLTGridSpheres* grid=msg.grid;
-
- // Allocate new texture, if necessary
- if (grid->plts[particle])
+
+ // Skip valid textures
+ if (grid->valid[particle])
continue;
- grid->plts[particle]=new DynPLT();
+ // Allocate new texture, if necessary
+ if (!grid->allocated[particle]) {
+ grid->plts[particle]=new DynPLT();
+ grid->allocated[particle]=true;
+ }
- // Determine texture resolution
- DynPLT* dynplt=grid->plts[particle];
- unsigned int xres=dynplt->getXRes();
- unsigned int yres=dynplt->getYRes();
- // Real inv_width=1/static_cast<Real>(xres - 1);
- // Real inv_height=1/static_cast<Real>(yres - 1);
- Real inv_width=1/static_cast<Real>(xres);
- Real inv_height=1/static_cast<Real>(yres);
-
- // Intialize the textures
- bzero(dynplt->texture, xres*yres*sizeof(float));
- bzero(dynplt->inside, xres*yres*sizeof(float));
bool dilateTexture=false;
- // Generate particle's texture
- Vector center=grid->getCenter(particle);
- Real radius=grid->getRadius(particle);
-
- for (unsigned int v=0; v<yres; ++v) {
- for (unsigned int u=0; u<xres; ++u) {
- // Pick a random sample group for surface points
- unsigned int sidx=static_cast<unsigned int>(ngroups*rng.gendrand());
-
- // Pick random sample group for points on the hemisphere at each
depth
- for (int d=0; d<=max_depth; ++d)
- hidx[d]=static_cast<unsigned int>(ngroups*rng.gendrand());
-
- for (unsigned int s=0; s<nsamples; s += RayPacket::MaxSize) {
- Real diffuse=0;
- Real ambient=0;
- Packet<Real> atten;
-
- // Initialize a ray packet
- int size=RayPacket::MaxSize;
- if (size >= nsamples - s) {
- // Remaining number of samples isn't large enough to fill a ray
- // packet, so set the size of the ray packet to the number of
samples
- // that remain
- size=nsamples - s;
- }
+ // Render the texture
+ switch (grid->getTextureMode()) {
+ case DynPLTGridSpheres::AmbientOcclusion:
+ dilateTexture=renderAmbient(context, rctx, grid, particle);
+ break;
+ case DynPLTGridSpheres::GlobalIllumination:
+ default:
+ dilateTexture=renderGlobal(context, rctx, grid, particle);
+ break;
+ }
+
+ if (context->dilate && dilateTexture)
+ grid->plts[particle]->dilate(context);
+
+ // XXX: maybe use a transaction to mark the texture as valid and prevent
+ // tearing in the middle of a frame
+ grid->valid[particle]=true;
- RayPacketData raydata;
- RayPacket rays(raydata, RayPacket::UnknownShape, 0, size, 0, 0);
+ // Receive next message
+ msg=context->queue->receive();
+ }
- // Fill in the hit positions and surface normals at sample points
- for (int i=rays.begin(); i<rays.end(); ++i) {
- // Project surface sample point onto particle's surface
- Vector2D sample=sample_groups[sidx][s + i];
+ if (exitSem)
+ exitSem->up();
+}
+
+bool DynPLTWorker::renderAmbient(const DynPLTContext* context,
+ const RenderContext& rctx,
+ const DynPLTGridSpheres* grid,
+ unsigned int particle)
+{
+ // Grab useful information from the DynPLT context
+ unsigned int ngroups=context->ngroups;
+ unsigned int nsamples=context->nsamples;
+ unsigned int max_depth=context->max_depth;
+ Real inv_nsamples=1/static_cast<Real>(nsamples);
+
+ // Determine texture resolution
+ DynPLT* dynplt=grid->plts[particle];
+ unsigned int xres=dynplt->getXRes();
+ unsigned int yres=dynplt->getYRes();
+ // Real inv_width=1/static_cast<Real>(xres - 1);
+ // Real inv_height=1/static_cast<Real>(yres - 1);
+ Real inv_width=1/static_cast<Real>(xres);
+ Real inv_height=1/static_cast<Real>(yres);
+
+ // Intialize the textures
+ bzero(dynplt->texture, xres*yres*sizeof(float));
+ bzero(dynplt->inside, xres*yres*sizeof(float));
+
+ // Generate texture
+ const Vector center=grid->getCenter(particle);
+ Real radius=grid->getRadius(particle);
+ bool dilateTexture=false;
+
+ for (unsigned int v=0; v<yres; ++v) {
+ for (unsigned int u=0; u<xres; ++u) {
+ // Pick a random sample group for surface points
+ unsigned int sidx=static_cast<unsigned int>(ngroups*rng.gendrand());
+
+ // Pick random sample group for points on the hemisphere at each depth
+ for (int d=0; d<=max_depth; ++d)
+ hidx[d]=static_cast<unsigned int>(ngroups*rng.gendrand());
+
+ Real ambient=0;
+ for (unsigned int s=0; s<nsamples; s += RayPacket::MaxSize) {
+ // Initialize a ray packet
+ int size=RayPacket::MaxSize;
+ if (size >= nsamples - s) {
+ // Remaining number of samples isn't large enough to fill a ray
+ // packet, so set the size of the ray packet to the number of
samples
+ // that remain
+ size=nsamples - s;
+ }
+
+ RayPacketData raydata;
+ RayPacket rays(raydata, RayPacket::UnknownShape, 0, size, 0, 0);
+
+ // Fill in the ray origins and directions at sample points
+ for (int i=rays.begin(); i<rays.end(); ++i) {
+ // Project surface sample point onto particle's surface
+ Vector2D sample=sample_groups[sidx][s + i];
- // Range of 2*M_PI*(u + sample.x)/(xres - 1) --> [0, 2*Pi]
- // Range of M_PI*(v + sample.y)/(yres - 1) --> [0, Pi]
- Real phi=2*M_PI*(u + sample.x())*inv_width;
- Real theta=M_PI*(v + sample.y())*inv_height;
-
- Real x=cos(phi)*sin(theta);
- Real y=sin(phi)*sin(theta);
- Real z=cos(theta);
-
- Vector normal(x, y, z);
- Vector surface=center + radius*normal;
-
- rays.setHitPosition(i, surface);
- rays.setNormal(i, normal);
- atten.set(i, 1);
+ // Range of 2*M_PI*(u + sample.x)/(xres - 1) --> [0, 2*Pi]
+ // Range of M_PI*(v + sample.y)/(yres - 1) --> [0, Pi]
+ Real phi=2*M_PI*(u + sample.x())*inv_width;
+ Real theta=M_PI*(v + sample.y())*inv_height;
+
+ Real x=cos(phi)*sin(theta);
+ Real y=sin(phi)*sin(theta);
+ Real z=cos(theta);
+
+ Vector normal(x, y, z);
+ Vector origin=center + radius*normal;
+
+ // Compute an ONB at the surface point
+ Vector v0(Cross(normal, Vector(1,0,0)));
+ if (v0.length2()==0)
+ v0=Cross(normal, Vector(0,1,0));
+ Vector v1=Cross(normal, v0);
+ v0.normalize();
+ v1.normalize();
+
+ // Generate a random direction in the hemisphere
+ Vector2D hemi=sample_groups[hidx[0]][i];
+ Real hphi=2.0*M_PI*hemi.x();
+ Real hr=SCIRun::Sqrt(hemi.y());
+ Real hx=hr*cos(hphi);
+ Real hy=hr*sin(hphi);
+ Real hz=1 - hx*hx - hy*hy;
+ hz=(hz>0?SCIRun::Sqrt(hz):0);
+
+ Vector out=Vector(hx, hy, hz).normal();
+ Vector dir=v0*out.x() + v1*out.y() + normal*out.z();
+ dir.normalize();
+
+ // Set ray origin and direction
+ rays.setOrigin(i, origin);
+ rays.setDirection(i, dir);
+ }
+
+ // Reset ray packet
+ rays.setAllFlags(0);
+ rays.setFlag(RayPacket::NormalizedDirections);
+ rays.resetHits();
+
+ // Intersect rays with the geometry
+ context->scene->getObject()->intersect(rctx, rays);
+
+ for (unsigned int i=rays.begin(); i<rays.end();) {
+ if (rays.wasHit(i)) {
+ // Find a run of rays that hit an object
+ unsigned int end=i + 1;
+ while (end < rays.end() && rays.wasHit(end))
+ ++end;
+
+ // Rays that intersect other objects do not contribute, but
check for
+ // invalid hits (if necessary)
+ if (context->dilate) {
+ // Compute hit positions and normals
+ RayPacket sub(rays, i, end);
+ sub.computeHitPositions();
+ sub.computeNormals(rctx);
+
+ for (unsigned int j=sub.begin(); j<sub.end(); ++j) {
+ Real dotprod=Dot(sub.getNormal(j), -sub.getDirection(j));
+ if (dotprod<=0) {
+ // An invalid hit, resulting from:
+ //
+ // 1. Intersecting spheres---Ray origin is inside of one
+ // sphere and it hits the inside surface of the other
+ //
+ // 2. Ray origin is coincident with the surface of a
+ // neighboring sphere---May result in some crazy
+ // math, and thus a negative dot product
+ //
+ // Either way, ignore the hit and mark the texel for
+ // dilation
+ dynplt->inside[u][v] += 1;
+ dilateTexture=true;
+ }
+ }
+ }
+
+ i=end;
+ } else {
+ // Find a run of rays that didn't hit anything
+ unsigned int end=i + 1;
+ while (end < rays.end() && !rays.wasHit(end))
+ ++end;
+
+ ambient += end - i;
+
+ i=end;
}
+ }
+ }
- // Iteratively trace the ray packet
- for (unsigned int d=0; d<max_depth; ++d) {
- // Reset ray packet flags
- rays.setAllFlags(0);
- rays.setFlag(RayPacket::HaveHitPositions |
RayPacket::HaveNormals |
- RayPacket::HaveUnitNormals);
-
- // Compute direct lighting at current hit positions
- const LightSet* activeLights=grid->getActiveLights();
- ShadowAlgorithm::StateBuffer stateBuffer;
- bool firstTime=true;
- bool done;
- do {
- RayPacketData shadowData;
- RayPacket shadowRays(shadowData, RayPacket::UnknownShape, 0, 0,
- rays.getDepth(), 0);
-
- // Call the shadow algorithm (SA) to generate shadow rays. We
- // may not be able to compute all of them, so we pass along a
- // buffer for the SA object to store it's state. The firstTime
- // flag tells the SA to fill in the state rather than using
- // anything in the state buffer. Most SAs will only need to
- // store an int or two in the statebuffer.
- done=rctx.shadowAlgorithm->computeShadows(rctx, activeLights,
- rays, shadowRays,
- firstTime,
- stateBuffer);
+ // Store the normalized result
+ dynplt->texture[u][v]=context->Ka*ambient*inv_nsamples;
+ }
+ }
+
+ return dilateTexture;
+}
+
+bool DynPLTWorker::renderGlobal(const DynPLTContext* context,
+ const RenderContext& rctx,
+ const DynPLTGridSpheres* grid,
+ unsigned int particle)
+{
+ // Grab useful information from the DynPLT context
+ unsigned int ngroups=context->ngroups;
+ unsigned int nsamples=context->nsamples;
+ unsigned int max_depth=context->max_depth;
+ Real inv_nsamples=1/static_cast<Real>(nsamples);
+
+ // Determine texture resolution
+ DynPLT* dynplt=grid->plts[particle];
+ unsigned int xres=dynplt->getXRes();
+ unsigned int yres=dynplt->getYRes();
+ // Real inv_width=1/static_cast<Real>(xres - 1);
+ // Real inv_height=1/static_cast<Real>(yres - 1);
+ Real inv_width=1/static_cast<Real>(xres);
+ Real inv_height=1/static_cast<Real>(yres);
+
+ // Intialize the textures
+ bzero(dynplt->texture, xres*yres*sizeof(float));
+ bzero(dynplt->inside, xres*yres*sizeof(float));
+
+ // Generate texture
+ const Vector center=grid->getCenter(particle);
+ Real radius=grid->getRadius(particle);
+ bool dilateTexture=false;
+
+ for (unsigned int v=0; v<yres; ++v) {
+ for (unsigned int u=0; u<xres; ++u) {
+ // Pick a random sample group for surface points
+ unsigned int sidx=static_cast<unsigned int>(ngroups*rng.gendrand());
+
+ // Pick random sample group for points on the hemisphere at each depth
+ for (int d=0; d<=max_depth; ++d)
+ hidx[d]=static_cast<unsigned int>(ngroups*rng.gendrand());
+
+ for (unsigned int s=0; s<nsamples; s += RayPacket::MaxSize) {
+ Real diffuse=0;
+ Real ambient=0;
+ Packet<Real> atten;
+
+ // Initialize a ray packet
+ int size=RayPacket::MaxSize;
+ if (size >= nsamples - s) {
+ // Remaining number of samples isn't large enough to fill a ray
+ // packet, so set the size of the ray packet to the number of
samples
+ // that remain
+ size=nsamples - s;
+ }
+
+ RayPacketData raydata;
+ RayPacket rays(raydata, RayPacket::UnknownShape, 0, size, 0, 0);
+
+ // Fill in the hit positions and surface normals at sample points
+ for (int i=rays.begin(); i<rays.end(); ++i) {
+ // Project surface sample point onto particle's surface
+ Vector2D sample=sample_groups[sidx][s + i];
+
+ // Range of 2*M_PI*(u + sample.x)/(xres - 1) --> [0, 2*Pi]
+ // Range of M_PI*(v + sample.y)/(yres - 1) --> [0, Pi]
+ Real phi=2*M_PI*(u + sample.x())*inv_width;
+ Real theta=M_PI*(v + sample.y())*inv_height;
+
+ Real x=cos(phi)*sin(theta);
+ Real y=sin(phi)*sin(theta);
+ Real z=cos(theta);
+
+ Vector normal(x, y, z);
+ Vector surface=center + radius*normal;
+
+ rays.setHitPosition(i, surface);
+ rays.setNormal(i, normal);
+ atten.set(i, 1);
+ }
+
+ // Iteratively trace the ray packet
+ for (unsigned int d=0; d<max_depth; ++d) {
+ // Reset ray packet flags
+ rays.setAllFlags(0);
+ rays.setFlag(RayPacket::HaveHitPositions | RayPacket::HaveNormals |
+ RayPacket::HaveUnitNormals);
+
+ // Compute direct lighting at current hit positions
+ const LightSet* activeLights=grid->getActiveLights();
+ ShadowAlgorithm::StateBuffer stateBuffer;
+ bool firstTime=true;
+ bool done;
+ do {
+ RayPacketData shadowData;
+ RayPacket shadowRays(shadowData, RayPacket::UnknownShape, 0, 0,
+ rays.getDepth(), 0);
+
+ // Call the shadow algorithm (SA) to generate shadow rays. We
+ // may not be able to compute all of them, so we pass along a
+ // buffer for the SA object to store it's state. The firstTime
+ // flag tells the SA to fill in the state rather than using
+ // anything in the state buffer. Most SAs will only need to
+ // store an int or two in the statebuffer.
+ done=rctx.shadowAlgorithm->computeShadows(rctx, activeLights,
+ rays, shadowRays,
+ firstTime,
+ stateBuffer);
- // Normalize directions for proper dot product computation
- shadowRays.normalizeDirections();
+ // Normalize directions for proper dot product computation
+ shadowRays.normalizeDirections();
- for (int i=shadowRays.begin(); i<shadowRays.end(); ++i) {
- if (!shadowRays.wasHit(i)) {
- // Not in shadow, so compute the direct contribution
- Vector normal=rays.getNormal(i);
- Vector shadowdir=shadowRays.getDirection(i);
- Real cos_theta=Dot(shadowdir, normal);
- Color light=shadowRays.getColor(i);
- diffuse += atten.get(i)*light.luminance()*cos_theta;
- }
+ for (int i=shadowRays.begin(); i<shadowRays.end(); ++i) {
+ if (!shadowRays.wasHit(i)) {
+ // Not in shadow, so compute the direct contribution
+ Vector normal=rays.getNormal(i);
+ Vector shadowdir=shadowRays.getDirection(i);
+ Real cos_theta=Dot(shadowdir, normal);
+ Color light=shadowRays.getColor(i);
+ diffuse += atten.get(i)*light.luminance()*cos_theta;
}
+ }
- firstTime=false;
- } while(!done);
+ firstTime=false;
+ } while(!done);
+
+ // Don't fill/trace ray packet if it's not going to contribute
+ if (d >= max_depth - 1)
+ break;
- // Don't fill/trace ray packet if it's not going to contribute
- if (d >= max_depth - 1)
- break;
-
- for (int i=rays.begin(); i<rays.end(); ++i) {
- // Compute an ONB at the surface point
- Vector normal=rays.getNormal(i);
- Vector v0(Cross(normal, Vector(1,0,0)));
- if (v0.length2()==0)
- v0=Cross(normal, Vector(0,1,0));
- Vector v1=Cross(normal, v0);
- v0.normalize();
- v1.normalize();
-
- // Generate a random direction in the hemisphere
- Vector2D hemi=sample_groups[hidx[d]][i];
- Real hphi=2.0*M_PI*hemi.x();
- Real hr=SCIRun::Sqrt(hemi.y());
- Real hx=hr*cos(hphi);
- Real hy=hr*sin(hphi);
- Real hz=1 - hx*hx - hy*hy;
- hz=(hz>0?SCIRun::Sqrt(hz):0);
-
- Vector out=Vector(hx, hy, hz).normal();
- Vector dir=v0*out.x() + v1*out.y() + normal*out.z();
- dir.normalize();
-
- // Set ray origin and direction
- rays.setOrigin(i, rays.getHitPosition(i));
- rays.setDirection(i, dir);
+ for (int i=rays.begin(); i<rays.end(); ++i) {
+ // Compute an ONB at the surface point
+ Vector normal=rays.getNormal(i);
+ Vector v0(Cross(normal, Vector(1,0,0)));
+ if (v0.length2()==0)
+ v0=Cross(normal, Vector(0,1,0));
+ Vector v1=Cross(normal, v0);
+ v0.normalize();
+ v1.normalize();
+
+ // Generate a random direction in the hemisphere
+ Vector2D hemi=sample_groups[hidx[d]][i];
+ Real hphi=2.0*M_PI*hemi.x();
+ Real hr=SCIRun::Sqrt(hemi.y());
+ Real hx=hr*cos(hphi);
+ Real hy=hr*sin(hphi);
+ Real hz=1 - hx*hx - hy*hy;
+ hz=(hz>0?SCIRun::Sqrt(hz):0);
+
+ Vector out=Vector(hx, hy, hz).normal();
+ Vector dir=v0*out.x() + v1*out.y() + normal*out.z();
+ dir.normalize();
+
+ // Set ray origin and direction
+ rays.setOrigin(i, rays.getHitPosition(i));
+ rays.setDirection(i, dir);
- // Update attenutation
- atten.set(i, atten.get(i)*Dot(normal, dir));
- }
+ // Update attenutation
+ atten.set(i, atten.get(i)*Dot(normal, dir));
+ }
- // Reset ray packet
- rays.setAllFlags(0);
- rays.setFlag(RayPacket::NormalizedDirections);
- rays.resetHits();
-
- // Intersect rays with the geometry
- scene->getObject()->intersect(rctx, rays);
-
- // Prepare ray packet for next iteration
- unsigned int validRays=0;
- for (unsigned int i=rays.begin(); i<rays.end();) {
- if (rays.wasHit(i)) {
- // Find a run of rays that hit an object
- unsigned int end=i + 1;
- while (end < rays.end() && rays.wasHit(end))
- ++end;
-
- // Compute hit positions and normals
- RayPacket sub(rays, i, end);
- sub.computeHitPositions();
- sub.computeNormals(rctx);
-
- // Store hit positions, normals for valid hits
- for (unsigned int j=sub.begin(); j<sub.end(); ++j) {
- Real dotprod=Dot(sub.getNormal(j), -sub.getDirection(j));
- if (dotprod>0) {
- rays.setHitPosition(validRays, sub.getHitPosition(j));
- rays.setNormal(validRays, sub.getNormal(j));
- atten.set(validRays, atten.get(j));
- ++validRays;
- } else {
- // An invalid hit, resulting from:
- //
- // 1. Intersecting spheres---Ray origin is inside of
one
- // sphere and it hits the inside surface of the
other
- //
- // 2. Ray origin is coincident with the surface of a
- // neighboring sphere---May result in some crazy
- // math, and thus a negative dot product
- //
- // Either way, ignore the hit and mark the texel for
- // dilation
- dynplt->inside[u][v] += 1;
- dilateTexture=true;
- }
+ // Reset ray packet
+ rays.setAllFlags(0);
+ rays.setFlag(RayPacket::NormalizedDirections);
+ rays.resetHits();
+
+ // Intersect rays with the geometry
+ context->scene->getObject()->intersect(rctx, rays);
+
+ // Prepare ray packet for next iteration
+ unsigned int validRays=0;
+ for (unsigned int i=rays.begin(); i<rays.end();) {
+ if (rays.wasHit(i)) {
+ // Find a run of rays that hit an object
+ unsigned int end=i + 1;
+ while (end < rays.end() && rays.wasHit(end))
+ ++end;
+
+ // Compute hit positions and normals
+ RayPacket sub(rays, i, end);
+ sub.computeHitPositions();
+ sub.computeNormals(rctx);
+
+ // Store hit positions, normals for valid hits
+ for (unsigned int j=sub.begin(); j<sub.end(); ++j) {
+ Real dotprod=Dot(sub.getNormal(j), -sub.getDirection(j));
+ if (dotprod>0) {
+ rays.setHitPosition(validRays, sub.getHitPosition(j));
+ rays.setNormal(validRays, sub.getNormal(j));
+ atten.set(validRays, atten.get(j));
+ ++validRays;
+ } else {
+ // An invalid hit, resulting from:
+ //
+ // 1. Intersecting spheres---Ray origin is inside of one
+ // sphere and it hits the inside surface of the other
+ //
+ // 2. Ray origin is coincident with the surface of a
+ // neighboring sphere---May result in some crazy
+ // math, and thus a negative dot product
+ //
+ // Either way, ignore the hit and mark the texel for
+ // dilation
+ dynplt->inside[u][v] += 1;
+ dilateTexture=true;
}
+ }
- i=end;
- } else {
- // Find a run of rays that didn't hit anything
- unsigned int end=i + 1;
- while (end < rays.end() && !rays.wasHit(end))
- ++end;
-
- // Shade the rays, and accumulate background color
- RayPacket sub(rays, i, end);
- scene->getBackground()->shade(rctx, sub);
+ i=end;
+ } else {
+ // Find a run of rays that didn't hit anything
+ unsigned int end=i + 1;
+ while (end < rays.end() && !rays.wasHit(end))
+ ++end;
+
+ // Shade the rays, and accumulate background color
+ RayPacket sub(rays, i, end);
+ context->scene->getBackground()->shade(rctx, sub);
- for (unsigned int j=sub.begin(); j<sub.end(); ++j)
- ambient += sub.getColor(j).luminance();
+ for (unsigned int j=sub.begin(); j<sub.end(); ++j)
+ ambient += sub.getColor(j).luminance();
- i=end;
- }
+ i=end;
}
-
- // Terminate at current depth, if necessary
- if (validRays==0)
- break;
-
- // Update the ray packet configuration, loop to next depth
- rays.setDepth(rays.getDepth() + 1);
- rays.resize(validRays);
}
- // Store the result
- dynplt->texture[u][v] += context->Ka*ambient + context->Kd*diffuse;
+ // Terminate at current depth, if necessary
+ if (validRays==0)
+ break;
+
+ // Update the ray packet configuration, loop to next depth
+ rays.setDepth(rays.getDepth() + 1);
+ rays.resize(validRays);
}
- // Normalize the texel
- dynplt->texture[u][v] *= inv_nsamples;
+ // Store the result
+ dynplt->texture[u][v] += context->Ka*ambient + context->Kd*diffuse;
}
- }
-
- if (context->dilate && dilateTexture)
- dynplt->dilate(context);
-
- // XXX: maybe use a transaction to mark the texture as valid and prevent
- // tearing in the middle of a frame
- grid->valid[particle]=true;
- // Receive next message
- msg=context->queue->receive();
+ // Normalize the texel
+ dynplt->texture[u][v] *= inv_nsamples;
+ }
}
- if (exitSem)
- exitSem->up();
+ return dilateTexture;
}
void DynPLTWorker::terminate(MantaInterface*)
Modified: trunk/Engine/Control/DynPLTWorker.h
==============================================================================
--- trunk/Engine/Control/DynPLTWorker.h (original)
+++ trunk/Engine/Control/DynPLTWorker.h Sun Jun 4 14:14:24 2006
@@ -59,6 +59,11 @@
void terminate(MantaInterface*);
private:
+ bool renderAmbient(const DynPLTContext* context, const RenderContext&
rctx,
+ const DynPLTGridSpheres* grid, unsigned int particle);
+ bool renderGlobal(const DynPLTContext* context, const RenderContext&
rctx,
+ const DynPLTGridSpheres* grid, unsigned int particle);
+
const DynPLTContext* context;
unsigned int id;
MT_RNG rng;
Modified: trunk/Model/Primitives/DynPLTGridSpheres.cc
==============================================================================
--- trunk/Model/Primitives/DynPLTGridSpheres.cc (original)
+++ trunk/Model/Primitives/DynPLTGridSpheres.cc Sun Jun 4 14:14:24 2006
@@ -1,5 +1,7 @@
#include <Core/Color/RegularColorMap.h>
+#include <Interface/AmbientLight.h>
+#include <Interface/LightSet.h>
#include <Interface/RayPacket.h>
#include <Engine/Control/DynPLTWorker.h>
#include <Model/Primitives/DynPLTGridSpheres.h>
@@ -20,12 +22,18 @@
cerr<<"Initializing DynPLTGridSpheres\n";
plts.resize(nspheres);
valid.resize(nspheres);
+ allocated.resize(nspheres);
requested.resize(nspheres);
for (unsigned int i=0; i<nspheres; ++i) {
plts[i]=0;
- valid[i]=false;
requested[i]=false;
+ allocated[i]=false;
+ valid[i]=false;
}
+
+ // XXX: hard coded for now
+ // textureMode=AmbientOcclusion;
+ textureMode=GlobalIllumination;
}
DynPLTGridSpheres::~DynPLTGridSpheres(void)
@@ -36,6 +44,69 @@
void DynPLTGridSpheres::shade(const RenderContext& context,
RayPacket& rays) const
{
+ switch (textureMode) {
+ case AmbientOcclusion:
+ shadeAmbient(context, rays);
+ break;
+ case GlobalIllumination:
+ default:
+ shadeGlobal(context, rays);
+ break;
+ }
+}
+
+void DynPLTGridSpheres::shadeAmbient(const RenderContext& context,
+ RayPacket& rays) const
+{
+ ColorArray ambient;
+
+ for (unsigned int i=rays.begin(); i<rays.end(); ) {
+ // Find a run of rays that hit the same particle
+ int offset=rays.scratchpad<int>(i);
+ unsigned int end=i + 1;
+ while (end < rays.end() && rays.scratchpad<int>(end)==offset)
+ ++end;
+
+ int particle=offset/nvars;
+
+ // Compute ambient light for the rays
+ RayPacket sub(rays, i, end);
+ if (valid[particle]) {
+ // Compute diffuse colors
+ Packet<Color> diffuse;
+ mapDiffuseColors(diffuse, sub);
+
+ // Compute textured ambient luminance
+ sub.computeTextureCoordinates2(context);
+
+ for (unsigned int i=sub.begin(); i<sub.end(); ++i) {
+ Real luminance=computeLuminance(i, sub, particle);
+ for (int j=0; j < Color::NumComponents; ++j)
+ ambient[j][i]=luminance;
+ }
+ } else {
+ // Request texture generation, if necessary
+ if (!requested[particle]) {
+ // Create and post message
+ DynPLTMessage msg(particle, this);
+ if (queue->trySend(msg))
+ requested[particle]=true;
+ }
+
+ // Use default ambient light while texture is invalid
+ activeLights->getAmbientLight()->computeAmbient(context, sub, ambient);
+ }
+
+ i=end;
+ }
+
+ // Shade the rays
+ GridSpheres::lambertianShade(context, rays, ambient);
+}
+
+void DynPLTGridSpheres::shadeGlobal(const RenderContext& context,
+ RayPacket& rays) const
+{
for (unsigned int i=rays.begin(); i<rays.end(); ) {
// Find a run of rays that hit the same particle
int offset=rays.scratchpad<int>(i);
@@ -55,40 +126,8 @@
// Compute textured luminance
sub.computeTextureCoordinates2(context);
- for (unsigned int i=sub.begin(); i < sub.end(); ++i) {
- // Wrap in x (assumes xres is a power of two)
- Real x=sub.getTexCoords2(i, 0)*XRES;
- int lx=static_cast<int>(x) & (XRES - 1);
- int hx=(lx + 1) & (XRES - 1);
- Real wx=x - lx;
-
- // Clamp in y
- Real y=sub.getTexCoords2(i, 1);
- int ly;
- Real wy;
- if (y < 0) {
- ly=0;
- wy=0;
- } else {
- y *= YRES - 1;
- ly=static_cast<int>(y);
- if (ly > YRES - 1) {
- ly=YRES - 1;
- wy=0;
- } else {
- wy=y - ly;
- }
- }
-
- int hy=ly + 1;
-
- // Interpolate
- Real a=(plts[particle]->texture[lx][ly]*(1 - wx) +
- plts[particle]->texture[hx][ly]*wx);
- Real b=(plts[particle]->texture[lx][hy]*(1 - wx) +
- plts[particle]->texture[hx][hy]*wx);
- Real luminance=a*(1 - wy) + b*wy;
-
+ for (unsigned int i=sub.begin(); i<sub.end(); ++i) {
+ Real luminance=computeLuminance(i, rays, particle);
sub.setColor(i, diffuse.get(i)*luminance);
}
} else {
@@ -106,6 +145,44 @@
i=end;
}
+}
+
+Real DynPLTGridSpheres::computeLuminance(unsigned int ray_idx, RayPacket&
rays,
+ unsigned int particle) const
+{
+ // Wrap in x (assumes xres is a power of two)
+ Real x=rays.getTexCoords2(ray_idx, 0)*XRES;
+ int lx=static_cast<int>(x) & (XRES - 1);
+ int hx=(lx + 1) & (XRES - 1);
+ Real wx=x - lx;
+
+ // Clamp in y
+ Real y=rays.getTexCoords2(ray_idx, 1);
+ int ly;
+ Real wy;
+ if (y < 0) {
+ ly=0;
+ wy=0;
+ } else {
+ y *= YRES - 1;
+ ly=static_cast<int>(y);
+ if (ly > YRES - 1) {
+ ly=YRES - 1;
+ wy=0;
+ } else {
+ wy=y - ly;
+ }
+ }
+
+ int hy=ly + 1;
+
+ // Bi-linearly interpolate
+ Real a=(plts[particle]->texture[lx][ly]*(1 - wx) +
+ plts[particle]->texture[hx][ly]*wx);
+ Real b=(plts[particle]->texture[lx][hy]*(1 - wx) +
+ plts[particle]->texture[hx][hy]*wx);
+
+ return a*(1 - wy) + b*wy;
}
void DynPLT::dilate(const DynPLTContext* context)
Modified: trunk/Model/Primitives/DynPLTGridSpheres.h
==============================================================================
--- trunk/Model/Primitives/DynPLTGridSpheres.h (original)
+++ trunk/Model/Primitives/DynPLTGridSpheres.h Sun Jun 4 14:14:24 2006
@@ -50,6 +50,11 @@
class DynPLTGridSpheres : public GridSpheres
{
public:
+ enum {
+ AmbientOcclusion,
+ GlobalIllumination
+ } TextureMode;
+
DynPLTGridSpheres(SCIRun::Mailbox<DynPLTMessage>* queue, float* spheres,
int nspheres, int nvars, int ncells, int depth,
Real radius, int ridx, RegularColorMap* cmap, int
cidx);
@@ -59,6 +64,15 @@
const LightSet* getActiveLights(void) const { return activeLights; }
+ unsigned int getTextureMode(void) const { return textureMode; }
+ void setTextureMode(unsigned int mode)
+ {
+ if (textureMode != mode) {
+ invalidateTextures();
+ textureMode=mode;
+ }
+ }
+
Vector getCenter(int particle) const
{
float* data=spheres + particle*nvars;
@@ -78,12 +92,28 @@
return radius;
}
- mutable vector<bool> valid;
mutable vector<DynPLT*> plts;
+ mutable vector<bool> allocated;
+ mutable vector<bool> valid;
private:
+ void shadeAmbient(const RenderContext& context, RayPacket& rays) const;
+ void shadeGlobal(const RenderContext& context, RayPacket& rays) const;
+ Real computeLuminance(unsigned int ray_idx, RayPacket& rays,
+ unsigned int particle) const;
+
+ void invalidateTextures(void)
+ {
+ for (unsigned int i=0; i<nspheres; ++i) {
+ requested[i]=false;
+ valid[i]=false;
+ }
+ }
+
SCIRun::Mailbox<DynPLTMessage>* queue;
mutable vector<bool> requested;
+
+ unsigned int textureMode;
};
}
Modified: trunk/Model/Primitives/GridSpheres.cc
==============================================================================
--- trunk/Model/Primitives/GridSpheres.cc (original)
+++ trunk/Model/Primitives/GridSpheres.cc Sun Jun 4 14:14:24 2006
@@ -542,18 +542,23 @@
void GridSpheres::shade(const RenderContext& context, RayPacket& rays) const
{
+ // Compute ambient light
+ ColorArray ambient;
+ activeLights->getAmbientLight()->computeAmbient(context, rays, ambient);
+
// Shade a bunch of rays that have intersected the same particle
+ lambertianShade(context, rays, ambient);
+}
+void GridSpheres::lambertianShade(const RenderContext& context, RayPacket&
rays,
+ ColorArray& totalLight) const
+{
// Compute normals
rays.computeNormals(context);
// Compute colors
Packet<Color> diffuse;
mapDiffuseColors(diffuse, rays);
-
- // Compute ambient contributions for all rays
- ColorArray totalLight;
- activeLights->getAmbientLight()->computeAmbient(context, rays, totalLight);
// Normalize directions for proper dot product computation
rays.normalizeDirections();
Modified: trunk/Model/Primitives/GridSpheres.h
==============================================================================
--- trunk/Model/Primitives/GridSpheres.h (original)
+++ trunk/Model/Primitives/GridSpheres.h Sun Jun 4 14:14:24 2006
@@ -4,6 +4,7 @@
#include <Core/Color/Color.h>
#include <Core/Geometry/BBox.h>
+#include <Interface/RayPacket.h>
#include <Interface/TexCoordMapper.h>
#include <Interface/Texture.h>
#include <Model/Primitives/PrimitiveCommon.h>
@@ -80,6 +81,9 @@
#endif // USE_OPTIMIZED_FCNS
void intersectSphereDefault(RayPacket& rays, int ray_idx, int idx,
const Vector& center, float radius2) const;
+
+ void lambertianShade(const RenderContext& context, RayPacket& rays,
+ ColorArray& totalLight) const;
float* spheres;
int nspheres;
- [MANTA] r1097 - in trunk: Engine/Control Model/Primitives, cgribble, 06/04/2006
Archive powered by MHonArc 2.6.16.