Maya几何体变铁链

本来心血来潮想写个做锁子甲的脚本,最后弄成了个类似铁链的效果。不过也挺有意思,要是弄铁链的时候还是挺方便的。

研究的过程还是挺有意思的。在一开始的时候想的很简单。调用一个方法直接把要复制的对象Y轴对齐到平面的法线方向上,但是无奈怎么也没找到Maya里面有这个方法。纠结了一段时间以后只能把旋转分为两次。在物体的局部的X,Z轴上分别旋转两次把Y轴对齐到法线上,这样就可以吧物体附着到面上了。

沿着边进行复制的时候就简单多了。首先取相邻面的发线求平均值,再用任意一个面的中心位置减去另一个中心位置,标准化后求出方向,然后这两个向量叉乘。那么用这三个向量构建出的空间变换矩阵就是沿着边复制几何体的矩阵了。

附结果图,蓝色圆环是复制到几何体上的。单独的蓝色圆环下面的面积是用来进行参考这样就可以根据曲面大小自动缩放,需要注意的是越是正方形的链接效果越好。

# -*- coding:utf-8 -*-
import pymel.core as pm
import math


#运行报错的请删除中文注释

dup = pm.ls(selection=True)#选择要复制的物体运行这一行。

faceArea = pm.ls(selection=True, flatten=True)[0].getArea(space='world')#选择参考面,注意是选择面,不是物体。运行这一行

obj = pm.listRelatives(pm.ls(selection=True), shapes=True)#选择将要附着的对象,运行这一行






def faceCenter(faces):
    nub = 0
    averX = 0.0
    averY = 0.0
    averZ = 0.0
    for i in faces.getPoints(space='world'):
        nub += 1
        averX += i.x
        averY += i.y
        averZ += i.z
    return averX / nub, averY / nub, averZ / nub


def edgeCenter(edge):
    averX = (edge.getPoint(0, space='world').x + edge.getPoint(1, space='world').x) / 2
    averY = (edge.getPoint(0, space='world').y + edge.getPoint(1, space='world').y) / 2
    averZ = (edge.getPoint(0, space='world').z + edge.getPoint(1, space='world').z) / 2
    return averX, averY, averZ


def RotateDupObj(face, rotatObj):
    faceN = face
    Rx = math.atan2(faceN.z, faceN.y) * (180 / math.pi)  # Xaxis
    Pt = faceN.z / (
    math.sin(math.atan2(faceN.z, faceN.y)) if abs(math.sin(math.atan2(faceN.z, faceN.y))) > 0.00001 else 0.00001)
    Rz = math.atan2(faceN.x, Pt) * (180 / math.pi) * (-1)
    pm.rotate(rotatObj, Rx, x=True, objectSpace=True, relative=True)#沿着物体的局部坐标进行两次旋转使物体的Y轴对齐法线方向
    pm.rotate(rotatObj, Rz, z=True, objectSpace=True, relative=True)#沿着物体的局部坐标进行两次旋转使物体的Y轴对齐法线方向
    pm.rotate(rotatObj, -rotatObj[0].getRotation(space='object').y, y=True, objectSpace=True, relative=True)#想将Y轴旋转归零,经测试运行多次这一行代码才有效,这一行删了也不影响。


#沿面进行复制
for f in obj[0].faces:
    faceC = faceCenter(f)
    faceScale = math.sqrt(f.getArea(space='world') / faceArea)
    dupObj = pm.duplicate(dup)
    pm.move(faceC[0], faceC[1], faceC[2], dupObj)
    RotateDupObj(f.getNormal(space="world").normal(), dupObj)#旋转
    dupObj[0].setScale((faceScale, faceScale, faceScale))
#沿着边进行复制
for e in obj[0].edges:
    if (e.numConnectedFaces() > 1):
        averagePoin = pm.datatypes.Vector(0, 0, 0)
        averageN = pm.datatypes.Vector(0, 0, 0)
        xAixsRot = pm.datatypes.Vector(0, 0, 0)
        faceScale = 0.0
        for i in e.connectedFaces():
            averageN = averageN + i.getNormal(space="world").normal()
            averagePoin = averagePoin + faceCenter(i)
            xAixsRot = faceCenter(i) - xAixsRot
            faceScale = faceScale + i.getArea(space='world')
        dupObj = pm.duplicate(dup)
        averageN = averageN / 2
        faceScale = math.sqrt((faceScale / 2) / faceArea)
        averagePoin = averagePoin / 2
        xAixsRot.normalize()
        cross = averageN.cross(xAixsRot).normal()
        dupMaix = dupObj[0].getMatrix(worldSpace=True)
        #重构旋转矩阵
        dupObj[0].setMatrix((xAixsRot.x * faceScale, xAixsRot.y * faceScale, xAixsRot.z * faceScale, 0,
                             averageN.x * faceScale, averageN.y * faceScale, averageN.z * faceScale, 0,
                             cross.x * faceScale, cross.y * faceScale, cross.z * faceScale, 0,
                             averagePoin.x, averagePoin.y, averagePoin.z, 1), worldSpace=True)
        pm.rotate(dupObj, 90, x=True, objectSpace=True, relative=True)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值