void AmbientOcclusion::computeCSZ (RenderDevice* rd, const Array<shared_ptr<Framebuffer> >& cszFramebuffers, const shared_ptr<Texture>& csZBuffer, const AmbientOcclusionSettings& settings, const shared_ptr<Texture>& depthBuffer, const Vector3& clipInfo, const shared_ptr<Texture>& peeledDepthBuffer) { BEGIN_PROFILER_EVENT("computeCSZ"); // Generate level 0 cszFramebuffers[0]->set(Framebuffer::DEPTH, depthBuffer); rd->push2D(cszFramebuffers[0]); { rd->clear(true, false, false); rd->setDepthWrite(false); rd->setDepthTest(RenderDevice::DEPTH_GREATER); Args args; args.setUniform(SYMBOL_clipInfo, clipInfo); args.setUniform(SYMBOL_DEPTH_AND_STENCIL_buffer, depthBuffer, Sampler::buffer()); alwaysAssertM(!settings.useDepthPeelBuffer || notNull(peeledDepthBuffer), "Tried to run AO with peeled depth buffer, but buffer was null"); args.setMacro(SYMBOL_USE_PEELED_DEPTH_BUFFER, settings.useDepthPeelBuffer); if (settings.useDepthPeelBuffer) { args.setUniform(SYMBOL_peeledDepthBuffer, peeledDepthBuffer, Sampler::buffer()); } args.setRect(rd->viewport()); LAUNCH_SHADER("AmbientOcclusion_reconstructCSZ.*", args); } rd->pop2D(); // Generate the other levels (we don't have a depth texture to cull against for these) for (int i = 1; i <= MAX_MIP_LEVEL; ++i) { Args args; args.setUniform("CSZ_buffer", csZBuffer, cszSamplerSettings()); args.setMacro(SYMBOL_USE_PEELED_DEPTH_BUFFER, settings.useDepthPeelBuffer); rd->push2D(cszFramebuffers[i]); { rd->clear(); args.setUniform(SYMBOL_previousMIPNumber, i - 1); args.setRect(rd->viewport()); LAUNCH_SHADER("AmbientOcclusion_minify.*", args); } rd->pop2D(); } END_PROFILER_EVENT(); }
shared_ptr<Texture> TemporalFilter::apply (RenderDevice* rd, const Vector3& clipConstant, const Vector4& projConstant, const CFrame& currentCameraFrame, const CFrame& prevCameraFrame, const shared_ptr<Texture>& unfilteredValue, const shared_ptr<Texture>& depth, const shared_ptr<Texture>& ssVelocity, const Vector2& guardBandSize, int numFilterComponents, const Settings& settings) { if (settings.hysteresis == 0.0f) { return unfilteredValue; } alwaysAssertM((settings.hysteresis >= 0.0f) && (settings.hysteresis <= 1.0f), "TemporalFilter::Settings::hysteresis must be in [0.0, 1.0]"); alwaysAssertM(notNull(unfilteredValue) && notNull(depth) && notNull(ssVelocity), "Sent null buffer to TemporalFilter::apply"); alwaysAssertM((numFilterComponents >= 1) && (numFilterComponents <= 4), "numFilterComponents must be between 1 and 4"); if (isNull(m_previousDepthBuffer) || isNull(m_previousTexture) || (m_previousDepthBuffer->vector2Bounds() != depth->vector2Bounds()) || (m_previousTexture->vector2Bounds() != unfilteredValue->vector2Bounds())) { unfilteredValue->copyInto(m_previousTexture); depth->copyInto(m_previousDepthBuffer); m_resultFramebuffer = Framebuffer::create(Texture::createEmpty("TemporalFilter::m_resultFramebuffer", m_previousTexture->width(), m_previousTexture->height(), m_previousTexture->format())); Texture::copy(m_previousTexture, m_resultFramebuffer->texture(0)); return m_resultFramebuffer->texture(0); } rd->push2D(m_resultFramebuffer); { Args args; args.setMacro("FILTER_COMPONENT_COUNT", numFilterComponents); ssVelocity->setShaderArgs(args, "ssVelocity_", Sampler::buffer()); unfilteredValue->setShaderArgs(args, "unfilteredValue_", Sampler::buffer()); depth->setShaderArgs(args, "depth_", Sampler::buffer()); m_previousDepthBuffer->setShaderArgs(args, "previousDepth_", Sampler::video()); m_previousTexture->setShaderArgs(args, "previousValue_", Sampler::video()); args.setUniform("guardBandSize", guardBandSize); args.setUniform("cameraToWorld", currentCameraFrame); args.setUniform("cameraToWorldPrevious", prevCameraFrame); args.setUniform("clipInfo", clipConstant); args.setUniform("projInfo", projConstant); settings.setArgs(args); args.setRect(rd->viewport()); LAUNCH_SHADER("TemporalFilter_apply.*", args); m_resultFramebuffer->texture(0)->copyInto(m_previousTexture); depth->copyInto(m_previousDepthBuffer); } rd->pop2D(); return m_resultFramebuffer->texture(0); }
void App::handlePlayPulses() { for (int i = m_currentPlayPulses.size() - 1; i >= 0; --i) { int currentSampleIndex = (g_sampleWindowIndex * g_currentAudioBuffer.size()); shared_ptr<SonicSculpturePiece> piece = m_currentPlayPulses[i].piece; int endIndex = m_currentPlayPulses[i].initialSample + (piece->size() * g_currentAudioBuffer.size()); RenderDevice* rd = RenderDevice::current; static shared_ptr<Framebuffer> playPulseFB = Framebuffer::create("Play Pulse FB"); shared_ptr<UniversalMaterial> material = piece->material(); if (currentSampleIndex >= endIndex) { playPulseFB->set(Framebuffer::COLOR0, material->emissive().texture()); rd->push2D(playPulseFB); { rd->setColorClearValue(Color3::black()); rd->clear(); } rd->pop2D(); material->emissive().texture()->generateMipMaps(); m_currentPlayPulses.remove(i); continue; } float alpha = float(currentSampleIndex - m_currentPlayPulses[i].initialSample) / (endIndex - m_currentPlayPulses[i].initialSample); playPulseFB->set(Framebuffer::COLOR0, material->emissive().texture()); rd->push2D(playPulseFB); { Args args; args.setUniform("pulsePos", alpha * playPulseFB->width()); args.setRect(rd->viewport()); LAUNCH_SHADER("playPulse.pix", args); } rd->pop2D(); material->emissive().texture()->generateMipMaps(); } }
// Called before the application loop begins. Load data here and // not in the constructor so that common exceptions will be // automatically caught. void App::onInit() { RenderDevice* rd = renderDevice; Vector2 destSize(1024, 1024); const Rect2D& dest = Rect2D::xywh(Vector2(0, 0), destSize); Args args; // args.appendToPreamble("#define KERNEL_RADIUS 9\nfloat gaussCoef[KERNEL_RADIUS] = float[KERNEL_RADIUS](0.00194372, 0.00535662, 0.01289581, 0.02712094, 0.04982645, 0.07996757, 0.11211578, 0.13731514, 0.14691596);"); rd->push2D(dest); { args.setRect(dest); LAUNCH_SHADER("apply.*", args); } rd->pop2D(); // Or Equivalently: //GaussianBlur::apply(renderDevice, Texture::createEmpty("test",1024,1024)); }
void App::onGraphics3D(RenderDevice* rd, Array<shared_ptr<Surface> >& surface3D) { m_gbuffer->setSpecification(m_gbufferSpecification); m_gbuffer->resize(m_framebuffer->width(), m_framebuffer->height()); m_gbuffer->prepare(rd, activeCamera(), 0, -(float)previousSimTimeStep(), m_settings.depthGuardBandThickness, m_settings.colorGuardBandThickness); m_renderer->render(rd, m_framebuffer, m_depthPeelFramebuffer, scene()->lightingEnvironment(), m_gbuffer, surface3D); rd->pushState(m_framebuffer); { rd->setProjectionAndCameraMatrix(m_debugCamera->projection(), m_debugCamera->frame()); Array< shared_ptr<Surface> > mySurfaces; // Pose our model based on the manipulator axes model->pose(mySurfaces, manipulator->frame()); // Set up shared arguments Args args; configureShaderArgs(args); // Send model geometry to the graphics card CFrame cframe; for (int i = 0; i < mySurfaces.size(); ++i) { // Downcast to UniversalSurface to access its fields shared_ptr<UniversalSurface> surface = dynamic_pointer_cast<UniversalSurface>(mySurfaces[i]); if (notNull(surface)) { surface->getCoordinateFrame(cframe); rd->setObjectToWorldMatrix(cframe); surface->gpuGeom()->setShaderArgs(args); // (If you want to manually set the material properties and vertex attributes // for shader args, they can be accessed from the fields of the gpuGeom.) LAUNCH_SHADER("phong.*", args); } } } rd->popState(); swapBuffers(); rd->clear(); m_film->exposeAndRender(rd, m_debugCamera->filmSettings(), m_framebuffer->texture(0), 1); }
void DepthOfField::composite (RenderDevice* rd, shared_ptr<Texture> packedBuffer, shared_ptr<Texture> blurBuffer, Vector2int16 outputGuardBandThickness) { rd->push2D(); { rd->clear(true, false, false); rd->setGuardBandClip2D(outputGuardBandThickness); Args args; // Shift blur buffer texture coordinates by the guard band amount args.setUniform("blurBuffer", blurBuffer); args.setUniform("packedBuffer", packedBuffer); args.setUniform("shift", Vector2(outputGuardBandThickness)); args.setRect(rd->viewport()); LAUNCH_SHADER("DepthOfField_composite.*", args); } rd->pop2D(); }
void AmbientOcclusion::blurOneDirection (RenderDevice* rd, const AmbientOcclusionSettings& settings, const shared_ptr<Texture>& depthBuffer, const Vector4& projConstant, const shared_ptr<Texture>& normalBuffer, const Vector2int16& axis, const shared_ptr<Framebuffer>& framebuffer, const shared_ptr<Texture>& source) { framebuffer->set(Framebuffer::DEPTH, depthBuffer); rd->push2D(framebuffer); { // For quick early-out testing vs. skybox rd->setDepthTest(RenderDevice::DEPTH_GREATER); rd->setColorClearValue(Color3::white()); rd->clear(true, false, false); Args args; args.setUniform(SYMBOL_source, source, Sampler::buffer()); args.setUniform(SYMBOL_axis, axis); args.setUniform(SYMBOL_projInfo, projConstant); args.setMacro(SYMBOL_EDGE_SHARPNESS, settings.edgeSharpness); args.setMacro(SYMBOL_SCALE, settings.blurStepSize); args.setMacro(SYMBOL_R, settings.blurRadius); args.setMacro(SYMBOL_MDB_WEIGHTS, settings.monotonicallyDecreasingBilateralWeights ? 1 : 0); if (settings.useNormalsInBlur && settings.useNormalBuffer) { normalBuffer->setShaderArgs(args, "normal_", Sampler::buffer()); } rd->setClip2D(Rect2D::xyxy((float)m_guardBandSize, (float)m_guardBandSize, rd->viewport().width() - m_guardBandSize, rd->viewport().height() - m_guardBandSize)); args.setRect(rd->viewport()); LAUNCH_SHADER("AmbientOcclusion_blur.*", args); } rd->pop2D(); }
void App::onGraphics3D(RenderDevice* rd, Array<shared_ptr<Surface> >& allSurfaces) { // This implementation is equivalent to the default GApp's. It is repeated here to make it // easy to modify rendering. If you don't require custom rendering, just delete this // method from your application and rely on the base class. if (! scene()) { return; } m_gbuffer->setSpecification(m_gbufferSpecification); m_gbuffer->resize(m_framebuffer->width(), m_framebuffer->height()); m_gbuffer->prepare(rd, activeCamera(), 0, -(float)previousSimTimeStep(), m_settings.hdrFramebuffer.depthGuardBandThickness, m_settings.hdrFramebuffer.colorGuardBandThickness); m_renderer->render(rd, m_framebuffer, m_depthPeelFramebuffer, scene()->lightingEnvironment(), m_gbuffer, allSurfaces); // Debug visualizations and post-process effects rd->pushState(m_framebuffer); { if (m_enableSVO) { rd->clear(); //rd->setProjectionAndCameraMatrix(activeCamera()->projection(), activeCamera()->frame()); rd->push2D(); const Vector2int32 guardBand(m_settings.hdrFramebuffer.depthGuardBandThickness - m_settings.hdrFramebuffer.colorGuardBandThickness); const Vector2int32 colorRegionExtent = Vector2int32(m_framebuffer->vector2Bounds()) - guardBand * 2; Args args; rd->setGuardBandClip2D(Vector2int16(guardBand)); args.setRect(rd->viewport()); Matrix4 proj; activeCamera()->getProjectUnitMatrix(m_framebuffer->rect2DBounds(), proj); float focalLength = proj[0][0]; m_svo->setCurSvoId(0); args.setUniform("guardBand", guardBand); args.setUniform("focalLength", focalLength); args.setUniform("renderRes", Vector2(colorRegionExtent)); args.setUniform("renderResI", colorRegionExtent); args.setUniform("screenRatio", float(colorRegionExtent.y) / float(colorRegionExtent.x)); m_svo->connectToShader(args, Access::READ, m_svo->maxDepth(), m_svo->maxDepth()); rd->setColorWrite(true); rd->setDepthWrite(false); const Matrix4& cameraToVoxelMatrix = Matrix4(m_svo->svoToWorldMatrix()).inverse() * activeCamera()->frame(); args.setUniform("cameraToVoxelMatrix", cameraToVoxelMatrix); args.setUniform("voxelToWorldMatrix", m_svo->svoToWorldMatrix()); args.setUniform("worldToVoxelMatrix", m_svo->worldToSVOMatrix()); args.setUniform("wsCameraPos", activeCamera()->frame().translation); scene()->lightingEnvironment().setShaderArgs(args); args.setUniform("raycastingConeFactor", m_voxelConeAperture); rd->setDepthTest(RenderDevice::DEPTH_ALWAYS_PASS); // TODO: write gl_FragDepth and use a regular depth test here m_gbuffer->texture(GBuffer::Field::DEPTH_AND_STENCIL)->setShaderArgs(args, "depth_", Sampler::buffer()); //rd->setBlendFunc(RenderDevice::BLEND_ONE, RenderDevice::BLEND_ONE_MINUS_SRC_ALPHA); LAUNCH_SHADER("raycast.pix", args); rd->pop2D(); } // Call to make the App show the output of debugDraw(...) rd->setProjectionAndCameraMatrix(activeCamera()->projection(), activeCamera()->frame()); drawDebugShapes(); const shared_ptr<Entity>& selectedEntity = (notNull(developerWindow) && notNull(developerWindow->sceneEditorWindow)) ? developerWindow->sceneEditorWindow->selectedEntity() : shared_ptr<Entity>(); scene()->visualize(rd, selectedEntity, allSurfaces, sceneVisualizationSettings(), activeCamera()); rd->setPolygonOffset(-0.2f); if (m_debugSVONodes) { m_svo->visualizeNodes(rd, m_debugSVONodeLevel); } if (m_debugSVOFragments) { m_svo->visualizeFragments(rd); } rd->setPolygonOffset(0.0f); // Post-process special effects m_depthOfField->apply(rd, m_framebuffer->texture(0), m_framebuffer->texture(Framebuffer::DEPTH), activeCamera(), m_settings.hdrFramebuffer.depthGuardBandThickness - m_settings.hdrFramebuffer.colorGuardBandThickness); m_motionBlur->apply(rd, m_framebuffer->texture(0), m_gbuffer->texture(GBuffer::Field::SS_EXPRESSIVE_MOTION), m_framebuffer->texture(Framebuffer::DEPTH), activeCamera(), m_settings.hdrFramebuffer.depthGuardBandThickness - m_settings.hdrFramebuffer.colorGuardBandThickness); } rd->popState(); if ((submitToDisplayMode() == SubmitToDisplayMode::MAXIMIZE_THROUGHPUT) && (!renderDevice->swapBuffersAutomatically())) { // We're about to render to the actual back buffer, so swap the buffers now. // This call also allows the screenshot and video recording to capture the // previous frame just before it is displayed. swapBuffers(); } // Clear the entire screen (needed even though we'll render over it, since // AFR uses clear() to detect that the buffer is not re-used.) rd->clear(); // Perform gamma correction, bloom, and SSAA, and write to the native window frame buffer m_film->exposeAndRender(rd, activeCamera()->filmSettings(), m_framebuffer->texture(0)); }
void App::onGraphics3D(RenderDevice* rd, Array<shared_ptr<Surface> >& surface3D) { rd->setColorClearValue(Color3::white() * 0.3f); rd->clear(); // Draw the base geometry as gray with black wireframe rd->pushState(); rd->setPolygonOffset(0.2f); rd->setColor(Color3::white() * 0.10f); for (int i = 0; i < m_sceneGeometry.size(); ++i) { const shared_ptr<Surface>& surface = m_sceneGeometry[i]; CFrame cframe; surface->getCoordinateFrame(cframe); rd->setObjectToWorldMatrix(cframe); surface->sendGeometry(rd); } rd->popState(); rd->pushState(); rd->setColor(Color3::black()); rd->setRenderMode(RenderDevice::RENDER_WIREFRAME); for (int i = 0; i < m_sceneGeometry.size(); ++i) { const shared_ptr<Surface>& surface = m_sceneGeometry[i]; CFrame cframe; surface->getCoordinateFrame(cframe); rd->setObjectToWorldMatrix(cframe); surface->sendGeometry(rd); } rd->popState(); // Draw the extruded geometry as colored wireframe with "glass" interior rd->pushState(); rd->setBlendFunc(RenderDevice::BLEND_ONE, RenderDevice::BLEND_ONE); rd->setDepthWrite(false); Args args; args.setUniform("intensity", 0.1f); CFrame cframe; for (int i = 0; i < m_sceneGeometry.size(); ++i) { const shared_ptr<UniversalSurface>& surface = dynamic_pointer_cast<UniversalSurface>(m_sceneGeometry[i]); if (surface) { surface->getCoordinateFrame(cframe); args.setUniform("MVP", rd->invertYMatrix() * rd->projectionMatrix() * (rd->cameraToWorldMatrix().inverse() * cframe)); surface->gpuGeom()->setShaderArgs(args); LAUNCH_SHADER("extrude.*", args); } } rd->popState(); rd->pushState(); rd->setRenderMode(RenderDevice::RENDER_WIREFRAME); rd->setCullFace(CullFace::NONE); args.setUniform("intensity", 1.0f); for (int i = 0; i < m_sceneGeometry.size(); ++i) { const shared_ptr<UniversalSurface>& surface = dynamic_pointer_cast<UniversalSurface>(m_sceneGeometry[i]); if (notNull(surface)) { surface->getCoordinateFrame(cframe); args.setUniform("MVP", rd->invertYMatrix() * rd->projectionMatrix() * (rd->cameraToWorldMatrix().inverse() * cframe)); surface->gpuGeom()->setShaderArgs(args); LAUNCH_SHADER("extrude.*", args); } } rd->popState(); drawDebugShapes(); }
void AmbientOcclusion::computeRawAO (RenderDevice* rd, const AmbientOcclusionSettings& settings, const shared_ptr<Texture>& depthBuffer, const Vector3& clipConstant, const Vector4& projConstant, const float projScale, const shared_ptr<Texture>& csZBuffer, const shared_ptr<Texture>& peeledCSZBuffer, const shared_ptr<Texture>& normalBuffer) { debugAssert(projScale > 0); m_rawAOFramebuffer->set(Framebuffer::DEPTH, depthBuffer); rd->push2D(m_rawAOFramebuffer); { // For quick early-out testing vs. skybox rd->setDepthTest(RenderDevice::DEPTH_GREATER); // Values that are never touched due to the depth test will be white rd->setColorClearValue(Color3::white()); rd->clear(true, false, false); Args args; args.setMacro(SYMBOL_NUM_SAMPLES, settings.numSamples); args.setMacro(SYMBOL_NUM_SPIRAL_TURNS, settings.numSpiralTurns()); args.setUniform(SYMBOL_radius, settings.radius); args.setUniform(SYMBOL_bias, settings.bias); args.setUniform(SYMBOL_clipInfo, clipConstant); args.setUniform(SYMBOL_projInfo, projConstant); args.setUniform(SYMBOL_projScale, projScale); args.setUniform(SYMBOL_CS_Z_buffer, csZBuffer, cszSamplerSettings()); args.setUniform(SYMBOL_intensityDivR6, (float)(settings.intensity / powf(settings.radius, 6.0f))); args.setUniform(SYMBOL_intensity, settings.intensity); args.setUniform(SYMBOL_radius2, square(settings.radius)); args.setUniform(SYMBOL_invRadius2, 1.0f / square(settings.radius)); args.setMacro("TEMPORALLY_VARY_SAMPLES", settings.temporallyVarySamples); const bool useDepthPeel = settings.useDepthPeelBuffer; args.setMacro(SYMBOL_USE_DEPTH_PEEL, useDepthPeel ? 1 : 0); if ( useDepthPeel ) { bool cszPackedTogether = csZBuffer == peeledCSZBuffer; args.setMacro(SYMBOL_CS_Z_PACKED_TOGETHER, cszPackedTogether ? 1 : 0); if ( !cszPackedTogether ) { args.setUniform(SYMBOL_peeled_CS_Z_buffer, peeledCSZBuffer, cszSamplerSettings()); const Vector2& peeledExtent = peeledCSZBuffer->rect2DBounds().extent(); const Vector2& unpeeledExtent = csZBuffer->rect2DBounds().extent(); bool differingDepthExtents = peeledExtent != unpeeledExtent; args.setMacro(SYMBOL_DIFFERENT_DEPTH_RESOLUTIONS, differingDepthExtents ? 1 : 0); if (differingDepthExtents) { //TODO: only calculate one dimension in the first place args.setUniform(SYMBOL_peeledToUnpeeledScale, (peeledExtent / unpeeledExtent).x); } } else { args.setMacro(SYMBOL_DIFFERENT_DEPTH_RESOLUTIONS, 0); } } else { args.setMacro(SYMBOL_CS_Z_PACKED_TOGETHER, 0); args.setMacro(SYMBOL_DIFFERENT_DEPTH_RESOLUTIONS, 0); } if (settings.useNormalBuffer && notNull(normalBuffer)) { debugAssertM(normalBuffer->encoding().frame == FrameName::CAMERA, "AmbientOcclusion expects camera-space normals"); normalBuffer->setShaderArgs(args, "normal_", Sampler::buffer()); } rd->setClip2D(Rect2D::xyxy((float)m_guardBandSize, (float)m_guardBandSize, rd->viewport().width() - m_guardBandSize, rd->viewport().height() - m_guardBandSize)); args.setRect(rd->viewport()); LAUNCH_SHADER("AmbientOcclusion_AO.*", args); } rd->pop2D(); }