当前位置: 首页 > news >正文

【maxscript】矩阵对齐-武器残影

最简单的矩阵对齐,

m = matrix3 1
-- 应用旋转
m = rotate m (at time timeValue in coordsys world ($'Bip001 Prop1'.rotation))
-- 应用位置
m = translate m (at time timeValue ($'Bip001 Prop1'.pos ))
-- 应用到武器
targetObj.transform = m

精确版的矩阵对齐

-- 1. 获取sourceBip的位置(矩阵第4列是位置信息)
local sourcePos = sourceBip.transform[4]  -- 等价于 sourceBip.pos
-- 2. 获取sourceBip的X轴方向(矩阵第1列)
local sourceX = sourceBip.transform[1]  -- X轴方向向量-- 3. 构建目标旋转矩阵(Z轴对齐sourceX)
local targetZ = normalize sourceX  -- 目标Z轴 = sourceBip的X轴
local worldUp = [0,1,0]  -- 参考上方向(可改为sourceBip的Y轴)
local targetX = normalize (cross worldUp targetZ)  -- 计算X轴(与Z轴正交)
local targetY = cross targetZ targetX  -- 计算Y轴(确保三轴正交)-- 4. 构建完整变换矩阵(包含旋转+位移)
-- 矩阵结构:[X轴, Y轴, Z轴, 位置]
local finalMatrix = matrix3 targetX targetY targetZ sourcePos-- 5. 应用矩阵到目标对象
targetObj.transform = finalMatrix

麻烦帮解释下,如何做到targetObj的z轴对齐sourceBip的x轴的?

这段代码通过矩阵变换实现了让targetObj的 Z 轴与sourceBip的 X 轴对齐,核心原理如下:

获取源对象的 X 轴方向

local sourceX = sourceBip.transform[1]  -- X轴方向向量

这里从sourceBip的变换矩阵中提取了第一列,这列数据代表了sourceBip在世界空间中的 X 轴方向向量

将源 X 轴设为目标 Z 轴

local targetZ = normalize sourceX  -- 目标Z轴 = sourceBip的X轴

直接将sourceBip的 X 轴方向向量归一化后,作为targetObj的 Z 轴方向向量,这一步是实现对齐的关键

构建完整的正交坐标系

因为 3D 空间中的三个轴需要相互正交,所以需要基于已确定的 Z 轴计算出对应的 X 轴和 Y 轴:

local targetX = normalize (cross worldUp targetZ)  -- 计算X轴(与Z轴正交)
local targetY = cross targetZ targetX  -- 计算Y轴(确保三轴正交)

通过叉乘运算确保三个轴两两垂直,形成一个标准的三维坐标系

构建变换矩阵并应用

最后将计算出的三个轴向量和源对象的位置组合成变换矩阵,应用到目标对象:

local finalMatrix = matrix3 targetX targetY targetZ sourcePos
targetObj.transform = finalMatrix

通过这个过程,targetObj的 Z 轴就精确地指向了sourceBip的 X 轴方向,同时保持了自身坐标系的正交性。

要根据单选按钮的选择来决定targetObj的哪个轴对齐到sourceBip的 X 轴,你可以这样修改代码:

-- 获取单选按钮的选择状态(1=x, 2=y, 3=z)
local selectedAxis = ChangeAxis.selected-- 1. 获取源对象的位置和X轴方向
local sourcePos = sourceBip.transform[4] -- 位置信息
local sourceX = normalize sourceBip.transform[1] -- 源对象X轴方向(归一化)-- 2. 定义世界上方向向量
local worldUp = [0,1,0]-- 3. 根据选择确定目标轴与源X轴对齐
local targetX, targetY, targetZcase selectedAxis of
(1: -- 目标X轴对齐源X轴(targetX = sourceXtargetZ = normalize (cross worldUp targetX)targetY = cross targetZ targetX)2: -- 目标Y轴对齐源X轴(targetY = sourceXtargetX = normalize (cross targetY worldUp)targetZ = cross targetX targetY)3: -- 目标Z轴对齐源X轴(原始逻辑)(targetZ = sourceXtargetX = normalize (cross worldUp targetZ)targetY = cross targetZ targetX)
)-- 4. 构建完整的变换矩阵
local finalMatrix = matrix3 targetX targetY targetZ sourcePos-- 5. 应用变换矩阵到目标对象
targetObj.transform = finalMatrix

