ruhuasiyu
本帖最后由 ruhuasiyu 于 2016-8-16 20:45 编辑
在文章结尾新增了单指令工具,这样不用计算只需要输入控制点即可得到命令。

本文受 http://www.mcbbs.net/thread-565887-1-1.html @林扬骐 启发,但是我觉得原来的作者原理上讲的可能不是很清楚,而且算法(速度)也慢了。

Bezier曲线
首先我就不贴那两张图了。这样的曲线叫做Bezier曲线,n+1个点控制的我们称为n阶Bezier曲线,因为这条曲线的方程式n次的。
例如 n=2 时,对应的曲线一定是抛物线。


过程我不作推导,n次Bezier曲线的方程以向量形式为


特别地, n=2 时为


例子和命令
以 P_0=(0,0,0), P_1=(7,6,-10), P_2=(10,1,-3) 为例
P=(-4t^2+14t, -11t^2+12t, 17t^2-20t)

令步数为 N=100, s=100 t, 则
P(s)-P(s-1)=(-0.0008,-0.0022,0.0034)s+(0.1404,0.1211,-0.2017).

我们现在来实现它。首先召唤两个雪球 a 和 b:
  1. summon Snowball ~10 ~5 ~10 {CustomName:"a",CustomNameVisible:1,NoGravity:1}
  2. summon Snowball ~10 ~5 ~10 {CustomName:"b",CustomNameVisible:1,NoGravity:1}
复制代码

然后放置 3 个命令方块, 依次为循环型、连锁型条件保持开启、连锁型条件保持开启并输入命令
  1. tp @e[name=a] ~0.1404 ~0.1211 ~-0.2017
  2. execute @e[name=b] ~ ~ ~ tp @e[name=a] ~-0.0008 ~-0.0022 ~0.0034
  3. execute @e[name=a] ~ ~ ~ summon Snowball ~ ~ ~ {CustomName:"b",CustomNameVisible:1,NoGravity:1}
复制代码


如此第 s 步的时候有 s 个雪球 b,每个雪球 b 将雪球 a 移动 (-0.0008,-0.0022,0.0034),再加上第一个命令的 (0.1404,0.1211,-0.2017), 因此共移动
(-0.0008,-0.0022,0.0034)s+(0.1404,0.1211,-0.2017)=P(s)-P(s-1)。

所以从开始到第 s 步共移动 P(s)-P(0)=P(s),我们成功将雪球 a 移动至 Bezier 曲线上的第 s 的拟合点。



计算公式
对于一般的3个控制点 P_0=(0,0,0), P_1=(a,b,c), P_2=(d,e,f),  设步数为 N,计算出
  1. (2a(N+1)-d)/N^2, (2b(N+1)-e)/N^2, (2c(N+1)-f)/N^2,
  2. (2d-4a)/N^2, (2e-4b)/N^2, (2f-4c)/N^2,
复制代码

将其代入上述两个 execute 命令的相对坐标即可。

如果需要的话可以加一个循环次数的限制,利用计分板即可,原帖中有提及,这里回忆一下:先生成一个记分板
  1. scoreboard objectives add temp dummy
复制代码

再设置循环次数为 100 次
  1. scoreboard players set #n temp 100
复制代码

在原来的命令方块前方和后方各添加
  1. scoreboard players test #n temp 1 10000
  2. scoreboard players remove #n temp 1
复制代码

设置命令方块模式如图


对于n阶Bezier曲线,设步长为 N,将s=Nt 代入公式中计算出 P(s),
然后计算 P(s)-P(s-1) 得到 s 的 n-1 阶多项式,将其从低次到高次的坐标依次代入
  1. tp @e[name=a] ~这里 ~这里 ~这里
  2. execute @e[name=b] ~ ~ ~ tp @e[name=a] ~这里 ~这里 ~这里
  3. execute @e[name=b] ~ ~ ~ execute @e[name=b] ~ ~ ~ tp @e[name=a] ~这里 ~这里 ~这里
  4. ……
  5. 直到 n-1 个 execute @e[name=b] ~ ~ ~ …… execute @e[name=b] ~ ~ ~ tp @e[name=a] ~这里 ~这里 ~这里
复制代码

即可。算法速度为 O(N^n),上述例子大约需执行5000次,时长约数秒。

这是用4条Bezier曲线拟合得到的圆




OOC生成器

如果你觉得上述过程不能理解,你可以直接打开下面的网页,输入控制点的绝对坐标和拟合点的个数,即可生成一条命令,然后将该命令复制到命令方块中执行即可,最后敲到多余的方块。
http://zsx.blog.ustc.edu.cn/wp-c ... 2016/08/bezier.html


每次画完之后请输入
  1. entitydata @e[type=Snowball] {CustomName:""}
复制代码

将雪球的名字去掉,然后再进行下一条曲线的生成。删除上一次生成的曲线只需
  1. kill @e[type=Snowball,name=a]
  2. kill @e[type=Snowball,name=b]
复制代码

删除所有曲线输入
  1. kill @e[type=Snowball]
复制代码

因为这几条命令比较简单我就没加到OOC里面了。

以下是利用OOC得到的控制点为 (0,20,0),  (0,20,20),  (20,20,20) 得到的近似1/4圆。










pylsdani
这玩意可以拿来当装饰,并木有实际意义~

kuangwenxin
这都是高科技,

woshisong12
{:10_496:}虽然我用不到 但是好厉害

爱心魔王FHC
把雪球换成带着方块的盔甲架就能做彩虹了23333
初三表示看不懂乱七八糟的公式了

乙烯_中国
我看了一下这个帖子,难道说这个数字,是你自己打进去而不是通过cb阵列自行计算的吗?

下一页 最后一页