1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

mayaのカメラをなんとかしたい5 ~2Dカメラアニメーション~

1
Last updated at Posted at 2025-12-13

アニメーション作業をしている人を見ながら ふと

2次元カメラのアニメーションを確認するために
プレイブラスト書き出して、
AE起動して読み込ませて・・・・・

ん~めんどそう。

maya内である程度完結できんものかなぁ

カメラの機能を確認

この辺のアトリビュートですよねぇ
似たものがありますが、微妙に評価順とか機能とかで結果が違うんですよね。

image.png

例えばこの2つ。
一見すると同じように見えるんですが、filmTranslateは2D的な後処理なのに対して
filmOffsetはカメラの構造から調整している感じなのでパースに影響が出るようです。

filmOffset
シーンに対して、解像度ゲート(Resolution Gate)とフィルム ゲート(Film Gate)を垂直または水平にオフセットします。フィルム オフセット(Film Offset)の値を変更すると 2 次元トラックが生成されます(移動距離をインチ単位で指定します)。

filmTranslate
フィルムの移動(Film Translate)は 2D エフェクトで使用されます。この値は、人工的な 2D カメラ パンを表します。このフィールドに値を入力してください。

なので、2Dカメラワークよくある指示に対して

移動 -> filmTranslate
回転 -> filmRollValue
TU,TB -> postScale

で対応してみようかと思います。

構造

2Dカメラの動きをカメラを通して見ながら動かすのはなかなかやりづらそうなので、

2Dカメラワークの結果を見れるカメラ と 2Dカメラワーク全体?を見れるカメラに別けてみます。

image.png

あとは2Dカメラの動きを目視するための何か(メッシュかカーブ)を用意したいですね。

それはあまり邪魔になってほしくないので、nearClipPlane上にあると理想的かなと。

なのでこの時に作った機能が使えそうですね。

設置した板をとりあえず filmOffsetにつないで動かしてみるとー

image.png

めっちゃ動くので、倍率の調整が必要そうですね。
filmOffsetなので、filmGateを動かしてるかんじですかね。
であれば nearClipPlaneの距離とFocalLengthの比を使えば・・・・

filmOffsetはインチ単位なので、25.4で割らないといかんですね。

image.png

image.png

ピッタリ来ました。

postScale

この板のscaleX,Yは今ふさがっているので、一旦scaleZからpostScaleへつないでみます。

カメラ2から見るとこんな感じ。
postScaleをいじっても 板とカメラ2のresolutionGateが一致して欲しいですね。

image.png

scaleZをいじることで、板のscaleX,Yにもスケールがかかり カメラ2のpostScaleにも数値が入る
という流れで。

ただし postScale は 被写体にスケールがかかって見えるようにするので、相対的にはresolutionGateにはその逆数が入ってる感じですね。

なので

scaleX は resGateSizeH * scaleZ
scaleY は resGateSizeV * scaleZ
postScale は 1.0/scaleZ

となるようにつないでみました

image.png

image.png

ピッタリ来てますね。

filmRollValue

最後に回転を・・・・
これもとりあえずつないでみます。

image.png

これはー このままでよさそうですね。

まとめてスクリプト化

import maya.cmds as cmds
import maya.api.OpenMaya as om2

def getResGateSize(cameraName,resolutionW,resolutionH):

    sourceCamDAG = om2.MGlobal.getSelectionListByName(cameraName).getDagPath(0)
    sourceCamFn = om2.MFnCamera(sourceCamDAG)

    if cmds.getAttr(cameraName + ".filmFit") == 1:
        deviceAspectRatio = resolutionH / resolutionW
        sourceResH = sourceCamFn.horizontalFilmAperture * deviceAspectRatio
        sourceResW = sourceCamFn.horizontalFilmAperture

        
    elif cmds.getAttr(cameraName + ".filmFit") == 2:
        deviceAspectRatio = resolutionW / resolutionH 
        sourceResH = sourceCamFn.verticalFilmAperture 
        sourceResW = sourceCamFn.verticalFilmAperture * deviceAspectRatio

    return sourceResW*25.4,sourceResH*25.4

def addCameraProxyPos(cameraName):
    camProxy = cameraName + "_proxy"

    if cmds.objExists(camProxy) == False:
        cmds.createNode("transform",name = camProxy)	
        cmds.parentConstraint(cameraName,camProxy)
        
    return camProxy
                 
def addNearClipPos(cameraName):
    camProxy = addCameraProxyPos(cameraName)
    nearClipPoint = cameraName + "_nearClipPos"
    
    if cmds.objExists(nearClipPoint) == False:
        nearClipPoint = cmds.createNode("transform",name = nearClipPoint)
        cmds.parent(nearClipPoint,camProxy,r = True)		
        
        rev = cmds.createNode("floatMath")
        cmds.setAttr(rev + ".operation",2)
        cmds.setAttr(rev + ".floatB",-1)
        
        cmds.connectAttr(cameraName + ".nearClipPlane",rev+".floatA" )
        cmds.connectAttr(rev + ".outFloat",nearClipPoint+".tz" )

    return nearClipPoint

