0
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のカメラを何とかしたい6 ~大判解像度の算出~

0
Last updated at Posted at 2025-12-14

前回に引き続きカメラネタをこすっていこうかと。

2Dカメラワークを確認しやすくなったんですが、例えばこんな風にカメラワークを決めた場合

image.png

最終的なレンダリング解像度はいくつになるでしょうか?

レギュラーサイズを 960x540 だとすると、
青線の一番小さい時が 960x540になる必要があります。

image.png

必要最低限のレンダリング範囲を求めるなら 赤線の解像度が欲しいですね
image.png

まー力技ではありますが、
フレーミング用の板の4点の 開始・終了時座標をとって、バウンディングボックスサイズを算出し
現在のresolutionGateサイズとの比をだします。
その比を基に解像度を求められないかなぁ~

nearClipPlane 上での座標を求める

matrixやらなんやらをコネコネして、nearClipPlane上での座標を求めてみます。
とりあえず左上のvtxの座標を・・・

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

parentSpace = "persp1_nearClipPos"
matrixP = om2.MMatrix(cmds.getAttr(parentSpace+".worldInverseMatrix[0]"))
pointA = cmds.xform("persp1_resGateplane.vtx[2]",ws =True,t=True,q=True)
vectorA = om2.MVector(pointA)
matrixA = om2.MTransformationMatrix(om2.MMatrix.kIdentity).setTranslation(vectorA,om2.MSpace.kWorld).asMatrix()
localPositionA = om2.MTransformationMatrix(matrixA*matrixP).translation(om2.MSpace.kWorld)    
print(localPositionA)

# (-0.0458055, 0.0237331, -1.77636e-15)

locatorを実際に配置してみると、合ってそうですね。

image.png

まぁこれをやっていけば良いのですがー
1つ問題が。

この板はアニメーションをします。
アニメーションするので、各フレーム毎の座標を確認する必要があります。
cmds.getAttr() だとフレーム指定で値をとれますが、vtxの位置はcmds.getAttr()では取れません。
cmds.xform()でvtxの座標をとれますが、 cmds.xform()だとフレーム指定でき・・・なかったよなぁ

となると、プレイブラストの様に1fずつ送って確認するしかないかなぁ と
ただ、重いシーンだとそれやりたくないんですよねぇ 重いから。

で、ボケーっと空を見上げてたら流れ星が見えまして、

あ。もーしょんとれいる

と。(嘘です)

なのでvtx毎にmotionTrailを設置して、そこから全フレーム分の位置情報を引っ張り出してやろうと思います。


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

def getPosition(target):
    nodeType = cmds.nodeType(target)    
    if nodeType == "joint" or nodeType == "transform" or nodeType == "ikHandle" or nodeType == "place3dTexture":        
        return cmds.xform(target , q =True , ws = True, rotatePivot =True)
    elif nodeType == "mesh" or nodeType == "nurbsCurve" or nodeType == "nurbsSurface" or nodeType == "lattice":
        return cmds.xform(target , q =True , ws = True, t =True)


def getTrailPoints(planeName,startFrame,endFrame,index):
    trailPointNodes = []
    trailNodes = []
    trailPoints = []

    for i in range(0,len(index)):
        position = getPosition(planeName +".vtx["+str(index[i])+"]")
        
        trailPointNode = cmds.createNode("transform",name = planeName + str(i))
        cmds.setAttr(trailPointNode + ".t",**position)
        cmds.parent(trailPointNode,planeName,a =True)
        cmds.setAttr(trailPointNode + ".r",0,0,0)

        trailPointNodes.append(trailPointNode)

        nodes = cmds.snapshot(trailPointNode, motionTrail =True ,increment = 1, startTime =startFrame ,endTime = endFrame)
        trailNodes.append(nodes[-1])        
        points = cmds.getAttr(nodes[-1] + ".points")
        trailPoints.append(points)  

    cmds.delete(trailNodes)
    cmds.delete(trailPointNodes)

    return trailPoints

一旦 deleteの部分をコメントアウトして実行してみます。

parentSpace = "persp1_nearClipPos"
matrixP = om2.MMatrix(cmds.getAttr(parentSpace+".worldInverseMatrix[0]"))
planeName = "persp1_resGateplane"
startFrame = 1
endFrame = 50
index = [2]
trailPoints = getTrailPoints(planeName,startFrame,endFrame,index)

設置されて、数値も取れました。

image.png

この数値をもとにバウンディングボックスを定義して、そこから解像度を割り出します。
一番小さい板のサイズもついでに引っ張り出しておきます。


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

def getPosition(target):
    nodeType = cmds.nodeType(target)
    
    if nodeType == "joint" or nodeType == "transform" or nodeType == "ikHandle" or nodeType == "place3dTexture":
        return cmds.xform(target , q =True , ws = True, rotatePivot =True)

    elif nodeType == "mesh" or nodeType == "nurbsCurve" or nodeType == "nurbsSurface" or nodeType == "lattice":
        return cmds.xform(target , q =True , ws = True, t =True)