加入缩放

			-- 获取单选按钮状态local selectedAxis = ChangeAxis.state-- 1. 分解源对象的变换信息local sourceTM = sourceBip.transform  -- 完整变换矩阵local sourcePos = sourceTM[4]         -- 位置local sourceScale = sourceBip.scale   -- 缩放-- 兼容旧版本:从矩阵中提取纯旋转部分(移除缩放影响)local rotOnlyTM = sourceTM-- 归一化矩阵的三个轴,消除缩放影响,得到纯旋转矩阵rotOnlyTM[1] = normalize rotOnlyTM[1]rotOnlyTM[2] = normalize rotOnlyTM[2]rotOnlyTM[3] = normalize rotOnlyTM[3]local sourceX = rotOnlyTM[1]  -- 仅用旋转信息计算X轴方向-- 2. 定义世界上方向local worldUp = [0,1,0]-- 3. 计算目标对象的轴向(仅处理旋转,不包含缩放)local targetX, targetY, targetZcase selectedAxis of(1: -- 目标X轴对齐源X轴(targetX = sourceXtargetZ = normalize (cross worldUp targetX)targetY = cross targetZ targetX)2: -- 目标Y轴对齐源X轴(targetY = sourceXtargetX = normalize (cross targetY worldUp)targetZ = cross targetX targetY)3: -- 目标Z轴对齐源X轴(targetZ = sourceXtargetX = normalize (cross worldUp targetZ)targetY = cross targetZ targetX))-- 4. 构建包含正确缩放的变换矩阵local rotMatrix = matrix3 targetX targetY targetZ [0,0,0]local myscaleMatrix = scaleMatrix sourceScale  -- 单独的缩放矩阵local finalRotScale = rotMatrix * myscaleMatrix  -- 旋转×缩放finalRotScale[4] = sourcePos  -- 设置位置-- 5. 应用最终变换矩阵targetObj.transform = finalRotScale

完整版


