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); }
/* static */ GlfSimpleLightingContextRefPtr px_vp20Utils::GetLightingContextFromDrawContext( const MHWRender::MDrawContext& context) { const GfVec4f blackColor(0.0f, 0.0f, 0.0f, 1.0f); const GfVec4f whiteColor(1.0f, 1.0f, 1.0f, 1.0f); GlfSimpleLightingContextRefPtr lightingContext = GlfSimpleLightingContext::New(); MStatus status; unsigned int numMayaLights = context.numberOfActiveLights(MHWRender::MDrawContext::kFilteredToLightLimit, &status); if (status != MS::kSuccess || numMayaLights < 1) { return lightingContext; } bool viewDirectionAlongNegZ = context.viewDirectionAlongNegZ(&status); if (status != MS::kSuccess) { // If we fail to find out the view direction for some reason, assume // that it's along the negative Z axis (OpenGL). viewDirectionAlongNegZ = true; } GlfSimpleLightVector lights; for (unsigned int i = 0; i < numMayaLights; ++i) { MHWRender::MLightParameterInformation* mayaLightParamInfo = context.getLightParameterInformation(i); if (!mayaLightParamInfo) { continue; } // Setup some default values before we read the light parameters. bool lightEnabled = true; bool lightHasPosition = false; GfVec4f lightPosition(0.0f, 0.0f, 0.0f, 1.0f); bool lightHasDirection = false; GfVec3f lightDirection(0.0f, 0.0f, -1.0f); if (!viewDirectionAlongNegZ) { // The convention for DirectX is positive Z. lightDirection[2] = 1.0f; } float lightIntensity = 1.0f; GfVec4f lightColor = blackColor; bool lightEmitsDiffuse = true; bool lightEmitsSpecular = false; float lightDecayRate = 0.0f; float lightDropoff = 0.0f; // The cone angle is 180 degrees by default. GfVec2f lightCosineConeAngle(-1.0f); float lightShadowBias = 0.0f; bool lightShadowOn = false; bool globalShadowOn = false; MStringArray paramNames; mayaLightParamInfo->parameterList(paramNames); for (unsigned int paramIndex = 0; paramIndex < paramNames.length(); ++paramIndex) { const MString paramName = paramNames[paramIndex]; const MHWRender::MLightParameterInformation::ParameterType paramType = mayaLightParamInfo->parameterType(paramName); const MHWRender::MLightParameterInformation::StockParameterSemantic paramSemantic = mayaLightParamInfo->parameterSemantic(paramName); MIntArray intValues; MFloatArray floatValues; switch (paramType) { case MHWRender::MLightParameterInformation::kBoolean: case MHWRender::MLightParameterInformation::kInteger: mayaLightParamInfo->getParameter(paramName, intValues); break; case MHWRender::MLightParameterInformation::kFloat: case MHWRender::MLightParameterInformation::kFloat2: case MHWRender::MLightParameterInformation::kFloat3: case MHWRender::MLightParameterInformation::kFloat4: mayaLightParamInfo->getParameter(paramName, floatValues); break; default: // Unsupported paramType. continue; break; } switch (paramSemantic) { case MHWRender::MLightParameterInformation::kLightEnabled: _GetLightingParam(intValues, floatValues, lightEnabled); break; case MHWRender::MLightParameterInformation::kWorldPosition: if (_GetLightingParam(intValues, floatValues, lightPosition)) { lightHasPosition = true; } break; case MHWRender::MLightParameterInformation::kWorldDirection: if (_GetLightingParam(intValues, floatValues, lightDirection)) { lightHasDirection = true; } break; case MHWRender::MLightParameterInformation::kIntensity: _GetLightingParam(intValues, floatValues, lightIntensity); break; case MHWRender::MLightParameterInformation::kColor: _GetLightingParam(intValues, floatValues, lightColor); break; case MHWRender::MLightParameterInformation::kEmitsDiffuse: _GetLightingParam(intValues, floatValues, lightEmitsDiffuse); break; case MHWRender::MLightParameterInformation::kEmitsSpecular: _GetLightingParam(intValues, floatValues, lightEmitsSpecular); break; case MHWRender::MLightParameterInformation::kDecayRate: _GetLightingParam(intValues, floatValues, lightDecayRate); break; case MHWRender::MLightParameterInformation::kDropoff: _GetLightingParam(intValues, floatValues, lightDropoff); break; case MHWRender::MLightParameterInformation::kCosConeAngle: _GetLightingParam(intValues, floatValues, lightCosineConeAngle); break; case MHWRender::MLightParameterInformation::kShadowBias: _GetLightingParam(intValues, floatValues, lightShadowBias); break; case MHWRender::MLightParameterInformation::kShadowOn: _GetLightingParam(intValues, floatValues, lightShadowOn); break; case MHWRender::MLightParameterInformation::kGlobalShadowOn: _GetLightingParam(intValues, floatValues, globalShadowOn); break; default: // Unsupported paramSemantic. continue; break; } if (!lightEnabled) { // Stop reading light parameters if the light is disabled. break; } } if (!lightEnabled) { // Skip to the next light if this light is disabled. continue; } lightColor[0] *= lightIntensity; lightColor[1] *= lightIntensity; lightColor[2] *= lightIntensity; // Populate a GlfSimpleLight from the light information from Maya. GlfSimpleLight light; GfVec4f lightAmbient = blackColor; GfVec4f lightDiffuse = blackColor; GfVec4f lightSpecular = blackColor; // We receive the cone angle from Maya as a pair of floats which // includes the penumbra, but GlfSimpleLights don't currently support // that, so we only use the primary cone angle value. float lightCutoff = GfRadiansToDegrees(std::acos(lightCosineConeAngle[0])); float lightFalloff = lightDropoff; // decayRate is actually an enum in Maya that we receive as a float: // - 0.0 = no attenuation // - 1.0 = linear attenuation // - 2.0 = quadratic attenuation // - 3.0 = cubic attenuation (not supported by GlfSimpleLight) GfVec3f lightAttenuation(0.0f); if (lightDecayRate > 1.5) { // Quadratic attenuation. lightAttenuation[2] = 1.0f; } else if (lightDecayRate > 0.5f) { // Linear attenuation. lightAttenuation[1] = 1.0f; } else { // No/constant attenuation. lightAttenuation[0] = 1.0f; } if (lightHasDirection && !lightHasPosition) { // This is a directional light. Set the direction as its position. lightPosition[0] = -lightDirection[0]; lightPosition[1] = -lightDirection[1]; lightPosition[2] = -lightDirection[2]; lightPosition[3] = 0.0f; // Revert direction to the default value. lightDirection = GfVec3f(0.0f, 0.0f, -1.0f); if (!viewDirectionAlongNegZ) { lightDirection[2] = 1.0f; } } if (!lightHasPosition && !lightHasDirection) { // This is an ambient light. lightAmbient = lightColor; } else { if (lightEmitsDiffuse) { lightDiffuse = lightColor; } if (lightEmitsSpecular) { // XXX: It seems that the specular color cannot be specified // separately from the diffuse color on Maya lights. lightSpecular = lightColor; } } light.SetAmbient(lightAmbient); light.SetDiffuse(lightDiffuse); light.SetSpecular(lightSpecular); light.SetPosition(lightPosition); light.SetSpotDirection(lightDirection); light.SetSpotCutoff(lightCutoff); light.SetSpotFalloff(lightFalloff); light.SetAttenuation(lightAttenuation); light.SetShadowBias(lightShadowBias); light.SetHasShadow(lightShadowOn && globalShadowOn); lights.push_back(light); } lightingContext->SetLights(lights); // XXX: These material settings match what we used to get when we read the // material from OpenGL. This should probably eventually be something more // sophisticated. GlfSimpleMaterial material; material.SetAmbient(whiteColor); material.SetDiffuse(whiteColor); material.SetSpecular(blackColor); material.SetEmission(blackColor); material.SetShininess(0.0001f); lightingContext->SetMaterial(material); lightingContext->SetSceneAmbient(blackColor); return lightingContext; }
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); } }
void My_TestGLDrawing::InitTest() { std::cout << "My_TestGLDrawing::InitTest()\n"; _stage = UsdStage::Open(GetStageFilePath()); SdfPathVector excludedPaths; if (UsdImagingGLEngine::IsHydraEnabled()) { std::cout << "Using HD Renderer.\n"; _engine.reset(new UsdImagingGLEngine( _stage->GetPseudoRoot().GetPath(), excludedPaths)); if (!_GetRenderer().IsEmpty()) { if (!_engine->SetRendererPlugin(_GetRenderer())) { std::cerr << "Couldn't set renderer plugin: " << _GetRenderer().GetText() << std::endl; exit(-1); } else { std::cout << "Renderer plugin: " << _GetRenderer().GetText() << std::endl; } } } else{ std::cout << "Using Reference Renderer.\n"; _engine.reset( new UsdImagingGLEngine(_stage->GetPseudoRoot().GetPath(), excludedPaths)); } std::cout << glGetString(GL_VENDOR) << "\n"; std::cout << glGetString(GL_RENDERER) << "\n"; std::cout << glGetString(GL_VERSION) << "\n"; if (_ShouldFrameAll()) { TfTokenVector purposes; purposes.push_back(UsdGeomTokens->default_); purposes.push_back(UsdGeomTokens->proxy); // Extent hints are sometimes authored as an optimization to avoid // computing bounds, they are particularly useful for some tests where // there is no bound on the first frame. bool useExtentHints = true; UsdGeomBBoxCache bboxCache(UsdTimeCode::Default(), purposes, useExtentHints); GfBBox3d bbox = bboxCache.ComputeWorldBound(_stage->GetPseudoRoot()); GfRange3d world = bbox.ComputeAlignedRange(); GfVec3d worldCenter = (world.GetMin() + world.GetMax()) / 2.0; double worldSize = world.GetSize().GetLength(); std::cerr << "worldCenter: " << worldCenter << "\n"; std::cerr << "worldSize: " << worldSize << "\n"; if (UsdGeomGetStageUpAxis(_stage) == UsdGeomTokens->z) { // transpose y and z centering translation _translate[0] = -worldCenter[0]; _translate[1] = -worldCenter[2]; _translate[2] = -worldCenter[1] - worldSize; } else { _translate[0] = -worldCenter[0]; _translate[1] = -worldCenter[1]; _translate[2] = -worldCenter[2] - worldSize; } } else { _translate[0] = GetTranslate()[0]; _translate[1] = GetTranslate()[1]; _translate[2] = GetTranslate()[2]; } if(IsEnabledTestLighting()) { if(UsdImagingGLEngine::IsHydraEnabled()) { // set same parameter as GlfSimpleLightingContext::SetStateFromOpenGL // OpenGL defaults _lightingContext = GlfSimpleLightingContext::New(); GlfSimpleLight light; if (IsEnabledCameraLight()) { light.SetPosition(GfVec4f(_translate[0], _translate[2], _translate[1], 0)); } else { light.SetPosition(GfVec4f(0, -.5, .5, 0)); } light.SetDiffuse(GfVec4f(1,1,1,1)); light.SetAmbient(GfVec4f(0,0,0,1)); light.SetSpecular(GfVec4f(1,1,1,1)); GlfSimpleLightVector lights; lights.push_back(light); _lightingContext->SetLights(lights); GlfSimpleMaterial material; material.SetAmbient(GfVec4f(0.2, 0.2, 0.2, 1.0)); material.SetDiffuse(GfVec4f(0.8, 0.8, 0.8, 1.0)); material.SetSpecular(GfVec4f(0,0,0,1)); material.SetShininess(0.0001f); _lightingContext->SetMaterial(material); _lightingContext->SetSceneAmbient(GfVec4f(0.2,0.2,0.2,1.0)); } else { glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); if (IsEnabledCameraLight()) { float position[4] = {_translate[0], _translate[2], _translate[1], 0}; glLightfv(GL_LIGHT0, GL_POSITION, position); } else { float position[4] = {0,-.5,.5,0}; glLightfv(GL_LIGHT0, GL_POSITION, position); } } } }