-
Notifications
You must be signed in to change notification settings - Fork 0
Tech
使用fnbt读取Schematic文件,并将所有方块信息写入一个三维列表中。
要匹配一个方块的模型,我们只需要这个方块的类型,不需要额外的数据。
所以我们只需要使用到方块的id
和data
这两个基本的方块信息。
详情 - Wiki - Schematic文件格式
Model类,用于定义一个方块的模型。
public class Model
{
public string __comment;
public Dictionary<string, string> textures;
public Element[] elements;
public class Element
{
public float[] from;
public float[] to;
public Dictionary<string, Face> faces;
public class Face
{
public string texture;
public float[] uv;
}
}
}
详情 - Wiki - 模型
通过Json.NET将Model类转为Json文件。
方块是模型中的基本单位。
尽管方块的材质不尽相同,但方块的模型却很有特点。
依照方块的外观,可以分为:
-
Layer - 层级方块,以高度划分,底部完整或近似完整,没有特殊行为的方块。
例如:石头、箱子、半砖、荷叶...
-
Connector - 连接体,能够和相邻同类方块连接的方块。
例如:栅栏、玻璃板、红石线...
-
Column - 柱体,以高度划分,底部不完整,没有特殊行为的方块。
例如:南瓜梗、小麦、火把...
-
Board - 板,以高度与朝向划分,竖立的且薄的,没有特殊行为的方块。
例如:告示牌、旗帜、门...
-
Wall - 墙贴,以高度与朝向划分,悬挂的且薄的,没有特殊行为的方块。
例如:告示牌、旗帜、可可豆...
目前只制作了层级方块和连接体
分为8个高度、10种类型:
- Height=1 - 流体、羊毛、雪层;
- Height=g - 压力板、比较器、中继器、陷阱门、荷叶;
- Height=2 - 流体、床、雪层;
- Height=3 - 流体、雪层、阳光检测器;
- Height=b - 流体、半砖、附魔台、雪层;
- Height=t - 半砖;
- Height=5 - 流体、雪层;
- Height=6 - 流体、铁砧、雪层;
- Height=7 - 流体、活塞臂、火、炼药锅、漏斗、雪层;
- Height=8 - 几乎所有建筑方块、台阶。
g:Height=1(不完整), b:Height=4(底部), t:Height=4(顶部), 真实高度 = Height * 0.125
分为3个高度、3种类型:
- Height=1 - 玻璃板、铁栅栏;
- Height=2 - 栅栏、石墙;
- Height=3 - 铁轨、红石线。
真实高度 = Height * 0.5
每个方块根据其id和data对应一个材质。
算法最终只会选取材质中的一个像素点。
用于普通材质,范围为16*16。
材质中不包含透明部分,因此在16*16范围内可以任取像素点。
x = (float)random.NextDouble() * 16;
y = (float)random.NextDouble() * 16;
return uv{x,y};
对于smooth模式,所选取的像素点是唯一的。
return uv{0,0};
用于透明材质,范围为16*16。
如果Json模型的所替换的方块不是透明方块,那么引用透明材质后,透明部分会变黑。
因此在16*16范围内任取像素点后,我们还要对Alpha进行比对,排除透明的像素点。(texturePath为对应材质的路径)
bool textureError = true;
while (textureError)
x = (float)random.NextDouble() * 16;
y = (float)random.NextDouble() * 16;
Bitmap compare = new Bitmap(texturePath);
textureError = (compare.GetPixel((int)x, (int)y).A <= 8);
}
return uv{x,y};
对于smooth模式,可以通过像素点索引顺序获取一个唯一解。
Bitmap compare = new Bitmap(texturePath);
for (int mh = 0; mh < compare.Size.Height; mh++)
{
for (int mw = 0; mw < compare.Size.Width; mw++)
{
if (compare.GetPixel(mh, mw).A > 8) { x = mh; y = mw; break; }
}
if (x > 0 && y > 0) break;
}
return uv{x,y};
用于关联生物群系的材质,范围为256*256。
拿树叶为例,这个方块非常特殊,它的材质本来只有黑白二色,而绿色,是根据生物群系的colormap(选取绿色)和它的材质(代表灰度)一起生成的。
如果Json模型的所替换的方块不是这些方块,在引用黑白材质后,所显示的还是黑白材质。
只有像树叶一样的某些特殊方块支持colormap,其他则不支持。
因此对于这些方块,需要另创一套算法,能从colormap中选取合适的颜色。
/// <summary>
/// 通过生物群系获取材质uv
/// </summary>
/// <param name="temp">温度</param>
/// <param name="rain">降水</param>
/// <param name="pixel_range">像素随机范围</param>
/// <param name="rich">是否使用foliage(默认为grass)</param>
/// <param name="warm">像素深度</param>
/// <returns>uv坐标</returns>
static public float[] getColorMapUV(float temp, float rain, int pixel_range = 0, bool rich = false, float warm = 0.0f)
{
float[] uv = new[] { /*uv-x*/0.0f, /*uv-y*/0.0f };
float uv_x = 0.0f, uv_y = 0.0f;
var theta = (double)new Random().NextDouble() * 360;
var d = (float)new Random().NextDouble() * pixel_range - pixel_range / 2;
uv_x = temp + (warm / 256f) + (d / 256f) * (float)Math.Cos(theta * Math.PI / 360); uv_y = temp * rain + (warm / 256f) + (d / 256f) * (float)Math.Sin(theta * Math.PI / 360);
if (uv_x < uv_y) { uv_x = temp + warm - (d / 256f) * (float)Math.Cosh(theta); uv_y = temp * rain + warm - (d / 256f) * (float)Math.Sinh(theta); }
if (rich)
{
uv_x = 1 - uv_x;
uv_y = 1 - uv_y;
}
else
{
var uv_t = uv_x;
uv_x = 1 - uv_y;
uv_y = 1 - uv_t;
}
uv[0] = (1 - uv_x)*16;
uv[1] = (1 - uv_y)*16;
return uv;
}
通过对这些属性的设置,能够使最终在colormap中所选取的颜色接近于方块在Minecraft中所显示的颜色。
详情 - Wiki - 生物群系
将方块按照模型分类,每个方块对应一个材质。
h8.Add("137_0", "blocks/command_block_front");
"h8":方块模型, "137_0":方块id_方块data, "blocks/command_block_front":方块材质
对于一个方块,若能够忽略其data而对应同一个材质,使用'x'代替data以简化。
h8.Add("136_x", "blocks/planks_jungle");
"h8":方块模型, "137_x":方块id_忽略data, "blocks/planks_jungle":方块材质
将模型缩放至2*2*2的大小,使其能在Minecraft中正常显示。
if (!args.Contains("unlimit"))
{
var max = elements.Select(element => element.to.Max()).Concat(new float[] { 0 }).Max();
var changedAmount = (max - 32.0f) / max;
if (changedAmount > 0)
{
foreach (var element in elements)
{
for (var i = 0; i < 3; i++)
{
element.from[i] = Math.Max(element.from[i] - changedAmount * element.from[i], 0);
}
for (var i = 0; i < 3; i++)
{
element.to[i] = Math.Max(element.to[i] - changedAmount * element.to[i], 0);
}
}
}
}
- 增加filter_blocks、filter_models、biome指令(仅限cmd)
- 修复colormap材质算法,使与生物群系关联的方块有与生物群系关联的材质,包括树叶、荷叶(默认生物群系为虚空void)
- 增加UI操作
- 优化模型类型结构,并支持所有层级方块
- 修复透明材质问题
- 支持栅栏、玻璃板、地毯、雪层、压力板、红石比较器、红石中继器、陷阱门、荷叶、阳光感应器、附魔台、铁砧、活塞头、火、炼药锅、漏斗
- 修复普通玻璃的不透明性
- 修复DV读取不全
- 支持树叶
- 增加version指令
- 支持流体:水和岩浆
- 将材质列表升级为1.12版本
- 优化了部分算法
- 支持所有建筑方块
- 增加了smooth模式
- 将材质列表升级为1.10版本
- 程序框架完成,材质仅支持羊毛和硬化黏土