RGB SubsurfacePathtracer::trace(Ray p_ray, Vector3d cameraPos, int p_depth) { RGB radiance(0,0,0); RGB localRadiance(0,0,0); RayIntersection nearestRayInt; p_depth++; bool intersected = false; if(scene->kdTree == NULL) { intersected = p_ray.nearestIntersection(scene->getObjects(), scene->getObjectCount(), &nearestRayInt); } else { intersected = scene->kdTree->nearestIntersection(&p_ray, &nearestRayInt); } if(intersected) { if(!(nearestRayInt.object->getShader()->isLight() && p_ray.getDiffuse())) { //local ilumination: Vector3d viewVec = cameraPos - nearestRayInt.point; viewVec.normalize(); localRadiance = nearestRayInt.object->getShader()->getDiffuseRadiance(nearestRayInt.object, nearestRayInt.point, nearestRayInt.normal, nearestRayInt.uv, viewVec, scene); radiance = localRadiance; if(nearestRayInt.object->getShader()->hasSubsurface()) { radiance = radiance + subsurface(&nearestRayInt, &p_ray); //return subsurface(&nearestRayInt, &p_ray); } int outVecsCount = 0; RGB indirectRadiance; if(p_depth == 1) { for(int i = 0; i < 5; i++) { if(p_depth < maxDepth) { Ray outRays[10]; RGB values[10]; outVecsCount = nearestRayInt.object->getShader()->getBRDFSampledRays(nearestRayInt.object, nearestRayInt.point, nearestRayInt.normal, nearestRayInt.uv, viewVec, p_ray.getDir(), outRays, values); for(int s = 0; s < outVecsCount; s++) { Ray ray = outRays[s]; indirectRadiance = indirectRadiance + (trace(ray, cameraPos, p_depth) * values[s]) ; } } indirectRadiance; } indirectRadiance = indirectRadiance / 5; } else { if(p_depth < maxDepth) { Ray outRays[10]; RGB values[10]; outVecsCount = nearestRayInt.object->getShader()->getBRDFSampledRays(nearestRayInt.object, nearestRayInt.point, nearestRayInt.normal, nearestRayInt.uv, viewVec, p_ray.getDir(), outRays, values); for(int s = 0; s < outVecsCount; s++) { Ray ray = outRays[s]; indirectRadiance = indirectRadiance + (trace(ray, cameraPos, p_depth) * values[s]) ; } } } if(outVecsCount > 0) { radiance = radiance + indirectRadiance; } } } else if(scene->getBackground() != NULL) { radiance = scene->getBackground()->getRadianceAt(p_ray.getPoint(), p_ray.getPointAt(FAR_AWAY)); } return radiance; }
void GameUpdateDraw( NimblePixMap& map, NimbleRequest request ) { #if WRITING_DOCUMENTATION new(&TheMap) NimblePixMap( map ); #endif /* WRITING_DOCUMENTATION */ WavefieldRect = NimbleRect(PanelWidth,map.height()/2,map.width(),map.height()); NimblePixMap subsurface(map,WavefieldRect); NimblePixMap seismogramClip( map,NimbleRect(PanelWidth,0,map.width(),map.height()/2) ); if( request & NimbleUpdate ) { ShowGeology.update(); ShowSeismic.update(); } const NimbleRequest pausedRequest = IsPaused ? request-NimbleUpdate : request; SeismogramUpdateDraw( seismogramClip, pausedRequest&NimbleUpdate, TheColorFunc, IsAutoGainOn ); WavefieldFunctor wf(subsurface, pausedRequest); SeismogramFunctor sf( seismogramClip, pausedRequest&NimbleDraw ); ReservoirFunctor rf( pausedRequest ); #if PARALLEL tbb::parallel_invoke( wf, sf, rf ); #else wf(); sf(); rf(); #endif if( pausedRequest & NimbleUpdate ) { DrillBit.update(); UpdateDuckAndRig(); } if( request & NimbleDraw ) { ClickableSetEnd = ClickableSet; const int wavefieldWidth = map.width()-PanelWidth; Assert(wavefieldWidth%4==0); const int wavefieldHeight = map.height()/2; ReservoirDrawHoles( subsurface ); if( DrillY>0 ) DrillBit.drawOn( subsurface, RigX-DrillBit.width()/2, DrillY-5 ); if( ShowReservoir ) ReservoirDraw( subsurface ); NimblePixMap spriteClip( map, NimbleRect( PanelWidth, 0, map.width(), map.height() ));\ NimblePixel greenPixel = map.pixel( NimbleColor( 0, NimbleColor::FULL, 0 )); NimblePixel redPixel = map.pixel( NimbleColor( NimbleColor::FULL, 0, 0 )); const int lineHeight = map.height()/2-1; if( CultureBeginX<CultureEndX ) { spriteClip.draw( NimbleRect( 0, lineHeight, CultureBeginX, lineHeight+1 ), greenPixel ); spriteClip.draw( NimbleRect( CultureBeginX, lineHeight-1, CultureEndX, lineHeight+2 ), redPixel ); spriteClip.draw( NimbleRect( CultureEndX, lineHeight, spriteClip.width(), lineHeight+1 ), greenPixel ); Culture.drawOn( spriteClip, CultureBeginX+(CultureEndX-CultureBeginX)/2-Culture.width()/2, map.height()/2-Culture.height() ); } else { spriteClip.draw( NimbleRect( 0, lineHeight, spriteClip.width(), lineHeight+1 ), greenPixel ); } OilRig->drawOn( spriteClip, RigX-OilRig->width()/2, OilRigVerticalOffset ); if( DuckGoingLeft ) DuckLeft.drawOn( spriteClip, DuckX-50, map.height()/2-DuckLeft.height()+12 ); else DuckRight.drawOn( spriteClip, DuckX-(DuckRight.width()-50), map.height()/2-DuckLeft.height()+12 ); NimblePixMap panelClip( map, NimbleRect( 0, 0, PanelWidth, map.height() )); PanelBackground.drawOn( panelClip ); int cashMeterY = map.height()- 50 -CashMeter.height(); int levelMeterY = cashMeterY - 10 - LevelMeter.height(); // The Min is there so that if there is room, the green line artistically lines up // with the top of the fluid meters. int fluidMeterY = Min(levelMeterY - 10 - WaterMeter.height(), map.height()/2 ); if( ScoreState.isDisplayingScore() ) { LevelMeter.drawOn( map, PanelWidth/2-LevelMeter.width()/2, levelMeterY ); CashMeter.drawOn( map, PanelWidth/2-CashMeter.width()/2, cashMeterY ); } int meterMarginX = (PanelWidth-WaterMeter.width()-OilMeter.width()-GasMeter.width())/4; WaterMeter.drawOn( map, meterMarginX, fluidMeterY ); OilMeter.drawOn( map, PanelWidth/2-OilMeter.width()/2, fluidMeterY ); GasMeter.drawOn( map, PanelWidth-meterMarginX-GasMeter.width(), fluidMeterY ); if( VisibleDialog ) { if( VisibleDialog==&TheAboutTheAuthorDialog || VisibleDialog==&TheLevelContinueDialog ) // Center it on screen VisibleDialog->drawOn( map, map.width()/2-VisibleDialog->width()/2, map.height()/2-VisibleDialog->height()/2 ); else if( VisibleDialog==&TheKeyboardHelpDialog ) // Put in upper right corner VisibleDialog->drawOn( map, map.width()*.95f-VisibleDialog->width(), map.height()*.05f ); else // Put it in upper left portion of seismogram VisibleDialog->drawOn( map, PanelWidth+24, 24 ); } int tabTop1 = 50; int tabTop2 = tabTop1+2*TheFont.height(); int tabLeft1 = PanelWidth/8; int tabLeft2 = PanelWidth*5/8; int airGunTop = tabTop2+2*TheFont.height();; AirgunMeter.drawOn( map, PanelWidth/2-AirgunMeter.width()/2, airGunTop ); if( ShowFrameRate ) { FrameRateMeter.setValue( EstimateFrameRate() ); FrameRateMeter.drawOn( map, PanelWidth/2-FrameRateMeter.width()/2, fluidMeterY-FrameRateMeter.height()-15 ); } const int tabSpacing = PanelWidth/4; DrawClickable( TheFileMenu, map, tabLeft1, tabTop1 ); DrawClickable( TheHelpMenu, map, tabLeft2, tabTop1 ); // The "isTabbed" tests below do some ad-hoc occlusion testing. if( TheFileMenu.isTabbed() ) DrawClickable( TheModelMenu, map, tabLeft1, tabTop2 ); if( TheFileMenu.isTabbed() && TheHelpMenu.isTabbed() ) DrawClickable( TheViewMenu, map, tabLeft2, tabTop2 ); } ScoreState.update(); }