if(addghost!=undefined )do( DestroyDialog addghost )
rollout addghost "武器残影25.09.05" width:200 height:100 rolledup:false
(-- UI控件定义pickbutton 'pickobj' "拾取跟随骨骼" pos:[90,5] width:100 height:25 align:#center  -- 按钮文本更明确checkbox 'chk1' "创建dummy" pos:[5,5] width:80 height:26 tooltip:"翻转轴向."-- 新增:偏移量控制label 'offsetLabel' "偏移比例:" pos:[100,40] width:60 height:16spinner 'spinBaseOffset' "" pos:[150,40] width:40 height:16 range:[-100000, 100000, 0.5] type:#float step:0.1	button 'CollapseMartixAlign' "打印矩阵约束" pos:[5,35] width:90 height:25 enabled:trueradiobuttons 'ChangeAxis' "" pos:[14,75] width:97 height:16 labels:#("x", "y","z") default:1 columns:3 align:#leftlocal weapons = #()local lastPositions = #()local weaponsname = #("weapon001", "weapon002", "weapon003", "weapon004")fn followAndAlign targetObj sourceBip = (if (targetObj != undefined and sourceBip != undefined) then (-- 获取单选按钮状态local selectedAxis = ChangeAxis.state-- 1. 分解源对象的变换信息local sourceTM = sourceBip.transform  -- 完整变换矩阵local sourcePos = sourceTM[4]         -- 位置local sourceScale = sourceBip.scale   -- 缩放-- 兼容旧版本:从矩阵中提取纯旋转部分(移除缩放影响)local rotOnlyTM = sourceTM-- 归一化矩阵的三个轴,消除缩放影响,得到纯旋转矩阵rotOnlyTM[1] = normalize rotOnlyTM[1]rotOnlyTM[2] = normalize rotOnlyTM[2]rotOnlyTM[3] = normalize rotOnlyTM[3]local sourceX = rotOnlyTM[1]  -- 仅用旋转信息计算X轴方向-- 2. 定义世界上方向local worldUp = [0,1,0]-- 3. 计算目标对象的轴向(仅处理旋转,不包含缩放)local targetX, targetY, targetZcase selectedAxis of(1: -- 目标X轴对齐源X轴(targetX = sourceXtargetZ = normalize (cross worldUp targetX)targetY = cross targetZ targetX)2: -- 目标Y轴对齐源X轴(targetY = sourceXtargetX = normalize (cross targetY worldUp)targetZ = cross targetX targetY)3: -- 目标Z轴对齐源X轴(targetZ = sourceXtargetX = normalize (cross worldUp targetZ)targetY = cross targetZ targetX))-- 4. 构建包含正确缩放的变换矩阵local rotMatrix = matrix3 targetX targetY targetZ [0,0,0]local myscaleMatrix = scaleMatrix sourceScale  -- 单独的缩放矩阵local finalRotScale = rotMatrix * myscaleMatrix  -- 旋转×缩放finalRotScale[4] = sourcePos  -- 设置位置-- 5. 应用最终变换矩阵targetObj.transform = finalRotScale))-- 计算当前帧与前一帧的位置差fn getPositionDeltaAndDir sourceBip = (if currentTime > animationrange.start then (local currentPos = sourceBip.poslocal prevPos = at time (currentTime - 1) sourceBip.poslocal delta = currentPos - prevPos  -- 位置差向量local distance = length delta      -- 距离local dir = if distance > 0 then normalize delta else [0,0,0]  -- 归一化方向向量return [distance, dir.x,dir.y,dir.z]  -- 返回[距离, 方向向量])else(return [0.0,0.0,0.0,0.0]  -- 第一帧返回默认值)	)-- 自动偏移函数:仅使用倍数偏移逻辑,结合物理位置差fn autoOffsetWeapons sourceObj = (local baseDist = spinBaseOffset.value -- 基础偏移值(用户设置)local deltaData = getPositionDeltaAndDir sourceObjlocal distance = deltaData[1]local moveDir = [deltaData[2],deltaData[3],deltaData[4]]  -- 归一化的移动方向向量local index = 1  -- 武器序号        for weapon in weapons do (if weapon != undefined do (-- 计算偏移量:基础距离 × 序号 × 移动方向local offsetVec = baseDist * index * moveDir-- 获取源对象当前位置local sourcePos = sourceObj.pos-- 计算最终位置:源位置 + 偏移向量local finalPos = sourcePos + offsetVec-- 设置武器在当前帧的位置at time currentTime (weapon.pos = finalPos)                index += 1))	)on pickobj picked obj do(if (obj!=undefined) then (pickobj.text = obj.name)if (chk1.checked)then(weapons = #() -- 清空现有列表for weapon in weaponsname do (if weapon != undefined then (       local dummyObj = Dummy name:weapon        dummyObj.pos = [0,0,0]        dummyObj.boxsize =[10,10,10]			appendIfUnique weapons dummyObj))		)else(weapons = #($weapon001, $weapon002, $weapon003, $weapon004)))	on pickobj rightclick do(pickobj.text="拾取跟随骨骼"weapons = #())on CollapseMartixAlign pressed do(local obj = getnodebyname pickobj.textif obj == undefined then (print "请先拾取跟随骨骼")slidertime = animationrange.start-- 创建动画并应用偏移with redraw off(set animate onmax tool animmodefor t = animationrange.start to animationrange.end do (at time t (for weapon in weapons do(					followAndAlign weapon obj)-- 自动应用倍数偏移autoOffsetWeapons obj)				)    set animate offmax tool animmode))
)
-- 创建浮动窗口并添加rollout
createDialog addghost


