CNPC OBJ模型兼容

CNPC OBJ模型兼容

为CNPC提供OBJ相关渲染兼容性

我的Discord群组:https://discord.gg/rSaFbj89Te

CNPC OBJ Models

中文

CNPC OBJ Models 为 Minecraft 的 CustomNPCs 提供静态 OBJ 模型支持。

本 Mod 支持使用 OBJ + MTL + PNG 为 NPC、NPC 盔甲、脚本方块、脚本物品以及任意物品添加自定义模型。

无需编写任何 JSON 模型配置。

支持内容

  • 静态 OBJ 模型加载与渲染
  • OBJ、MTL、PNG 支持
  • MTL 可选
  • 支持资源包中的自定义模型
  • NPC OBJ 模型
  • NPC OBJ 盔甲
  • 脚本方块 OBJ 模型
  • 脚本物品 OBJ 模型
  • 通过指令为任意物品添加 OBJ 模型
  • XYZ 独立缩放
  • XYZ 独立旋转
  • 模型位置偏移
  • 物品栏 GUI 中的模型位置与大小调整
  • 独立的盔甲穿戴位置偏移
  • 可控制是否显示原版盔甲
  • 背面剔除控制
  • NPC OBJ 模型碰撞箱设置
  • 通过 /cnpcobj info 查看当前配置
  • OBJ、MTL、PNG 路径支持 Tab 补全

资源路径

所有模型和贴图路径均使用 Minecraft ResourceLocation 格式:

namespace:path

例如:

cnpcobj:models/dream_sphere.obj cnpcobj:models/dream_sphere.mtl cnpcobj:models/texture.png

自定义资源包可以按照以下结构放置:

assets/your_namespace/models/example.obj assets/your_namespace/models/example.mtl assets/your_namespace/models/texture.png

资源路径必须符合 Minecraft ResourceLocation 的命名规则。

文件名和路径不能使用中文等不受支持的字符。

贴图优先级

模型贴图按照以下优先级选择:

  1. 显式指定的 PNG 贴图
  2. MTL 文件中的第一个 map_Kd 贴图
  3. 白色兜底贴图

MTL 文件不是必须的。

OBJ + PNG 可以在没有 MTL 的情况下正常工作。

OBJ + MTL 可以从 MTL 中的 map_Kd 自动读取贴图。

如果同时指定 MTL 和 PNG,则显式指定的 PNG 优先。

如果没有任何贴图,模型仍然会被渲染,只是使用白色兜底贴图。

NPC 脚本 API

NPC OBJ 模型通过 event.npc 进行配置。

使用 API 前,NPC 必须先在模型设置中选择「OBJ Models」。

可用方法:

npc.setObjModel(String path) 设置 OBJ 模型路径。

npc.getObjModel() 获取当前 OBJ 模型路径。

npc.setObjMtl(String path) 设置 MTL 路径。 MTL 文件是可选的。 传入空字符串可以清除 MTL 路径。

npc.getObjMtl() 获取当前 MTL 路径。

npc.setObjTexture(String path) 设置 PNG 贴图路径。

npc.getObjTexture() 获取当前 PNG 贴图路径。

npc.setObjScale(float x, float y, float z) 设置模型 XYZ 缩放。

npc.setObjRotation(float x, float y, float z) 设置模型 XYZ 旋转。 单位为角度。 旋转围绕 OBJ 模型自身中心进行,不会因此改变模型位置。

npc.setObjHitbox(float width, float height) 设置 NPC 碰撞箱宽度和高度。 传入 0 表示不覆盖对应配置,继续使用 CustomNPCs 原本的碰撞箱计算方式。

npc.setObjCullBackface(boolean cull) 设置是否启用背面剔除。 默认值:true。

npc.clearObjModel() 清除 NPC 的全部 OBJ 配置。

脚本方块脚本 API

可以通过 event.block 为 CustomNPCs 脚本方块设置 OBJ 模型。

可用方法:

block.setObjModel(String path) 设置 OBJ 模型路径。

block.getObjModel() 获取当前 OBJ 模型路径。

block.setObjMtl(String path) 设置 MTL 路径。 MTL 文件是可选的。

block.getObjMtl() 获取当前 MTL 路径。

block.setObjTexture(String path) 设置 PNG 贴图路径。