def connectClipCamera(destCamera,resGatePlane,lengthRatio):

    cmds.connectAttr(resGatePlane + ".rz" , destCamera + ".filmRollValue")

    invPostScale = cmds.createNode("floatMath")
    cmds.setAttr(invPostScale+ ".floatA", 1.0)
    cmds.connectAttr(resGatePlane + ".sz", invPostScale + ".floatB")
    cmds.setAttr(invPostScale + ".operation",3)
    cmds.connectAttr(invPostScale + ".outFloat",destCamera + ".postScale")

    transYConv = cmds.createNode("floatMath")
    cmds.setAttr(transYConv + ".operation",3)
    cmds.connectAttr(resGatePlane + ".ty",transYConv + ".floatA")
    cmds.connectAttr(lengthRatio + ".outFloat",transYConv + ".floatB")

    transYConvUnit = cmds.createNode("floatMath")
    cmds.setAttr(transYConvUnit + ".operation",3)
    cmds.setAttr(transYConvUnit + ".floatB",25.4)
    cmds.connectAttr(transYConv + ".outFloat",transYConvUnit + ".floatA")

    cmds.connectAttr(transYConvUnit + ".outFloat",destCamera + ".verticalFilmOffset")

    transXConv = cmds.createNode("floatMath")
    cmds.setAttr(transXConv + ".operation",3)
    cmds.connectAttr(resGatePlane + ".tx",transXConv + ".floatA")
    cmds.connectAttr(lengthRatio + ".outFloat",transXConv + ".floatB")

    transXConvUnit = cmds.createNode("floatMath")
    cmds.setAttr(transXConvUnit + ".operation",3)
    cmds.setAttr(transXConvUnit + ".floatB",25.4)
    cmds.connectAttr(transXConv + ".outFloat",transXConvUnit + ".floatA")

    cmds.connectAttr(transXConvUnit + ".outFloat",destCamera + ".horizontalFilmOffset")
    
    cmds.setAttr(resGatePlane + ".tz",l = True)
    cmds.setAttr(resGatePlane + ".rx",l = True)
    cmds.setAttr(resGatePlane + ".ry",l = True)
    cmds.setAttr(resGatePlane + ".sx",l = True)
    cmds.setAttr(resGatePlane + ".sy",l = True)
    cmds.setAttr(resGatePlane + ".template",1)


def addClipFrame(cameraName,defaultResolution):
    resolutionW = defaultResolution[0]
    resolutionH =  defaultResolution[1]

    sourceResW,sourceResH = getResGateSize(cameraName,resolutionW,resolutionH)
    nearClipPoint = addNearClipPos(cameraName)

    resGatePlane = cmds.polyPlane(axis = [0,0,1],sx = 1,sy = 1,ch =False,name = cameraName + "_resGateplane")[0]
    
    cmds.parent(resGatePlane,nearClipPoint,r=True)
    
    lengthRatio = cmds.createNode("floatMath")
    cmds.connectAttr(cameraName + ".nearClipPlane",lengthRatio + ".floatA")
    cmds.connectAttr(cameraName + ".focalLength",lengthRatio + ".floatB")
    cmds.setAttr(lengthRatio + ".operation",3)

    outRezGateW = cmds.createNode("floatMath")
    outRezGateH = cmds.createNode("floatMath")

    cmds.setAttr(outRezGateW + ".operation",2)
    cmds.setAttr(outRezGateH + ".operation",2)

    cmds.setAttr(outRezGateW + ".floatB",sourceResW)
    cmds.setAttr(outRezGateH + ".floatB",sourceResH)

    cmds.connectAttr(lengthRatio + ".outFloat",outRezGateW + ".floatA")
    cmds.connectAttr(lengthRatio + ".outFloat",outRezGateH + ".floatA")
    
    outScaleX = cmds.createNode("floatMath")
    outScaleY = cmds.createNode("floatMath")
    cmds.setAttr(outScaleX + ".operation",2)
    cmds.setAttr(outScaleY + ".operation",2)

    cmds.connectAttr(outRezGateW + ".outFloat",outScaleX + ".floatA")
    cmds.connectAttr(outRezGateH + ".outFloat",outScaleY + ".floatA")
    
    cmds.connectAttr(resGatePlane + ".sz",outScaleX + ".floatB")
    cmds.connectAttr(resGatePlane + ".sz",outScaleY + ".floatB")
    
    cmds.connectAttr(outScaleX + ".outFloat",resGatePlane + ".sx")
    cmds.connectAttr(outScaleY + ".outFloat",resGatePlane + ".sy")

    return resGatePlane,lengthRatio

def create2DCamera(sourceCamera,replace = True):
    if cmds.listRelatives(sourceCamera,type = "camera") == None:
        return
        
    cameraName = sourceCamera.split(":")[-1]
    destCamera = cameraName + "_2D"
    parent = cmds.createNode("transform", name = destCamera + "_parent")    
    
    if cmds.objExists(destCamera):
        if replace:
            cmds.delete(destCamera)
            cmds.delete(parent)
        else:
            return destCamera
    
    if cmds.objExists(destCamera) == False:
        nodes = cmds.duplicate(sourceCamera)
        cmds.refresh()
        cmds.rename(nodes[0], destCamera)
        
        cmds.parentConstraint(sourceCamera,parent,mo =False)
        cmds.parent(destCamera,parent,a=True)
        # cmds.setAttr(parent + ".sx",-1.0)
        
        connectAttrs = ["focalLength","nearClipPlane","farClipPlane"]
        
        for attr in connectAttrs:
            cmds.connectAttr(sourceCamera + "." + attr,destCamera + "." + attr)

    return destCamera


select = cmds.ls(sl =True)
target = select[0]
destCamera = create2DCamera(target)
defaultResolution = [960,540]
resGatePlane,lengthRatio = addClipFrame(target,defaultResolution)
connectClipCamera(destCamera,resGatePlane,lengthRatio)

前回のスクリプトを改修してみました。

こんなシーンでカメラを選択して実行
image.png

色々作られてー
image.png

動かすとー こう
image.png

もう少し詰めるとなると、もとのカメラのpostscaleやらflimeoffsetやらにも対応できるといいかもですねぇ

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?