void HdxShadowTask::_Execute(HdTaskContext* ctx) { HD_TRACE_FUNCTION(); HF_MALLOC_TAG_FUNCTION(); // Extract the lighting context information from the task context GlfSimpleLightingContextRefPtr lightingContext; if (!_GetTaskContextData(ctx, HdxTokens->lightingContext, &lightingContext)) { return; } if (_depthBiasEnable) { glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(_depthBiasSlopeFactor, _depthBiasConstantFactor); } else { glDisable(GL_POLYGON_OFFSET_FILL); } // XXX: Move conversion to sync time once Task header becomes private. glDepthFunc(HdConversions::GetGlDepthFunc(_depthFunc)); glEnable(GL_PROGRAM_POINT_SIZE); // Generate the actual shadow maps GlfSimpleShadowArrayRefPtr const shadows = lightingContext->GetShadows(); for(size_t shadowId = 0; shadowId < shadows->GetNumLayers(); shadowId++) { // Bind the framebuffer that will store shadowId shadow map shadows->BeginCapture(shadowId, true); // Render the actual geometry in the collection _passes[shadowId]->Execute(_renderPassStates[shadowId], HdTokens->geometry); // Unbind the buffer and move on to the next shadow map shadows->EndCapture(shadowId); } // restore GL states to default glDisable(GL_PROGRAM_POINT_SIZE); glDisable(GL_POLYGON_OFFSET_FILL); }
void HdxShadowTask::Sync(HdSceneDelegate* delegate, HdTaskContext* ctx, HdDirtyBits* dirtyBits) { HD_TRACE_FUNCTION(); HF_MALLOC_TAG_FUNCTION(); GLF_GROUP_FUNCTION(); // Extract the lighting context information from the task context GlfSimpleLightingContextRefPtr lightingContext; if (!_GetTaskContextData(ctx, HdxTokens->lightingContext, &lightingContext)) { return; } GlfSimpleLightVector const glfLights = lightingContext->GetLights(); GlfSimpleShadowArrayRefPtr const shadows = lightingContext->GetShadows(); HdRenderIndex &renderIndex = delegate->GetRenderIndex(); const bool dirtyParams = (*dirtyBits) & HdChangeTracker::DirtyParams; if (dirtyParams) { // Extract the new shadow task params from exec if (!_GetTaskParams(delegate, &_params)) { return; } } if (!renderIndex.IsSprimTypeSupported(HdPrimTypeTokens->simpleLight)) { return; } // Iterate through all lights and for those that have shadows enabled // and ensure we have enough passes to render the shadows. size_t passCount = 0; for (size_t lightId = 0; lightId < glfLights.size(); lightId++) { const HdStLight* light = static_cast<const HdStLight*>( renderIndex.GetSprim(HdPrimTypeTokens->simpleLight, glfLights[lightId].GetID())); if (!glfLights[lightId].HasShadow()) { continue; } // It is possible the light is nullptr for area lights converted to // simple lights, however they should not have shadows enabled. TF_VERIFY(light); // Extract the collection from the HD light VtValue vtShadowCollection = light->Get(HdLightTokens->shadowCollection); const HdRprimCollection &col = vtShadowCollection.IsHolding<HdRprimCollection>() ? vtShadowCollection.Get<HdRprimCollection>() : HdRprimCollection(); // Creates or reuses a pass with the right geometry that will be // used during Execute phase to draw the shadow maps. if (passCount < _passes.size()) { // Note here that we may want to sort the passes by collection // to invalidate fewer passes if the collections match already. // SetRprimCollection checks for identity changes on the collection // and no-ops in that case. _passes[passCount]->SetRprimCollection(col); } else { // Create a new pass if we didn't have enough already, HdRenderPassSharedPtr p = boost::make_shared<HdSt_RenderPass> (&renderIndex, col); _passes.push_back(p); } passCount++; } // Shrink down to fit to conserve resources // We may want hysteresis here if we find the count goes up and down // frequently. if (_passes.size() > passCount) { _passes.resize(passCount); } // Shrink down to fit to conserve resources if (_renderPassStates.size() > _passes.size()) { _renderPassStates.resize(_passes.size()); } // Ensure all passes have the right params set. if (dirtyParams) { TF_FOR_ALL(it, _renderPassStates) { _UpdateDirtyParams(*it, _params); } }
void HdxShadowTask::_Sync(HdTaskContext* ctx) { HD_TRACE_FUNCTION(); HF_MALLOC_TAG_FUNCTION(); // Extract the lighting context information from the task context GlfSimpleLightingContextRefPtr lightingContext; if (!_GetTaskContextData(ctx, HdxTokens->lightingContext, &lightingContext)) { return; } GlfSimpleShadowArrayRefPtr const shadows = lightingContext->GetShadows(); _TaskDirtyState dirtyState; _GetTaskDirtyState(HdTokens->geometry, &dirtyState); // Check if the collection version has changed, if so, it means // that we should extract the new collections // from the lights in the render index, and then recreate the passes // required to render the shadow maps const bool collectionChanged = (_collectionVersion != dirtyState.collectionVersion); if ((dirtyState.bits & HdChangeTracker::DirtyParams) || collectionChanged) { _collectionVersion = dirtyState.collectionVersion; // Extract the new shadow task params from exec HdxShadowTaskParams params; if (!_GetSceneDelegateValue(HdTokens->params, ¶ms)) { return; } _depthBiasEnable = params.depthBiasEnable; _depthBiasConstantFactor = params.depthBiasConstantFactor; _depthBiasSlopeFactor = params.depthBiasSlopeFactor; _depthFunc = params.depthFunc; // XXX TODO: What to do about complexity? // We can now use the light information now // and create a pass for each _passes.clear(); _renderPassStates.clear(); HdSceneDelegate* delegate = GetDelegate(); const HdRenderIndex &renderIndex = delegate->GetRenderIndex(); // Extract the HD lights used to render the scene from the // task context, we will use them to find out what // lights are dirty and if we need to update the // collection for shadows mapping // XXX: This is inefficient, need to be optimized SdfPathVector sprimPaths = renderIndex.GetSprimSubtree( HdPrimTypeTokens->light, SdfPath::AbsoluteRootPath()); SdfPathVector lightPaths = HdxSimpleLightTask::ComputeIncludedLights( sprimPaths, params.lightIncludePaths, params.lightExcludePaths); HdxLightPtrConstVector lights; TF_FOR_ALL (it, lightPaths) { const HdxLight *light = static_cast<const HdxLight *>( renderIndex.GetSprim( HdPrimTypeTokens->light, *it)); if (light != nullptr) { lights.push_back(light); } } GlfSimpleLightVector const glfLights = lightingContext->GetLights(); TF_VERIFY(lights.size() == glfLights.size()); // Iterate through all lights and for those that have // shadows enabled we will extract the colection from // the render index and create a pass that during execution // it will be used for generating each shadowmap for (size_t lightId = 0; lightId < glfLights.size(); lightId++) { if (!glfLights[lightId].HasShadow()) { continue; } // Extract the collection from the HD light VtValue vtShadowCollection = lights[lightId]->Get(HdxLightTokens->shadowCollection); const HdRprimCollection &col = vtShadowCollection.IsHolding<HdRprimCollection>() ? vtShadowCollection.Get<HdRprimCollection>() : HdRprimCollection(); // Creates a pass with the right geometry that will be // use during Execute phase to draw the maps HdRenderPassSharedPtr p = boost::make_shared<HdRenderPass> (&delegate->GetRenderIndex(), col); HdRenderPassShaderSharedPtr renderPassShadowShader (new HdRenderPassShader(HdxPackageRenderPassShadowShader())); HdRenderPassStateSharedPtr renderPassState (new HdRenderPassState(renderPassShadowShader)); // Update the rest of the renderpass state parameters for this pass renderPassState->SetOverrideColor(params.overrideColor); renderPassState->SetWireframeColor(params.wireframeColor); renderPassState->SetLightingEnabled(false); // XXX : This can be removed when Hydra has support for // transparent objects. renderPassState->SetAlphaThreshold(1.0 /* params.alphaThreshold */); renderPassState->SetTessLevel(params.tessLevel); renderPassState->SetDrawingRange(params.drawingRange); renderPassState->SetCullStyle(params.cullStyle); _passes.push_back(p); _renderPassStates.push_back(renderPassState); } }