/* Utility method to update shader parameters based on available lighting information. */ static void updateLightShader( MHWRender::MShaderInstance *shaderInstance, const MHWRender::MDrawContext & context, const MSelectionList * lightList ) { if (!shaderInstance) return; // Check pass context information to see if we are in a shadow // map update pass. If so do nothing. // const MHWRender::MPassContext & passCtx = context.getPassContext(); const MStringArray & passSem = passCtx.passSemantics(); bool handlePass = true; for (unsigned int i=0; i<passSem.length() && handlePass; i++) { // Handle special pass drawing. // if (passSem[i] == MHWRender::MPassContext::kShadowPassSemantic) { handlePass = false; } } if (!handlePass) return; // // Perform light shader update with lighting information // If the light list is not empty then use that light's information. // Otherwise choose the first appropriate light which can cast shadows. // // Defaults in case there are no lights // bool globalShadowsOn = false; bool localShadowsOn = false; bool shadowDirty = false; MFloatVector direction(0.0f, 0.0f, 1.0f); float lightIntensity = 0.0f; // If no lights then black out the light float lightColor[3] = { 0.0f, 0.0f, 0.0f }; MStatus status; // Scan to find the first N lights that has a direction component in it // It's possible we find no lights. // MHWRender::MDrawContext::LightFilter considerAllSceneLights = MHWRender::MDrawContext::kFilteredIgnoreLightLimit; unsigned int lightCount = context.numberOfActiveLights(considerAllSceneLights); if (lightCount) { MFloatArray floatVals; MIntArray intVals; MHWRender::MTextureAssignment shadowResource; shadowResource.texture = NULL; MHWRender::MSamplerStateDesc samplerDesc; MMatrix shadowViewProj; float shadowColor[3] = { 0.0f, 0.0f, 0.0f }; unsigned int i=0; bool foundDirectional = false; for (i=0; i<lightCount && !foundDirectional ; i++) { MHWRender::MLightParameterInformation *lightParam = context.getLightParameterInformation( i, considerAllSceneLights ); if (lightParam) { // Prune against light list if any. if (lightList && lightList->length()) { if (!lightList->hasItem(lightParam->lightPath())) continue; } MStringArray params; lightParam->parameterList(params); for (unsigned int p=0; p<params.length(); p++) { MString pname = params[p]; MHWRender::MLightParameterInformation::StockParameterSemantic semantic = lightParam->parameterSemantic( pname ); switch (semantic) { // Pick a few light parameters to pick up as an example case MHWRender::MLightParameterInformation::kWorldDirection: lightParam->getParameter( pname, floatVals ); direction = MFloatVector( floatVals[0], floatVals[1], floatVals[2] ); foundDirectional = true; break; case MHWRender::MLightParameterInformation::kIntensity: lightParam->getParameter( pname, floatVals ); lightIntensity = floatVals[0]; break; case MHWRender::MLightParameterInformation::kColor: lightParam->getParameter( pname, floatVals ); lightColor[0] = floatVals[0]; lightColor[1] = floatVals[1]; lightColor[2] = floatVals[2]; break; // Pick up shadowing parameters case MHWRender::MLightParameterInformation::kGlobalShadowOn: lightParam->getParameter( pname, intVals ); if (intVals.length()) globalShadowsOn = (intVals[0] != 0) ? true : false; break; case MHWRender::MLightParameterInformation::kShadowOn: lightParam->getParameter( pname, intVals ); if (intVals.length()) localShadowsOn = (intVals[0] != 0) ? true : false; break; case MHWRender::MLightParameterInformation::kShadowViewProj: lightParam->getParameter( pname, shadowViewProj); break; case MHWRender::MLightParameterInformation::kShadowMap: lightParam->getParameter( pname, shadowResource ); break; case MHWRender::MLightParameterInformation::kShadowDirty: if (intVals.length()) shadowDirty = (intVals[0] != 0) ? true : false; break; case MHWRender::MLightParameterInformation::kShadowSamp: lightParam->getParameter( pname, samplerDesc ); break; case MHWRender::MLightParameterInformation::kShadowColor: lightParam->getParameter( pname, floatVals ); shadowColor[0] = floatVals[0]; shadowColor[1] = floatVals[1]; shadowColor[2] = floatVals[2]; break; default: break; } } /* for params */ } if (foundDirectional && globalShadowsOn && localShadowsOn && shadowResource.texture) { void *resourceHandle = shadowResource.texture->resourceHandle(); if (resourceHandle) { static bool debugShadowBindings = false; status = shaderInstance->setParameter("mayaShadowPCF1_shadowMap", shadowResource ); if (status == MStatus::kSuccess && debugShadowBindings) fprintf(stderr, "Bound shadow map to shader param mayaShadowPCF1_shadowMap\n"); status = shaderInstance->setParameter("mayaShadowPCF1_shadowViewProj", shadowViewProj ); if (status == MStatus::kSuccess && debugShadowBindings) fprintf(stderr, "Bound shadow map transform to shader param mayaShadowPCF1_shadowViewProj\n"); status = shaderInstance->setParameter("mayaShadowPCF1_shadowColor", &shadowColor[0] ); if (status == MStatus::kSuccess && debugShadowBindings) fprintf(stderr, "Bound shadow map color to shader param mayaShadowPCF1_shadowColor\n"); } MHWRender::MRenderer* renderer = MHWRender::MRenderer::theRenderer(); if (renderer) { MHWRender::MTextureManager* textureManager = renderer->getTextureManager(); if (textureManager) { textureManager->releaseTexture(shadowResource.texture); } } shadowResource.texture = NULL; } } } // Set up parameters which should be set regardless of light existence. status = shaderInstance->setParameter("mayaDirectionalLight_direction", &( direction[0] )); status = shaderInstance->setParameter("mayaDirectionalLight_intensity", lightIntensity ); status = shaderInstance->setParameter("mayaDirectionalLight_color", &( lightColor[0] )); status = shaderInstance->setParameter("mayaShadowPCF1_mayaGlobalShadowOn", globalShadowsOn); status = shaderInstance->setParameter("mayaShadowPCF1_mayaShadowOn", localShadowsOn); }
/* From the draw context, get the list of lights and queue the ones we are interested in into the "desired list" */ MStatus shadowPrepass::execute( const MHWRender::MDrawContext & context ) { MHWRender::MRenderer* theRenderer = MHWRender::MRenderer::theRenderer(); if (!theRenderer) return MStatus::kSuccess; // Skip lighting modes where there are no lights which can // cast shadows MHWRender::MDrawContext::LightingMode lightingMode = context.getLightingMode(); if (lightingMode != MHWRender::MDrawContext::kSelectedLights && lightingMode != MHWRender::MDrawContext::kSceneLights) { return MStatus::kSuccess; } MHWRender::MDrawContext::LightFilter lightFilter = MHWRender::MDrawContext::kFilteredIgnoreLightLimit; unsigned int nbSceneLights = context.numberOfActiveLights(lightFilter); for (unsigned int i=0; i<nbSceneLights; i++) { MHWRender::MLightParameterInformation* lightInfo = context.getLightParameterInformation( i, lightFilter ); if (!lightInfo) continue; // Get the actually Maya light node MStatus status = MStatus::kFailure; MDagPath lightPath = lightInfo->lightPath(&status); if (status != MStatus::kSuccess || !lightPath.isValid()) continue; // Would be good to have an API method here to indicate if it // casts shadows MIntArray intVals; // Check if light is enabled, and emits any lighting MHWRender::MLightParameterInformation::StockParameterSemantic semantic = MHWRender::MLightParameterInformation::kLightEnabled; if (MStatus::kSuccess == lightInfo->getParameter( semantic, intVals )) { if (intVals.length()) { if (intVals[0] == 0) continue; } } semantic = MHWRender::MLightParameterInformation::kEmitsDiffuse; if (MStatus::kSuccess == lightInfo->getParameter( semantic, intVals )) { if (intVals.length()) { if (intVals[0] == 0) continue; } } semantic = MHWRender::MLightParameterInformation::kEmitsSpecular; if (MStatus::kSuccess == lightInfo->getParameter( semantic, intVals )) { if (intVals.length()) { if (intVals[0] == 0) continue; } } // Check if local shadows are enabled. semantic = MHWRender::MLightParameterInformation::kShadowOn; if (MStatus::kSuccess == lightInfo->getParameter( semantic, intVals )) { if (intVals.length()) { if (intVals[0] == 0) continue; } } // Check if the shadow is "dirty" bool shadowIsDirty = false; semantic = MHWRender::MLightParameterInformation::kShadowDirty; if (MStatus::kSuccess == lightInfo->getParameter( semantic, intVals )) { if (intVals.length()) { if (intVals[0] == 0) // continue; shadowIsDirty = intVals[0] != 0 ? true : false ; } } // Check the light list to prune, if not already pruned bool prune = false; if (lightingMode != MHWRender::MDrawContext::kSelectedLights) { if (mLightList && mLightList->length()) { prune = !mLightList->hasItem(lightInfo->lightPath()); } } static bool debugShadowRequests = false; // Set that we require shadows for this light if (!prune) { if (debugShadowRequests) fprintf(stderr, "QUEUE light shadows for %s, shadowDirty = %d\n", lightPath.fullPathName().asChar(), shadowIsDirty); theRenderer->setLightRequiresShadows( lightPath.node(), true ); } // Set that we DON'T require shadows for this light else { if (debugShadowRequests) fprintf(stderr, "DEQUEUE light shadows for %s, shadowDirty = %d\n", lightPath.fullPathName().asChar(), shadowIsDirty); theRenderer->setLightRequiresShadows( lightPath.node(), false ); } } return MStatus::kSuccess; }
/* 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; }