UID82897性别保密经验 EP铁粒 粒回帖0主题精华在线时间 小时注册时间2021-7-23最后登录1970-1-1
| 本帖最后由 Cat_Anchor 于 2023-8-27 16:53 编辑
前言
|
今天,我们来讲点以前在讲方块时应该说的内容——动态纹理。
| | 动态方块纹理
|
动态纹理只支持循环播放,每“帧”动态纹理之间会叠化。几乎每个动态纹理都是长长的。如果没有使用模型,动态纹理的宽度一般是16,高度一般是16的倍数,这取决于你想让这个方块的动态纹理的一个循环有多长。以最上面为开始,画出16*16的范围,这就是动态纹理的第一帧。每向下16个像素都有一帧,一共有几帧不固定,这决定了高度。动态纹理的所有帧垂直着连接在一起,形成一张高度值很大的图片。
如果使用了模型,动态纹理的一帧会根据模型中定义的纹理宽度和高度进行解析。这种情况很少见,但是某些情况下非常有用。
动态纹理在资源包根目录下textures文件夹下flipbook_textures.json定义。打开这个文件,写以下代码。
- [
- {
- "flipbook_texture": "textures/blocks/fire_1", //纹理的路径,不需要后缀
- "atlas_tile": "fire_1", //对应着terrain_textures.json里的纹理短名。
- "frames": [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 ] //定义到底该以什么顺序播放帧。如果省略,就是从上播放到下。帧可以多次播放。
- },
- {
- "flipbook_texture": "textures/blocks/water_still_grey",
- "atlas_tile": "still_water_grey",
- "ticks_per_frame": 2 //指定一帧与一帧之间有多少游戏刻。
- },
- {
- "flipbook_texture": "textures/blocks/water_flow_grey",
- "atlas_tile": "flowing_water_grey",
- "replicate": 2 //只能写2的倍数。可以改变纹理使用的大小,指定了只渲染1/(值*2)像素。比如,值是2,那么只渲染4分之1的像素。值是4,只渲染8分之1的像素。这些渲染的像素会放大到一个方块的大小。
- },
- {
- "flipbook_texture": "textures/blocks/bubble_column_outer_a",
- "atlas_index": 0, //指定了一个纹理短名对应的数组中的很多纹理中,需要动态纹理的那个。
- "atlas_tile_variant": 0, //指定了一个纹理短名对应的变种中的很多纹理中,需要动态纹理的那个。
- "atlas_tile": "bubble_column_outer",
- "ticks_per_frame": 1,
- "frames": [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 ],
- "blend_frames": false //决定了混合帧。如果设为false,则不会将帧与帧之间叠化处理,会瞬间切换。如果是true,则叠化处理(又称平滑过渡处理)。
- }
- ]
复制代码
以上讲的那些都只适用于方块,至于物品,目前官方没有开放接口。
| | 动态物品纹理
|
制作动态方块纹理还算简单,但对于动态物品纹理,我们完全没有头绪,因为官方没有开放接口。也确实有一些模模糊糊的线索,例如物品组件minecraft:icon中的frame参数可能会接受Molang值从而实现动态纹理,例如似乎没有已知功能的minecraft:frame_count物品组件可以填写数字,等等。但那些实在是太复杂了,我研究了很久也没有做出什么成绩来。况且,Mojang已经移除了那些无用的组件。
所以,还是换一种思路吧。一天,我在翻看原版的兔子的渲染控制器文档时,发现里面用q.get_name实现了那个Toast兔子的彩蛋。没错,渲染控制器可以改变实体纹理。经过高手的评论,我明白了可以通过附着物和渲染控制器做出动态纹理。
我做的维度蛋糕附加包中,维度苹果的纹理就是动态的。当时我还在使用旧方法,不过参考了原版弓的渲染后,可以使用texture_mesh来完成这一点。texture_mesh就是一种把纹理转换成模型的技术,很适合做这个。
- "name": "rightitem", //直接覆盖原版中右手物品的模型
- "texture_meshes" : [ //指定纹理转换模型
- { //这下面的都不用改,主要看最后一个
- "local_pivot" : [ 6.0, 0.0, 6.0 ],
- "position" : [ 2.0, 1.0, -1.0 ],
- "rotation" : [ 0.0, -135.0, 90.0 ],
- "texture" : "bow_pulling_0" //渲染控制器里的纹理短名,记得修改
- }
- ]
复制代码
然后参考原版弓的动画就可以了。下面是旧方法。
创建一个模型,把物品的立方体的父立方体设置为rightItem,然后给物品添加一个附着物文档,再用渲染控制器使纹理切换。
首先,把需要的模型和玩家右手物品的模型绑定。这是我当时写的代码,主要看一下parent这一行,这一行代码使这个立方体组与原版中右手的物品的模型绑定。以下代码在bones数组下。
- {
- "name": "Item",
- "parent": "rightArm",
- "pivot": [...],
- "rotation": [...],
- "cubes": [...]
- }
复制代码
但上面是非动态的,只要把物品放到左手(副手)就露馅了。下面这种方法其实更好,可以根据上下文动态切换到底是绑定在左手还是右手。
- { //注意,要先把模型文件的格式升级到1.16.0才能使用binding。
- "name": "Item",
- "binding": "q.item_slot_to_bone_name(c.item_slot)", //这个Molang表达式中,我使用了一些缩写,q.等于query.,这个函数表示查询物品所在的骨骼名称,需要一个参数,所以右边在()里指定这个参数。c.等于context.,用于读取上下文数据,这里是读取到底在左手还是右手。这个表达式的作用是,如果物品在左手,输出leftItem,这样就绑定到左手那里;如果物品在右手,输出rightItem,这样就绑定到右手那里。
- "pivot": [...],
- "rotation": [...],
- "cubes": [...] //忘了说了,这里我建议使用很多个高度为0的立方体,在高度上多叠几个,实现类似于原版的物品模型效果,要不然会很麻烦。
- }
复制代码
然后定义一个动画。其实并不是真正的动画,只是为了能让物品在正确的位置。这个没办法教学,只能把玩家的模型导入blockbench然后硬搞,我也不能提供一个确切的数值。先把上面定义的模型和原版玩家模型导入,然后新建一个动画,在动画编辑页面里把上面定义的模型拖到平时玩家手里拿物品的那里。等你觉得看起来差不多而且不太奇怪了,就保存这个动画。注意,要给第一人称和第三人称都做一个动画。
现在你有了模型文件和动画文件,还缺附着物文件。就拿维度苹果的附着物文件说吧,其实你只需要稍微改改这个文件,就能直接用。
- {
- "format_version": "1.10.0",
- "minecraft:attachable": {
- "description": {
- "identifier": "supplementary:end_apple", //我的维度苹果的id,这里要改成你要做动态纹理的物品id
- "materials": {
- "default": "entity_alphatest", //不用管,只是让纹理支持透明
- "enchanted": "entity_alphatest_glint" //不用管,只是让物品可以有附魔效果(尽管实际上这个物品不可能有附魔),我建议不要删,否则会崩溃
- },
- "textures": {
- "apple1": "textures/items/end_apple1", //起个好记的名字,我这里是apple1,apple2,等等。以后要用。后面指定物品纹理,当然是能让你的模型正确显示的纹理。
- "apple2": "textures/items/end_apple2",
- "apple3": "textures/items/end_apple3",
- "apple4": "textures/items/end_apple4",
- "apple5": "textures/items/end_apple5",
- "apple6": "textures/items/end_apple6",
- "apple7": "textures/items/end_apple7",
- "apple8": "textures/items/end_apple8",
- "enchanted": "textures/misc/enchanted_item_glint" //别动它
- },
- "geometry": {
- "default": "geometry.item" //你自定义的模型id
- },
- "animations": {
- "holding": "animation.item2.holding", //指定两个动画,一个第一人称,一个第三人称
- "holding_third": "animation.item2.holding_third" //这是第三人称的动画
- },
- "scripts": {
- "animate": [
- {
- "holding": "q.main_hand_item_use_duration <= 0.0f && c.is_first_person" //c.is_first_person判断是否是第一人称
- },
- {
- "holding_third": "q.main_hand_item_use_duration <= 0.0f && !c.is_first_person" //c.is_first_person前面加!表示反选,判断是否不是第一人称
- }
- ]
- },
- "render_controllers": [
- "controller.render.tp_apples" //渲染控制器的id,这个要牢记,一会儿要用
- ]
- }
- }
- }
复制代码
然后新建一个渲染控制器文件。例如,我的维度苹果的渲染控制器。
- {
- "format_version": "1.8.0",
- "render_controllers": {
- "controller.render.tp_apples": { //这里,controller.render.tp_apples是渲染控制器的id,要与上面那个渲染控制器的id一样。
- "geometry": "Geometry.default", //不要改,这个代表使用刚才的默认模型
- "materials": [
- {
- "*": "Material.default" //也不要改,表示使用刚才的材料。
- }
- ],
- "textures": [
- "t.time = q.life_time * 7.8; return array.skins[t.time];" //这里首先定义了缓存变量t.time,定义这个缓存数据等于后面的Molang表达式,然后返回array.skins[缓存数据t.time的值]。q.life_time返回一个随时间增加的值,类似于正比例函数。(注:t.等于temp.,即临时缓存)
- ],
- "arrays": {
- "textures": {
- "Array.skins": [
- "Texture.apple1", //这里就是之前那个apple1啊,apple2啊,之类的纹理短名。这里的排列顺序决定了最后的动态纹理的切换顺序。一个值是一帧。
- "Texture.apple2",
- "Texture.apple3",
- "Texture.apple4",
- "Texture.apple5",
- "Texture.apple6",
- "Texture.apple7",
- "Texture.apple8"
- ]
- }
- }
- }
- }
- }
复制代码
一番操作猛如虎,经过好几次不成功的试验之后,你的物品纹理成功动了起来。没错,真麻烦。这篇教程在前期附加包教程系列(1-32期)的大小排行中排到了第三,第一和第二其实都是列举组件。所以其实这是我在前期附加包教程系列写的最长的一篇教程了,其难度可见一斑。
(当然,第33期的大小已经超过了20KB,因为那属于后期附加包教程系列。)
| | 总结
|
这一期,我们学习了方块和物品的动态纹理制作。
|
|
|