def getTrailPoints(planeName,startFrame,endFrame,index):
    trailPointNodes = []
    trailNodes = []
    trailPoints = []
    index = [0,2,6,8]   

    for i in range(0,len(index)):
        position = getPosition(planeName +".vtx["+str(index[i])+"]")
        
        trailPointNode = cmds.createNode("transform",name = planeName + str(i))
        cmds.setAttr(trailPointNode + ".t",*position)
        cmds.parent(trailPointNode,planeName,a =True)
        cmds.setAttr(trailPointNode + ".r",0,0,0)

        trailPointNodes.append(trailPointNode)

        nodes = cmds.snapshot(trailPointNode, motionTrail =True ,increment = 1, startTime =startFrame ,endTime = endFrame)
        trailNodes.append(nodes[-1])        
        points = cmds.getAttr(nodes[-1] + ".points")
        trailPoints.append(points)  

    cmds.delete(trailNodes)
    cmds.delete(trailPointNodes)

    return trailPoints

def getBBox(trailPoints,parentSpace):
    maxX = None
    minX = None
    maxY = None
    minY = None

    minWidth = None
    matrixP = om2.MMatrix(cmds.getAttr(parentSpace+".worldInverseMatrix[0]"))

    for i in range(0,len(trailPoints[0])):
        pointA = trailPoints[0][i][:3]#left-top
        pointB = trailPoints[1][i][:3]#right-top
        pointC = trailPoints[2][i][:3]#left-bot
        pointD = trailPoints[3][i][:3]#right-bot

        vectorA = om2.MVector(pointA)
        vectorB = om2.MVector(pointB)
        vectorC = om2.MVector(pointC)
        vectorD = om2.MVector(pointD)

        width = (vectorB - vectorA).length()

        if minWidth == None:
            minWidth = width

        elif minWidth > width:
            minWidth = width

        matrixA = om2.MTransformationMatrix(om2.MMatrix.kIdentity).setTranslation(vectorA,om2.MSpace.kWorld).asMatrix()
        matrixB = om2.MTransformationMatrix(om2.MMatrix.kIdentity).setTranslation(vectorB,om2.MSpace.kWorld).asMatrix()
        matrixC = om2.MTransformationMatrix(om2.MMatrix.kIdentity).setTranslation(vectorC,om2.MSpace.kWorld).asMatrix()
        matrixD = om2.MTransformationMatrix(om2.MMatrix.kIdentity).setTranslation(vectorD,om2.MSpace.kWorld).asMatrix()

        localPositionA = om2.MTransformationMatrix(matrixA*matrixP).translation(om2.MSpace.kWorld)    
        localPositionB = om2.MTransformationMatrix(matrixB*matrixP).translation(om2.MSpace.kWorld)    
        localPositionC = om2.MTransformationMatrix(matrixC*matrixP).translation(om2.MSpace.kWorld)    
        localPositionD = om2.MTransformationMatrix(matrixD*matrixP).translation(om2.MSpace.kWorld)    

        for position in [localPositionA,localPositionB,localPositionC,localPositionD]:
            if maxX == None:
                maxX = position[0]
            
            elif maxX < position[0]:
                maxX = position[0]
            
            if minX == None:
                minX = position[0]
            
            elif minX > position[0]:
                minX = position[0]

            if maxY == None:
                maxY = position[1]
            
            elif maxY < position[1]:
                maxY = position[1]
            
            if minY == None:
                minY = position[1]
            
            elif minY > position[1]:
                minY = position[1]

    return maxX,minX,maxY,minY,minWidth
##-----------------------------------------------------------------------------------------------------------

def getRasolution(parentSpace,defaultResolution,frameRange,planeIndex=[2,3,0,1]):        
    trailPoints = getTrailPoints(planeName,frameRange[0],frameRange[1],planeIndex)

    maxX,minX,maxY,minY,minWidth = getBBox(trailPoints,parentSpace)

    bboxW = maxX - minX
    bboxH = maxY - minY

    ratio = float(defaultResolution[0]) / minWidth
    wholeResolution = [math.ceil(bboxW * ratio), math.ceil(bboxH * ratio)]
    
    if wholeResolution[0] % 8 != 0:
        wholeResolution[0] = wholeResolution[0] + (8 - wholeResolution[0] % 8)
    
    if wholeResolution[1] % 8 != 0:
        wholeResolution[1] = wholeResolution[1] + (8 - wholeResolution[1] % 8)

    return wholeResolution

parentSpace = "persp1_nearClipPos"
planeName = "persp1_resGateplane"
planeIndex = [2,3,0,1] ##left-top/right-top/left-bot/right-bot
defaultResolution = [960,540]
frameRange = [
                cmds.playbackOptions(q =True, animationStartTime=True),
                cmds.playbackOptions(q =True, animationEndTime=True)
            ]

wholeResolution = getRasolution(parentSpace,defaultResolution,frameRange,planeIndex=[2,3,0,1])

print(wholeResolution)
# Result: [6656, 3232]

さて、合ってるかどうか・・・・

image.png

お、合ってそうですね。

地味にこの確認のための調整が面倒なので、ここもパシッと一発でできたら楽になりそうですね

0
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
0
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?