block.getObjTexture() 获取当前 PNG 贴图路径。

block.setObjScale(float x, float y, float z) 设置模型 XYZ 缩放。

block.getObjScaleX() 获取 X 轴缩放。

block.getObjScaleY() 获取 Y 轴缩放。

block.getObjScaleZ() 获取 Z 轴缩放。

block.setObjRotation(float x, float y, float z) 设置模型 XYZ 旋转,单位为角度。

block.getObjRotationX() 获取 X 轴旋转。

block.getObjRotationY() 获取 Y 轴旋转。

block.getObjRotationZ() 获取 Z 轴旋转。

block.setObjCullBackface(boolean cull) 设置是否启用背面剔除。 默认值:true。

block.clearObjModel() 清除脚本方块的全部 OBJ 配置。

脚本方块同步机制

脚本方块 OBJ 配置使用 CustomNPCs 自身的 needsClientUpdate 同步机制。

TileScripted 每 10 tick(0.5 秒)检查一次变化。

因此,如果在脚本中每 tick 修改模型,客户端并不会每 tick 平滑显示变化,而是按照 CustomNPCs 自身的同步间隔更新。

这是 CustomNPCs 的同步机制,并不是 OBJ 渲染器的问题。

OBJ 模型会替代脚本方块原本的外观。

手持 CustomNPCs 的 wand 或 scripter 时,脚本方块仍会临时显示 CustomNPCs 原本的脚本方块图标。

这是刻意保留的行为,可以方便定位和编辑脚本方块。

脚本方块原本的六个文本平面 text1 到 text6 仍然正常工作。

脚本物品脚本 API

可以为 CustomNPCs 的脚本物品(customnpcs:scripted_item)设置 OBJ 模型。

获取 IItemScripted 后,可以使用以下方法。

item.setObjModel(String path) 设置 OBJ 模型路径。

item.getObjModel() 获取当前 OBJ 模型路径。

item.setObjMtl(String path) 设置 MTL 路径。 MTL 文件是可选的。

item.getObjMtl() 获取当前 MTL 路径。

item.setObjTexture(String path) 设置 PNG 贴图路径。

item.getObjTexture() 获取当前 PNG 贴图路径。

item.setObjScale(float x, float y, float z) 设置模型 XYZ 缩放。

item.setObjRotation(float x, float y, float z) 设置模型 XYZ 旋转,单位为角度。 旋转围绕 OBJ 模型自身中心进行。

item.setObjGuiOffset(float x, float y) 设置模型在物品栏 GUI 中的 XY 位置偏移。

item.setObjGuiScale(float x, float y) 设置模型在物品栏 GUI 中的 XY 显示大小。

item.getObjGuiOffsetX() 获取物品栏 GUI X 轴偏移。

item.getObjGuiOffsetY() 获取物品栏 GUI Y 轴偏移。

item.getObjGuiScaleX() 获取物品栏 GUI X 轴大小。

item.getObjGuiScaleY() 获取物品栏 GUI Y 轴大小。

item.setObjOffset(float x, float y, float z) 设置非物品栏场景下使用的 XYZ 模型空间位置偏移。

该偏移会影响:

  • 第一人称手持
  • 第三人称手持
  • 地面掉落
  • 展示框
  • 头顶显示

三个轴均允许使用负数。

1.0 代表模型空间中的一个 Minecraft 方块单位。

通常应该使用该方法调整模型在玩家手中的位置。

item.getObjOffsetX() 获取 X 轴模型偏移。

item.getObjOffsetY() 获取 Y 轴模型偏移。

item.getObjOffsetZ() 获取 Z 轴模型偏移。

item.setObjArmorOffset(float x, float y, float z) 设置 OBJ 作为盔甲渲染时使用的 XYZ 偏移。

盔甲偏移与普通物品偏移相互独立。

默认情况下会显示原版盔甲。

item.setObjArmorOffset(float x, float y, float z, boolean showVanillaArmor) 设置盔甲 XYZ 偏移,同时控制是否显示原版盔甲。

true = 显示原版盔甲 false = 只显示 OBJ 模型

item.getObjArmorOffsetX() 获取盔甲 X 轴偏移。

item.getObjArmorOffsetY() 获取盔甲 Y 轴偏移。

