Skip to content

Instantly share code, notes, and snippets.

@tokejepsen
Last active November 14, 2019 09:56
Show Gist options
  • Save tokejepsen/48989dfeb031a8c9a67a2ea2e8a73e2c to your computer and use it in GitHub Desktop.
Save tokejepsen/48989dfeb031a8c9a67a2ea2e8a73e2c to your computer and use it in GitHub Desktop.
Maya Frustum Cutter
"""
Select the camera you want to cut from, then the geometry you want
to be cut.
"""
import maya.cmds as cmds
import pymel.core as pm
def cut_to_frustum(camera, geometry):
# Gather relevant camera attributes.
focalLength = cmds.getAttr(camera + ".focalLength")
horizontalAperture = cmds.getAttr(camera + ".cameraAperture")[0][0]
nearClipping = cmds.getAttr(camera + ".nearClipPlane")
farClipping = cmds.getAttr(camera + ".farClipPlane")
# Calculate ratios.
plane = horizontalAperture * 25.4
nearScaleValue = nearClipping * plane / focalLength
# Build geometry.
cube_transform, cube_shape = cmds.polyCube(
w=1,
h=1,
d=farClipping-nearClipping,
sy=1,
sx=1,
sz=1,
ax=[0, 1, 0],
ch=1,
name=camera.replace("Shape", "Frustrum")
)
cmds.setAttr(
cube_transform + ".translateZ",
nearClipping + (farClipping-nearClipping) * 0.5
)
cmds.makeIdentity(apply=True, t=1, r=1, s=1, n=0, pn=1)
cmds.setAttr(cube_transform + ".rotatePivotZ", 0)
cmds.setAttr(cube_transform + ".scalePivotZ", 0)
cmds.setAttr(cube_transform + ".rotateY", 180)
# Use expressions to update frustum geo as FOV and apertures are changed.
scaleX = (
"{}.scaleZ*{}.farClipPlane*{}.horizontalFilmAperture*25.4*0.94"
"/{}.focalLength".format(cube_transform, camera, camera, camera)
)
scaleY = (
"{}.scaleZ*{}.farClipPlane*{}.verticalFilmAperture*25.4"
"/{}.focalLength".format(cube_transform, camera, camera, camera)
)
cmds.move(0, 0, 0, cube_transform + ".f[2]", absolute=True)
cmds.scale(nearScaleValue, 0, 1, cube_transform + ".f[2]", pivot=[0, 0, 0])
cmds.expression(
s="{}.scaleX = {};{}.scaleY = {};".format(
cube_transform, scaleX, cube_transform, scaleY
),
n="{}_Expr".format(cube_transform)
)
cmds.parent(cube_transform, camera.getTransform().name(), relative=True)
cmds.parent(cube_transform, world=True)
# Difference operation.
pm.polyCBoolOp(
cube_transform,
geometry,
operation=2,
constructionHistory=False,
preserveColor=0,
classification=1,
name=geometry.name()
)
with pm.UndoChunk():
selection = pm.ls(selection=True)
cut_to_frustum(selection[0].getShape(), selection[1])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment