Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Camera with locked parameters #50

Open
mottosso opened this issue Mar 15, 2016 · 3 comments
Open

Camera with locked parameters #50

mottosso opened this issue Mar 15, 2016 · 3 comments
Labels

Comments

@mottosso
Copy link
Member

Goal

Enable capturing of camera where some parameters are locked.

At the moment, a camera may have connected or otherwise locked channels in which case capture.py fails.

Implementation

Either do not change these settings and move on, or create a duplicate of the camera with identical settings that we can modify.

@mottosso mottosso added the bug label Mar 15, 2016
@BigRoy
Copy link
Collaborator

BigRoy commented Mar 15, 2016

Would it work to temporarily duplicate only the camera shape so that it's parented under the same transform? Or duplicate the whole transform and parent it under the original camera?

We should avoid having to bake the transformation of the camera.

@mottosso
Copy link
Member Author

Could do.

@BigRoy
Copy link
Collaborator

BigRoy commented Sep 12, 2016

Here's another thing I thought of.

import contextlib
import maya.cmds as mc


@contextlib.contextmanager
def muted_value(attr, value):
    """Mute an attribute and force a specific value during the context.

    This allows you to set a non-animated value for the duration of the
    context even if the original input is keyed or connected to an output.

    Note:
        This will fail on referenced attributes that are locked on the
        reference since it's impossible to "unlock" referenced attributes.
        Just like a regular maya.cmds.setAttr

    """

    locked = mc.getAttr(attr, lock=True)
    muted = mc.mute(attr, query=True)

    # Query the original mute value so we can re-apply it
    # afterwards (only required if it was originally muted)
    if muted:
        mute_connections = mc.listConnections(attr, 
                                              source=True, 
                                              destination=False)
        mute_node = mc.ls(mute_connections, type="mute")[0]
        original = mc.getAttr(mute_node + ".hold")
    else:
        original = mc.getAttr(attr)

    # We'll disable autokey so setting a value temporarily
    # doesn't secretly apply any keys. Store the original state
    # so we can re-apply afterwards, leaving the scene unaltered.
    autokey = mc.autoKeyframe(query=True, state=True)

    try:

        # We need to unlock the attribute to do anything with it
        if locked:
            mc.setAttr(attr, lock=False)

        # Ensure no keys are set when setting value
        mc.autoKeyframe(state=False)

        # Using alteredValue we can overwrite the attributes
        # value even when it is keyed/connected.
        mc.setAttr(attr, value, alteredValue=True)
        mc.mute(attr)

        yield

    finally:
        # If originally muted we want to remute
        # it again, but with the original value.
        if muted:
            mc.setAttr(attr, original, alteredValue=True)
            mc.mute(attr)    # update muted value
        else:
            mc.mute(attr, disable=True, force=True)
            mc.setAttr(attr, original, alteredValue=True)

        # Relock it if required
        if locked:
            mc.setAttr(attr, lock=locked)

        mc.autoKeyframe(state=autokey)

You can set an attribute's value in Maya even if it is connected or keyed by using the alteredValue flag in setAttr. This will override any of the values currently incoming and the value is only present until a re-evaluation (unless it has no inputs at all, then there's no re-evaluation as it remains). Nevertheless this context manager applies the value only during the context and afterwards ensures the correctly original value is present.

The only moment this will not work is when the attribute is locked on a reference, since attributes on a reference cannot be unlocked/locked.

It's pretty elaborately commented to explain why it needs specific elements in the code.

A note about querying the original mute value. It is required because technically one can mute an attribute while it is unlocked and then set a different value. The new value that was set isn't actually the mute value (switching frames would set it to the muted value again). As such to be entirely correct when we "re-mute" afterwards we want to apply the held muted value, not the current one in the scene since it could be wrong. (Even though I imagine this exact scenario happening only 0.00001% of the cases.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants