当前位置:首页>悬赏问答>当前问题
重金之下,必有勇夫
悬赏提问

更多求助

悬赏:70素材币

关于AI写脚本时,材质吸取的问题

2026-07-19 11:07:41 | 浏览116次
材质吸取相关功能的准确性,需要用到“射线求交”AI写的相关功能时,总是对多维子材质下的子材质识别有偏差。 目前用的这个方案代替,但在某些极少的情况下,会出现结果上的不准确: 用户点击源物体 ↓ pickObject() → 拿到被点击的 node + screenPt ↓ _mrResolvePick(node, screenPt) → _mrPickFaceOnNode(node, screenPt) ↓ 返回 #(polyFaceIdx, matID) ↓ _mrLookupByFaceID(matA, matID) → 在 MultiMaterial 中定位子材质 ↓ 最终材质 = matA.materialList[slotIndex] 哪位前辈可以提供一段能准确识别物体表面ID的 脚本代码就好了。 以下是AI写的相对准确的识别物体ID和材质的方案: -- ============================================================ -- 材质吸取 - 准确性测试 -- ============================================================ -- 功能: -- 用户在视口点击模型表面 → 提取命中面的材质ID + 漫反射颜色 -- 输出 RayEx 格式: RayEx #((ray [pos] [dir]), matID, [r,g,b]) -- -- 求交流程 (两步兜底 + 两步修正): -- 1. intersectRayEx → 3ds Max 原生射线求交 (主方案, 返回三角面号) -- 2. snapshotAsMesh → 快照为 TriMesh + 手写 M-T 求交 (兜底方案) -- └ 范围优化: 先用 intersectRay 取命中点, 只遍历附近100单位内的面 -- 3. triToPolyFace → 三角面号 → 多边形面号 (Editable_Poly 专用) -- 4. verifyFaceByCenter → 面心距离交叉验证 (±3窗口修正) -- -- 兼容材质类型: -- Corona / VRay / Standard / Physical / Multi-Sub-Object -- ============================================================ -- 销毁已存在的对话框 (防止重复运行报错) try (destroydialog matPickTestRollout) catch() -- ========================================== -- Rollout UI 定义 -- ========================================== rollout matPickTestRollout "材质吸取 - 准确性测试" width:400 ( group "测试按钮:" ( button btn_test "点击视口拾取材质" width:380 height:30 ) -- 状态标签: 显示最近一次拾取的结果摘要 label lbl_last "(未测试)" align:#center -- 日志列表框: 显示拾取过程中的信息 listbox lb_log "" height:15 -- ========================================== -- 日志与字符串工具函数 -- ========================================== local logMsgs = #() -- 日志缓冲数组, 最多保留100条 -- valStr: 安全转字符串 (兼容任意类型, 失败返回占位符) fn valStr v = ( try ( formattedPrint v format:"" ) catch ( try (v as string) catch ("<转换失败>") ) ) -- numStr: 数值转字符串 (用于日志输出) fn numStr v = ( try ( formattedPrint v format:"" ) catch ( try (v as string) catch ("?") ) ) -- addLog: 追加一条日志到列表框 (超过100条自动丢弃最旧的) fn addLog msg = ( append logMsgs (valStr msg) if logMsgs.count > 100 do deleteItem logMsgs 1 lb_log.items = logMsgs ) -- logHeader: 输出带分隔线的标题 (同时写入 Listener 和 UI) fn logHeader testName = ( addLog ("========== " + testName + " ==========") ) -- logNodeInfo: 输出节点的详细信息 (名称/类型/面数/材质/子材质列表) fn logNodeInfo n = ( if n == undefined do return() local mat = try(n.material)catch(undefined) local matType = if mat != undefined then (classOf mat as string) else "(无)" addLog (" 节点: " + n.name + " (" + matType + ")") ) -- ========================================== -- 颜色工具函数 -- ========================================== -- normColor: 颜色归一化 -- 输入: 0-255 范围的 color 或 Point3 -- 输出: 0-1 范围的 color -- 异常时返回灰色 (0.5, 0.5, 0.5) fn normColor c = ( if c == undefined do return (color 0.5 0.5 0.5) -- Point3 → color 类型转换 if classOf c == Point3 do c = color c.x c.y c.z -- 如果任一通道 > 1.0, 认为是 0-255 范围, 除以 255 归一化 if (c.r > 1.0 or c.g > 1.0 or c.b > 1.0) do c = color (c.r/255.0) (c.g/255.0) (c.b/255.0) c ) -- getMtlColor: 提取材质的漫反射基础色 -- 按优先级检测属性, 兼容多种材质类型: -- baseColor → Physical Material / Corona -- diffuse → Standard / VRay -- color → 部分自定义材质 -- albedo → 部分新材质 -- 全部找不到时返回灰色 (128, 128, 128) fn getMtlColor m = ( if m == undefined do return (normColor (color 128 128 128)) if (isProperty m #baseColor) do return (normColor m.baseColor) if (isProperty m #diffuse) do return (normColor m.diffuse) if (isProperty m #color) do return (normColor m.color) if (isProperty m #albedo) do return (normColor m.albedo) return (normColor (color 128 128 128)) ) -- getHitColor: 按 matID 取子材质的漫反射颜色 -- 如果是 MultiMaterial (多维子材质), 按 matID 取对应子材质 -- 如果是普通材质, 直接取材质本身颜色 fn getHitColor obj matID = ( local m = obj.material if m == undefined do return (normColor (color 128 128 128)) local subM = m if classOf m == MultiMaterial then ( -- matID 范围校验后取对应子材质 if matID >= 1 and matID <= m.numsubs do subM = m[matID] ) getMtlColor subM ) -- getMatNameByID: 按 matID 获取材质名称 (用于日志显示) -- 多维子材质: 返回对应子槽位的名称 -- 普通材质: 返回材质本身名称 fn getMatNameByID obj matID = ( if obj == undefined or obj.material == undefined do return "(无材质)" local m = obj.material if classOf m == MultiMaterial then ( if matID >= 1 and matID <= m.numsubs then ( local sub = m[matID] if sub != undefined then return (try(sub.name)catch("(未命名子材质)")) else return "(子材质" + (matID as string) + "为空)" ) else return "(matID " + (matID as string) + " 越界)" ) else ( return (try(m.name)catch("(未命名材质)")) ) ) -- ========================================== -- 调试日志 (输出到 MAXScript Listener) -- ========================================== fn stepLog msg = ( format "[步骤] %\n" msg ) fn detailLog msg = ( format " ├ %\n" msg ) fn okLog msg = ( format " └ ✓ %\n" msg ) fn failLog msg = ( format " └ ✗ %\n" msg ) -- ========================================== -- 射线求交引擎 -- ========================================== -- -------------------------------------------------- -- manualIntersect: 手写 Möller-Trumbore 射线-三角形求交 -- -------------------------------------------------- -- 与全量遍历不同, 本函数支持"范围优化": -- 如果传入了 hitPoint (来自 intersectRay 的命中点), -- 则只遍历面中心距离 hitPoint < threshold 的三角面, -- 大幅减少计算量 (从万级降到几十级) -- -- 参数: -- mesh - TriMesh 网格对象 -- theRay - 射线 (ray pos dir) -- hitPoint - (可选) 预估命中点, 用于缩小搜索范围 -- threshold - 搜索半径 (世界单位, 默认100) -- -- 返回: #(三角面索引, 距离t) 或 undefined fn manualIntersect mesh theRay hitPoint:undefined threshold:100.0 = ( local closestT = 1e9 -- 最近命中距离 (初始化为极大值) local closestFace = 0 -- 最近命中面索引 local nFaces = try(mesh.numfaces) catch(0) -- 第一步: 筛选候选面 local facesToCheck = #() if hitPoint != undefined then ( -- ★ 范围优化模式: 只收集面中心距命中点 < threshold 的面 for f = 1 to nFaces do ( local fv = try(getFace mesh f) catch(undefined) if fv != undefined do ( local v1 = try(getVert mesh fv.x) catch(undefined) local v2 = try(getVert mesh fv.y) catch(undefined) local v3 = try(getVert mesh fv.z) catch(undefined) if v1 != undefined and v2 != undefined and v3 != undefined do ( -- 计算三角形面心 local center = (v1 + v2 + v3) / 3.0 -- 只保留 threshold 范围内的面 if distance center hitPoint < threshold do append facesToCheck f ) ) ) detailLog ("M-T 范围优化: 候选面 " + (facesToCheck.count as string) + "/" + (nFaces as string)) ) else ( -- 无命中点时, 退化为全量遍历 for f = 1 to nFaces do append facesToCheck f detailLog ("M-T 全量遍历: " + (nFaces as string) + " 面") ) -- 第二步: 对候选面执行 M-T 求交 for f in facesToCheck do ( local fv = try(getFace mesh f) catch(undefined) if fv != undefined do ( local v1 = try(getVert mesh fv.x) catch(undefined) local v2 = try(getVert mesh fv.y) catch(undefined) local v3 = try(getVert mesh fv.z) catch(undefined) if v1 != undefined and v2 != undefined and v3 != undefined do ( -- === Möller-Trumbore 算法开始 === -- e1, e2: 三角形两条边向量 local e1 = v2 - v1 local e2 = v3 - v1 -- pvec: 射线方向与 e2 的叉积 local pvec = cross theRay.dir e2 -- det: 行列式, 用于判断射线是否与三角形平面平行 local det = dot e1 pvec -- 行列式接近0 → 射线与三角形平行, 跳过 if abs det > 0.0001 do ( local invDet = 1.0 / det -- tvec: 射线起点到三角形顶点 v1 的向量 local tvec = theRay.pos - v1 -- u: 重心坐标分量1 (必须在 [0,1] 区间) local u = (dot tvec pvec) * invDet if u >= 0 and u <= 1 do ( -- qvec: tvec 与 e1 的叉积 local qvec = cross tvec e1 -- v: 重心坐标分量2 (u+v 必须 ≤ 1) local v2uv = (dot theRay.dir qvec) * invDet if v2uv >= 0 and (u + v2uv) <= 1 do ( -- t: 射线参数, 表示从起点到命中点的距离 local t = (dot e2 qvec) * invDet -- 取最近的有效命中 (t > 0.001 避免自交) if t > 0.001 and t < closestT do ( closestT = t closestFace = f ) ) ) ) -- === Möller-Trumbore 算法结束 === ) ) ) if closestFace > 0 then #(closestFace, closestT) else undefined ) -- -------------------------------------------------- -- triToPolyFace: 三角面索引 → 多边形面索引 -- -------------------------------------------------- -- 背景: -- intersectRayEx / snapshotAsMesh 返回的是三角面号 -- 但 Editable_Poly 的 polyop.getFaceMatID 需要多边形面号 -- 一个多边形 (n边形) 会被三角化为 (n-2) 个三角面 -- 本函数按 (deg-2) 累加, 找到三角面对应的多边形面 -- -- 参数: -- node - 目标节点 -- triFaceIdx - 三角面索引 (从1开始) -- -- 返回: 多边形面索引 (从1开始), 或 0 表示未找到 -- 非 Editable_Poly 对象直接返回原值 (无需转换) fn triToPolyFace node triFaceIdx = ( if triFaceIdx <= 0 do return 0 local isPoly = try(classOf node == Editable_Poly) catch(false) if not isPoly do return triFaceIdx -- 非 Editable_Poly 无需转换 local accumulated = 0 local nFaces = try(polyOp.getNumFaces node) catch(0) for p = 1 to nFaces do ( -- getFaceDeg: 获取多边形顶点数 (3=三角形, 4=四边形, 5=五边形...) local deg = try(polyOp.getFaceDeg node p) catch(4) if deg == undefined or deg < 3 do deg = 4 -- n边形 → (n-2) 个三角面 accumulated += (deg - 2) -- 三角面号落在累加范围内 → 返回多边形面号 if triFaceIdx <= accumulated do return p ) 0 ) -- -------------------------------------------------- -- verifyFaceByCenter: 面心距离交叉验证 -- -------------------------------------------------- -- 用途: -- M-T 或 intersectRayEx 返回的面号可能有偏差 -- (尤其在相邻面边界处) -- 本函数在候选面 ±window 范围内, -- 找面心距离命中点最近的多边形面, 作为修正结果 -- -- 参数: -- node - 目标节点 (仅对 Editable_Poly 有效) -- polyF - 候选多边面号 -- hitPoint - 射线命中点 (世界坐标) -- window - 搜索窗口 (默认 ±3 面) -- -- 返回: #(修正后面号, 修正前面号) fn verifyFaceByCenter node polyF hitPoint window:3 = ( -- 非 Editable_Poly 不做验证 if classOf node != Editable_Poly do return #(polyF, polyF) local nFaces = try(polyOp.getNumFaces node) catch(0) if nFaces == 0 do return #(polyF, polyF) -- 计算搜索范围 [lo, hi], 确保不越界 local lo = amax 1 (polyF - window) local hi = amin nFaces (polyF + window) local bestF = polyF -- 最佳面号, 初始为候选面 local bestD = 1e10 -- 最佳距离, 初始为极大值 -- 遍历窗口内的面, 找面心最近的 for i = lo to hi do ( -- getFaceCenter 返回局部坐标的面心 local center = [0,0,0] try (center = polyOp.getFaceCenter node i) catch() -- 转换到世界坐标 local worldCenter = center * node.objectTransform local d = distance hitPoint worldCenter if d < bestD do (bestD = d; bestF = i) ) detailLog ("面心验证: 修正前=" + (polyF as string) + " → 修正后=" + (bestF as string) + " (距离=" + (bestD as string) + ")") #(bestF, polyF) ) -- ========================================== -- 核心: 射线面求交主函数 -- ========================================== -- -------------------------------------------------- -- pickFaceOnNode: 对单个节点执行完整的面求交流程 -- -------------------------------------------------- -- 流程: -- 1. intersectRayEx (3ds Max 原生) → 三角面号 → triToPolyFace 转换 -- 2. [兜底] snapshotAsMesh + M-T (范围优化) → 三角面号 → triToPolyFace 转换 -- 3. 面心交叉验证 (Editable_Poly 专用) -- 4. 三级降级取 matID -- -- 参数: -- node - 目标节点 -- theRay - 射线 (ray pos dir) -- -- 返回: #(多边面号, matID, 三角面号, 距离) 或 undefined fn pickFaceOnNode node theRay = ( if node == undefined do return undefined -- 归一化射线方向 (M-T 算法要求单位向量) local ray = theRay local dirLen = length ray.dir if dirLen > 0 and dirLen != 1.0 do ray.dir = ray.dir / dirLen -- 初始化状态变量 local faceIdx = 0 -- 多边形面号 (最终用) local dist = -1.0 -- 命中距离 local found = false -- 是否已找到命中面 local meshMatID = 0 -- 从 mesh 获取的 matID (兜底用) local triFaceIdx = 0 -- 三角面号 (中间值) stepLog ("pickFaceOnNode 开始 | 对象: " + node.name + " | 类型: " + (classOf node as string)) detailLog ("射线起点: " + (ray.pos as string)) detailLog ("射线方向: " + (ray.dir as string)) -- ========================================== -- 步骤1: intersectRayEx (3ds Max 原生射线求交) -- ========================================== -- 优势: 内置加速结构, 速度快 -- 返回: hitRecord (含 .face .dist 属性) 或 Array 或 undefined try ( stepLog "步骤1: intersectRayEx (3ds Max 原生射线求交)" local hrEx = intersectRayEx node ray if hrEx != undefined then ( local triF = undefined local d = -1.0 -- intersectRayEx 返回格式不统一, 需兼容两种: -- 格式1: Array #(hitResult, faceIndex) -- 格式2: hitRecord 对象 (.face / .dist 属性) if classOf hrEx == Array and hrEx.count >= 2 then ( -- Array 格式: hrEx[1] = Ray 命中结果, hrEx[2] = 面索引 triF = hrEx[2] d = try(distance hrEx[1].pos ray.pos) catch(-1.0) detailLog ("intersectRayEx [Array格式] 三角面=" + (triF as string) + " 距离=" + (d as string)) ) else ( -- hitRecord 格式: 直接取 .face 和 .dist 属性 triF = try(hrEx.face) catch(undefined) d = try(hrEx.dist) catch(-1.0) detailLog ("intersectRayEx [hitRecord格式] 三角面=" + (triF as string) + " 距离=" + (d as string)) ) -- 拿到三角面号后, 转换为多边形面号 if triF != undefined and triF > 0 do ( dist = d triFaceIdx = triF faceIdx = triToPolyFace node triF detailLog ("三角面" + (triF as string) + " → 多边面" + (faceIdx as string)) if faceIdx > 0 do found = true ) ) else ( detailLog "intersectRayEx 返回 undefined" ) ) catch ( err ) ( failLog ("intersectRayEx 异常: " + (err as string)) ) -- ========================================== -- 步骤2: snapshotAsMesh + M-T (兜底方案) -- ========================================== -- 触发条件: 步骤1 未命中 -- 原理: 快照为 TriMesh → 手写 M-T 逐三角形求交 -- 优化: 先用 intersectRay 取命中点, 只遍历附近100单位内的面 if not found do ( stepLog "步骤2: snapshotAsMesh + M-T (兜底方案)" -- snapshotAsMesh: 获取节点的三角网格快照 (含世界变换) local m = try(snapshotAsMesh node) catch(undefined) if m != undefined then ( -- ========================================== -- 2a: 检测顶点空间 (局部 vs 世界) -- ========================================== -- snapshotAsMesh 的顶点可能在局部空间, 也可能在世界空间 -- 通过比较第一个顶点与节点 boundingbox 来判断 local bbMin = node.min; local bbMax = node.max local v1 = try(getVert m 1) catch([0,0,0]) local inWorld = (v1.x >= bbMin.x-0.5 and v1.x <= bbMax.x+0.5) if not inWorld do ( -- 顶点在局部空间 → 手动乘变换矩阵转到世界空间 detailLog "顶点在局部空间,变换到世界空间" local tm = node.transform for v = 1 to m.numverts do setVert m v ((getVert m v) * tm) ) update m -- ========================================== -- 2b: 用 intersectRay 取命中点 (缩小 M-T 搜索范围) -- ========================================== -- 仅对 Editable_Poly 执行 (其他类型步骤1通常已成功) local hitPoint = undefined local isEPoly = try(classOf node == Editable_Poly) catch(false) if isEPoly do ( -- intersectRay: 3ds Max 原生, 返回 Ray (pos=命中点, dir=反射方向) local hrRay = try(intersectRay node ray) catch(undefined) if hrRay != undefined do ( hitPoint = hrRay.pos detailLog ("intersectRay 命中点: " + (hitPoint as string)) ) ) stepLog "2c: 执行 M-T 求交 (范围优化)" local result = manualIntersect m ray hitPoint:hitPoint threshold:100.0 if result != undefined then ( triFaceIdx = result[1] dist = result[2] if triFaceIdx > 0 do ( -- 从 mesh 获取 matID (作为兜底值) try (meshMatID = meshop.getFaceMatID m triFaceIdx) catch () detailLog ("M-T 命中三角面: " + (triFaceIdx as string) + " | 距离=" + (dist as string) + " | meshMatID=" + (meshMatID as string)) -- 三角面号 → 多边形面号 faceIdx = triToPolyFace node triFaceIdx detailLog ("三角面" + (triFaceIdx as string) + " → 多边面" + (faceIdx as string)) if faceIdx > 0 do found = true ) ) else ( failLog "M-T 未命中" ) -- 释放 mesh 快照内存 free m ) else ( failLog "snapshotAsMesh 失败" ) ) -- 两步求交都失败 if not found do ( failLog "所有求交方案失败" addLog " ✗ 求交失败" return undefined ) -- ========================================== -- 步骤3: 面心交叉验证 (仅 Editable_Poly) -- ========================================== -- 用命中点重算世界坐标, 在候选面 ±3 范围内找面心最近的面 if classOf node == Editable_Poly and dist > 0 do ( stepLog "步骤3: 面心交叉验证 (Editable_Poly)" -- 用射线起点 + 方向 * 距离 = 命中点世界坐标 local hitPt = ray.pos + (normalize ray.dir) * dist local vResult = verifyFaceByCenter node faceIdx hitPt local origFace = faceIdx faceIdx = vResult[1] -- 采纳修正后的面号 if faceIdx != origFace then ( detailLog ("面心修正: 面" + (numStr origFace) + " → 面" + (numStr faceIdx)) addLog (" 面心修正: 面" + (numStr origFace) + " → 面" + (numStr faceIdx)) ) else detailLog "面心验证: 无需修正" ) stepLog "步骤4: 获取面材质 ID (三级降级)" -- 优先级1: polyop.getFaceMatID (Editable_Poly 专用, 最准) -- 优先级2: getFaceMatID (Mesh 通用) -- 优先级3: meshMatID (步骤2从 mesh 获取的兜底值) local matID = 0 try (matID = polyOp.getFaceMatID node faceIdx) catch () if matID != undefined and matID > 0 do detailLog ("优先级1 polyop.getFaceMatID → matID=" + (matID as string)) if matID == undefined or matID == 0 do ( try (matID = getFaceMatID node faceIdx) catch () if matID != undefined and matID > 0 do detailLog ("优先级2 getFaceMatID → matID=" + (matID as string)) ) if matID == undefined or matID == 0 do ( matID = meshMatID detailLog ("优先级3 meshMatID (兜底) → matID=" + (matID as string)) ) if matID == undefined do matID = 0 okLog ("最终结果: 多边面=" + (faceIdx as string) + " | 三角面=" + (triFaceIdx as string) + " | matID=" + (matID as string)) return #(faceIdx, matID, triFaceIdx, dist) ) -- ========================================== -- RayEx 格式输出 -- ========================================== -- RayExOutput: 格式化输出 RayEx 结果 (精简版) -- Listener: RayEx #((ray [pos] [dir]), matID, [r,g,b]) -- UI日志: 物体/面ID/材质信息 fn RayExOutput obj hitPos matID faceID triFaceID colorRGB matName = ( -- Listener 精简输出: RayEx 格式 + 物体面材质摘要 format "RayEx #((ray [%]) % [%])\n" hitPos matID colorRGB format " >> % | 面% (三角面%) | matID:% | %\n" obj.name faceID triFaceID matID matName -- UI 日志精简输出 addLog (obj.name + " | 面" + (numStr faceID) + " | matID:" + (numStr matID) + " | " + matName) ) -- ========================================== -- 核心分析函数: 射线 → 命中对象 → 面求交 → 输出 -- ========================================== -- analyzeRay: 完整分析流程入口 -- 1. intersectRayScene: 射线与场景中所有对象求交 -- 2. 取首个命中对象 -- 3. pickFaceOnNode: 对命中对象做面级求交 -- 4. 提取颜色 + 材质名 → RayEx 输出 -- -- 返回: #(对象, 命中坐标, matID, 多边面号, 三角面号, 颜色, 材质名) 或 undefined fn analyzeRay theRay = ( stepLog "analyzeRay: 开始射线分析" detailLog ("射线起点: " + (theRay.pos as string) + " | 方向: " + (theRay.dir as string)) -- intersectRayScene: 射线与场景所有对象求交 stepLog "intersectRayScene: 射线与场景对象求交..." local hits = intersectRayScene theRay if hits.count == 0 do ( failLog "未命中任何对象" addLog "RayEx: 未命中任何对象" return undefined ) detailLog ("场景命中 " + (hits.count as string) + " 个对象, 取最近的") -- 取第一个命中对象 (距离最近的) local hitPair = hits[1] local obj = hitPair[1] -- 命中的节点 local hitPos = hitPair[2].pos -- 命中点世界坐标 detailLog ("命中对象: " + obj.name + " | 命中坐标: " + (hitPos as string)) -- 对命中对象执行面级求交 stepLog "pickFaceOnNode: 面级求交..." local result = pickFaceOnNode obj theRay if result == undefined do ( failLog "面级求交失败" addLog " 求交失败,无法提取材质" return undefined ) -- 解包求交结果 local faceIdx = result[1] -- 多边形面号 local matID = result[2] -- 材质 ID local triFaceID = result[3] -- 三角面号 local dist = result[4] -- 命中距离 -- 提取材质颜色和名称 stepLog "提取材质信息" local col = getHitColor obj matID local matName = getMatNameByID obj matID detailLog ("材质名称: " + matName + " | 颜色: [" + (numStr col.r) + "," + (numStr col.g) + "," + (numStr col.b) + "]") -- 输出结果 stepLog "输出 RayEx 结果" RayExOutput obj hitPos matID faceIdx triFaceID col matName return #(obj, hitPos, matID, faceIdx, triFaceID, col, matName) ) -- ========================================== -- 交互式拾取工具 (视口鼠标点击) -- ========================================== tool RayPickTool ( -- mousePoint: 鼠标点击事件 (clickno=1 表示第一次点击) on mousePoint clickno do ( if clickno == 1 do ( stepLog "视口点击拾取" detailLog ("屏幕坐标: " + (mouse.pos as string)) -- mapScreenToWorldRay: 屏幕坐标 → 世界射线 local theRay = mapScreenToWorldRay mouse.pos detailLog ("屏幕→世界射线: pos=" + (theRay.pos as string) + " dir=" + (theRay.dir as string)) -- 执行完整分析流程 local result = analyzeRay theRay if result != undefined do ( local obj = result[1] local matID = result[3] local faceIdx = result[4] local triFaceID = result[5] -- 更新状态标签 lbl_last.text = obj.name + " | 多边面" + (numStr faceIdx) + " | 三角面" + (numStr triFaceID) + " | matID=" + (numStr matID) ) -- 拾取完成后停止工具, 还原鼠标状态 stepLog "拾取完成, 还原鼠标状态" stopTool RayPickTool ) ) -- mouseMove: 空实现 (必须声明, 否则工具会退出) on mouseMove pt do () ) -- ========================================== -- 按钮事件 -- ========================================== -- btn_test: 主按钮 — 启动拾取工具 on btn_test pressed do ( logMsgs = #() lb_log.items = #() format "\n========================================\n" format " 材质吸取 - 准确性测试\n" format "========================================\n" stepLog "启动拾取工具" addLog "点击视口对象拾取" startTool RayPickTool ) -- 对话框打开时的初始化日志 on matPickTestRollout open do ( addLog "点击按钮后在视口拾取对象" ) ) -- 创建对话框 createDialog matPickTestRollout
查看完整描述 ︾

