/*
	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;
}
Example #3
0
File: utils.cpp Project: JT-a/USD
/* 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;
}