item.getObjArmorOffsetZ() 获取盔甲 Z 轴偏移。

item.setObjShowVanillaArmor(boolean show) 控制 OBJ 盔甲模型是否与原版盔甲一起显示。

默认值:true。

item.getObjShowVanillaArmor() 获取当前原版盔甲显示状态。

item.setObjCullBackface(boolean cull) 设置是否启用背面剔除。 默认值:true。

item.clearObjModel() 清除脚本物品的全部 OBJ 配置。

GuiOffset、GuiScale 与 Offset 的区别

setObjGuiOffset 和 setObjGuiScale 只影响模型在物品栏 GUI 中的显示。

setObjOffset 影响所有非物品栏场景,包括:

  • 第一人称手持
  • 第三人称手持
  • 地面掉落
  • 展示框
  • 头顶显示

普通模型偏移和盔甲偏移相互独立。

调整模型在玩家手中的位置时,应使用 setObjOffset。

调整模型穿戴为盔甲时的位置,应使用 setObjArmorOffset。

脚本物品同步机制

脚本物品 OBJ 配置使用 CustomNPCs 的 updateClient 机制。

ScriptPlayerEventHandler 每 10 tick(0.5 秒)检查一次背包物品。

因此,修改脚本物品 OBJ 配置后可能需要最多约 0.5 秒才能在客户端看到变化。

指令 API

指令格式:

/cnpcobj <子指令> [参数]

权限等级:2。

所有子指令都只作用于执行者当前主手上的物品。

没有槽位参数。

指令不会修改其他物品栏槽位。

适用物品

指令系统可以处理任意 ItemStack。

包括:

  • 原版盔甲
  • Mod 盔甲
  • 武器
  • 工具
  • 方块
  • CustomNPCs 脚本物品
  • 其他 Mod 的物品

OBJ 配置直接保存于 ItemStack 的 CnpcObjModel NBT 数据中,不依赖特定物品 Mod 的能力或接口。

可用指令

/cnpcobj model <path> 设置 OBJ 模型。

/cnpcobj mtl <path> 设置 MTL 文件。

/cnpcobj texture <path> 设置 PNG 贴图。

/cnpcobj scale <x> <y> <z> 设置 XYZ 缩放。

/cnpcobj rotation <x> <y> <z> 设置 XYZ 旋转,单位为角度。

/cnpcobj guipos <x> <y> 设置 OBJ 模型在物品栏 GUI 中的 XY 位置。

/cnpcobj guisize <x> <y> 设置 OBJ 模型在物品栏 GUI 中的 XY 大小。

/cnpcobj offset <x> <y> <z> 设置非物品栏场景下的 XYZ 模型空间位置偏移。

允许使用负数。

可以用于调整模型在玩家手中、地面或展示框中的位置。

/cnpcobj armoroffset <x> <y> <z> [true|false] 设置 XYZ 盔甲穿戴位置偏移。

最后一个可选的布尔参数控制是否显示原版盔甲。

true = 显示原版盔甲 false = 只显示 OBJ 模型

省略该参数时默认为 true。

/cnpcobj vanillaarmor <true|false> 控制是否显示原版盔甲。

默认值:true。

/cnpcobj cull <true|false> 设置是否启用背面剔除。

默认值:true。

/cnpcobj clear 清除主手物品的全部 OBJ 配置。

/cnpcobj info 查看主手物品当前的 OBJ 配置。

指令 Tab 补全

model、mtl 和 texture 的路径参数支持 Tab 补全。

补全系统会扫描已加载资源包中的 models/ 目录,并根据当前需要的文件类型进行筛选。

例如输入部分模型名称后按 Tab,可以筛选可用模型路径。

单人游戏和局域网主机中,客户端与服务端运行在同一个 JVM,因此资源扫描可以正常工作。

专用服务器无法以相同方式访问客户端资源包中的资源。

因此,在专用服务器环境下 Tab 补全可能为空。

此时可以直接手动输入完整 ResourceLocation 路径。

NPC 盔甲支持

通过 OBJ 配置过的物品可以作为盔甲穿戴在 CustomNPCs NPC 身上。

当 NPC 使用 OBJ Models 模型类型时,NPC 自身的 OBJ 模型以及符合条件的 OBJ 盔甲都可以一起渲染。