悬赏剩余时间:10小时15分15.5秒

我来回答
1个回答|图文描述更容易被采纳
  • 微信用户ID375502 | 2026-08-02 07:18:26

    AI生成材质脚本常因输出长度限制和逻辑理解偏差,导致代码不完整或节点连线错误,且工程落地步骤繁琐。解决方向: MCP协议(如UE5-Material-MCP):让AI直接操作引擎Python接口,自动创建节点和连线,实时生成材质。

    自动化脚本:编写辅助脚本解析AI代码,自动在软件中生成对应材质节点和参数.

    外部AI工具(如Sampler):直接生成PBR贴图,绕过脚本问题。

    建议:学习基础着色器语法,将AI定位为辅助工具。明确具体软件(UE/Blender/Unity)和材质效果,能获得更精准的方案。


    0 0 评论
网站地图Copyright © 2023 tzsucai.com All Rights Reserved 版权所有. 闽ICP备2023001872号-1 增值电信业务经营许可证:闽B2-20230721

*有问题的链接ID:

安全验证
您的账号可能存在安全风险,为了确保为您本人操作,请先进行安全验证。
验证方式:+86-888****8888
请输入验证码:
如需帮助,请联系客服
依国家《网络安全法》,互联网账号需要绑定手机,否则被盗号后,账户资产无法找回!
手机号:
登录验证

再次使用微信扫一扫授权登录