文章转载自:

http://dgEwcHZL.qfdmh.cn
http://N9mNlWCh.qfdmh.cn
http://t13ZHP2i.qfdmh.cn
http://enUP8QSH.qfdmh.cn
http://sUgsiT98.qfdmh.cn
http://JyrNVr2d.qfdmh.cn
http://dDsqs92K.qfdmh.cn
http://BSaCgHyA.qfdmh.cn
http://WOTE2zZJ.qfdmh.cn
http://xCig2oVW.qfdmh.cn
http://MSi4L3AM.qfdmh.cn
http://sG8V0m7s.qfdmh.cn
http://tSwRZa13.qfdmh.cn
http://Rw7sHbYk.qfdmh.cn
http://6RQQCIDR.qfdmh.cn
http://Kb3xxkrR.qfdmh.cn
http://tfpPEgWJ.qfdmh.cn
http://neEm6zVV.qfdmh.cn
http://PFueq5do.qfdmh.cn
http://l764iNQ3.qfdmh.cn
http://v0wDJGSs.qfdmh.cn
http://0XONg8EC.qfdmh.cn
http://wyWR2Fzf.qfdmh.cn
http://FuPwRtuw.qfdmh.cn
http://58a606Cu.qfdmh.cn
http://sXReIsRC.qfdmh.cn
http://vQMqnLGI.qfdmh.cn
http://WdkYo8eN.qfdmh.cn
http://90gzuqHg.qfdmh.cn
http://1pvW6VEx.qfdmh.cn
http://www.dtcms.com/a/378306.html

相关文章:

  • Java 黑马程序员学习笔记(进阶篇4)
  • XR 和 AI 在 Siggraph 2025 上主导图形的未来,获取gltf/glb格式
  • TikTok矩阵有哪些运营支撑方案?
  • 《基于深度学习的近红外条纹投影三维测量》-论文总结
  • 优选算法 100 题 —— 2 滑动窗口
  • MongoDB 在线安装-一键安装脚本(CentOS 7.9)
  • DeepSeek辅助编写的利用quick_xml把xml转为csv的rust程序
  • Rider中的Run/Debug配置对应的本地文件
  • 综合项目实践:基于基础语法核心的Python项目
  • 开始 ComfyUI 的 AI 绘图之旅-Flux.1图生图(八)
  • 供应商管理系统包含哪些模块?
  • MongoDB Atlas 云数据库实战:从零搭建全球多节点集群
  • Apache服务——搭建实验
  • “一半是火焰,一半是海水”,金融大模型的爆发与困局
  • 开源 C++ QT Widget 开发(十六)程序发布
  • MPC控制器C语言实现:基于一阶RL系统
  • C++版单例模式-现代化简洁写法
  • 强大的开源文档问答工具-Kotaemon
  • 音视频学习(六十三):AVCC和HVCC
  • 深度解析强化学习(RL):原理、算法与金融应用
  • 独立显卡和集成显卡切换电脑卡住了怎么办?
  • 加固笔记本是什么意思?加固笔记本图片
  • 光子精密3D线激光轮廓测量仪:赋能手机生产全流程质量与效率升级
  • springboot excel 表格入门与实战
  • react实现无缝轮播组件
  • DbGate数据库管理新方案:cpolar打造跨平台远程访问通道
  • Spark+Hive中间件
  • 【案例分享】TeeChart 助力 Softdrill 提升油气钻井数据可视化能力
  • 在图形 / 游戏开发中,为何 Pixels Per Unit(PPU)数值越小,物体在屏幕上显示的尺寸越大?
  • new和mallo的区别