盔甲使用 armoroffset / setObjArmorOffset 设置的独立偏移。

不会使用普通物品的手持偏移。

盔甲模型会跟随对应的 NPC 身体部位:

  • 头部
  • 胸部 / 身体
  • 腿部
  • 脚部

NPC 图形界面

通过 GUI 配置 NPC:

  1. 右键 NPC,打开模型设置。
  2. 在模型列表中找到 OBJ Models。
  3. 选择 OBJ Models。
  4. 右上角会出现「OBJ 模型:[编辑]」按钮。
  5. 点击编辑进入 OBJ 配置界面。

OBJ 编辑器包含以下设置:

OBJ 文件 必填的 OBJ 模型路径。

MTL 文件 可选的 MTL 文件路径。

PNG 贴图 可选的 PNG 贴图路径。

缩放 X / Y / Z 独立的 XYZ 模型缩放。

旋转 X / Y / Z 独立的 XYZ 模型旋转,单位为角度。

碰撞箱 宽 / 高 NPC 自定义碰撞箱大小。 设置为 0 时使用 CustomNPCs 原本的碰撞箱逻辑。

背面剔除 控制是否剔除模型背面的三角面。

清除模型 清除全部 OBJ 配置。

资源选择按钮会列出已加载资源包中 models/ 目录下的资源。

双击资源即可选择。

如果列表为空,也可以直接在输入框中手动输入路径。

模型缩放

OBJ 的单位不一定与 Minecraft 的方块单位一致。

一个 Minecraft 方块对应 1.0 的模型空间单位。

根据建模软件和导出设置的不同,模型可能需要进行较大幅度的缩放。

例如,Blockbench 导出的部分模型可能需要使用约 0.0625(1/16)的缩放比例。

背面剔除

背面剔除默认开启。

对于球体等闭合模型,通常建议保持开启。

对于旗子、广告牌等单面模型,如果需要从正反两面都能看到模型,应关闭背面剔除。

已知限制

CNPC OBJ Models 主要用于静态 OBJ 模型。

目前不提供骨骼动画或动画 OBJ 模型支持。

如果需要动画模型,请使用基于 GeckoLib 的方案,例如 CNPC-Gecko-Addon。

与 Gecko Addon 的兼容性

CNPC OBJ Models 与 Gecko 模型相关的 Mod 可以同时安装。

两者不需要互相替代。

一个 NPC 的模型槽位一次只能使用一种模型类型。

NPC 使用 OBJ Models 时使用 OBJ 渲染器。

NPC 使用 Gecko 模型时使用 Gecko 渲染器。

因此,两种模型类型对于同一个 NPC 来说是互斥的,但并不是两个 Mod 之间的直接冲突。

常见问题

模型出现碎片化、破洞或渲染异常:

请确认使用的版本已经包含 OBJ 面处理相关修复。

包含复杂多边形的 OBJ,尤其是超过四个顶点的凹多边形,可能无法正确进行三角化。

建议在建模软件中先将复杂面三角化,再导出 OBJ。

从模型背面可以看到模型内部:

开启背面剔除。

使用:

setObjCullBackface(true)

或者:

/cnpcobj cull true

旗子、广告牌等单面模型从背面看不见:

关闭背面剔除。

使用:

setObjCullBackface(false)

或者:

/cnpcobj cull false

模型完全是白色的:

检查 MTL 中的 map_Kd 路径。

检查显式指定的 PNG 路径。

使用:

/cnpcobj info

查看当前 OBJ 配置。

模型太大或太小:

调整模型缩放。

OBJ 的单位会根据建模软件和导出设置有所不同。

部分 Blockbench 导出的模型可能需要约 0.0625(1/16)的缩放。

脚本方块或脚本物品修改后没有立即生效:

CustomNPCs 大约每 10 tick(0.5 秒)同步一次这些变化。

等待下一次客户端同步即可。

NPC 选择了 OBJ Models,但是没有显示模型:

请确认已经设置 OBJ 模型路径。

NPC 选择 OBJ Models 但没有配置 OBJ 文件时,本身就不会显示 OBJ 模型。

这样可以方便区分「已经选择 OBJ 模型类型」和「已经完成 OBJ 模型配置」的 NPC。