找回密码
 点一下
查看: 3229|回复: 28

Bad Apple!! 高清版 80×60 16FPS

[复制链接]
发表于 2020-9-6 22:07:52 | 显示全部楼层 |阅读模式
本帖最后由 枪兵打巨像 于 2021-2-1 20:50 编辑

Bad Apple!! 星际争霸2萨尔那加神器版 80×60 16FPS.mp4_000104.951.jpg

经过一个月的艰苦努力,高清版 Bad Apple!! 终于出炉了 !

相比上个版本:
- 分辨率从 24×18 提高到了 80×60
- 像素数量从 432 个提高到了 4800 个!
- 帧率从 12.5 帧提高到了 16 帧!
- 音画不同步问题已解决,累计误差从 +100 秒减小到了 +1 秒!
- 编码表导入算法从 数组导入算法 改为了 字符串导入算法 ,编码效率提高了 15 倍!

视频演示:
萨尔那加神器版:https://www.bilibili.com/video/BV1EA411n7dB/
高能瓦斯版:https://www.bilibili.com/video/BV1mT4y1L7ZD/

开发过程:https://bbs.islga.org/read-htm-tid-5486853-page-1-fpage-1.html

24×18版本链接:https://bbs.islga.org/read-htm-tid-5486762-page-1-fpage-1.html

 楼主| 发表于 2020-9-6 22:12:11 | 显示全部楼层
本帖最后由 枪兵打巨像 于 2020-10-19 18:54 编辑

Bad Apple!! 实现过程:

1、新建单位作为像素点 ↓↓↓
     (1) 新建单位。
     (2) 新建演算体,并于单位关联。
     (3) 导入指定单位模型,尽量挑选光照、粒子、烟雾效果少的模型,减少CPU负担。
     (4) 通过演算体进行模型优化,停止模型基线动画,减少模型光照效果,减少CPU负担。

   (经过反复挑选调试,我选择了 萨尔那加神器碎片1星灵高能瓦斯包 这两个模型,这两个模型视觉效果好,同时CPU占用少,播放比较流畅)

2、在地图上创建像素"点"和"区域",生成显示器 ↓↓↓
  1. for(i=0;i<60;i+=1){
  2.     for(j=0;j<80;j+=1){
  3.         x=70+1.5*j;
  4.         y=160-1.5*i;
  5.         k=80*i+j+1;
  6.         pt[k]=Point(x,y);
  7.         rg[k]=RegionCircle(pt[k],0.5);
  8.     }
  9. }
复制代码

3、初始化"显示器",在像素"点"和"区域"上创建以上新建的单位 ↓↓↓
  1. for(i=1;i<4801;i+=1){
  2.     UnitCreate(1, "Pixel2", 0, 1, pt[i], 270.0);
  3.     RegionAttachToUnit(rg[i], UnitLastCreated(), Point(0.0, 0.0));
  4. }
复制代码

4、导入编码表字符串 ↓↓↓
  1. p1[30]="1111111111111111111111111111111111111111111111111111111000000000000000000000000011111111111111111111111111111111111111111111111111111110000000000000000000000000111111111111111111111111111111111111111111111111111111000000000000000000000000001111111111111111111111111111111111111111111111111111110000000000000000000000000011111111111111111111111111111111111111111111111111111000000000000000000000000000111111111111111111111111111111111111111111111111111110000000000000000000000000001111111111111111111111111111111111111111111111111111000000000000000000000000000011111111111111111111111111111111111111111111111111100000000000000000000000000000111111111111111111111111111111111111111111111111111000000000000000000000000000001111111111111111111111111111111111111111111111111100000000000000000000000000000011111111111111111111111111111111111111111111111111000000000000000000000000000000111111111111111111111111111111111111111111111111100000000000000000000000000000001111111111111111111111111111111111111111111111110000000000000000000000000000000011111111111111111111111111111111111111111111111100000000000000000000000000000000111111111111111111111111111111111111111111111110000000000000000000000000000000001111111111111111111111111111111111111111111111100000000000000000000000000000000011111111111111111111111111111111111111111111111000000000000000000000000000000000111111111111111111111111111111111111111111111110000000000000000000000000000000001111111111111111111111111111111111111111111111100000000000000000000000000000000011111111111111111111111111111111111111111111111000000000000000000000000000000000";

  2. p2[30]="1111111111111111111111111111111111111111111111100000000000000000000000000000000011111111111111111111111111111111111111111111111111111110000000000000000000000000111111111111111111111111111111111111111111111111111111100000000000000000000000001111111111111111111111111111111111111111111111111111110000000000000000000000000011111111111111111111111111111111111111111111111111111000000000000000000000000000111111111111111111111111111111111111111111111111111110000000000000000000000000001111111111111111111111111111111111111111111111111111000000000000000000000000000011111111111111111111111111111111111111111111111111110000000000000000000000000000111111111111111111111111111111111111111111111111111110000000000000000000000000001111111111111111111111111111111111111111111111111111111000000000000000000000000011111111111111111111111111111111111111111111111111111111000000000000000000000000111111111111111111111111111111111111111111111111111111111100000000000000000000001111111111111111111111111111111111111111111111111111111111100000000000000000000011111111111111111111111111111111111111111111111111111111111110000000000000000000111111111111111111111111111111111111111111111111111111111111110000000000000000001111111111111111111111111111111111111111111111111111111111111110000000000000000011111111111111111111111111111111111111111111111111111111111111100000000000000000111111111111111111111111111111111111111111111111111111111111111100000000000000001111111111111111111111111111111111111111111111111111111111111111100000000000000011111111111111111111111111111111111111111111111111111111111111111000000000000000";

  3. p3[30]="1111111111111111111111111111111111111111111111111111111111111111110000000000000011111111111111111111111111111111111111111111111111111111111111111100000000000000111111111111111111111111111111111111111111111111111111111111111111000000000000001111111111111111111111111111111111111111111111111111111111111111110000000000000011111111111111111111111111111111111111111111111111111111111111111110000000000000111111111111111111111111111111111111111111111111111111111111111111100000000000001111111111111111111111111111111111111111111111111111111111111111111000000000000011111111111111111111111111111111111111111111111111111111111111111110000000000000111111111111111111111111111111111111111111111111111111111111111111100000000000001111111111111111111111111111111111111111111111111111111111111111111000000000000011111111111111111111111111111111111111111111111111111111111111111110000000000000111111111111111111111111111111111111111111111111111111111111111111000000000000001111111111111111111111111111111111111111111111111111111111111111110000000000000011111111111111111111111111111111111111111111111111111111111111111111000000000000111111111111111111111111111111111111111111111111111111111111111111111100000000001111111111111111111111111111111111111111111111111111111111111111111111100000000011111111111111111111111111111111111111111111111111111111111111111111111100000000111111111111111111111111111111111111111111111111111111111111111111111111100000001111111111111111111111111111111111111111111111111111111111111111111111111100000011111111111111111111111111111111111111111111111111111111111111111111111111100000";

  4. // 以第30帧的编码表字符串为例说明。完整的编码表有3504帧,其余帧的编码表字符串省略,不再一一列举。
  5. // 由于Galaxy字符串的长度限制为2045个字符,而每一帧有80*60=4800个"0/1"字符编码,所以设定每一个字符串存储每一帧1/3的字符编码,即1600个字符编码。
复制代码

5、使用 StringSub函数 遍历字符串,读取编码。
     根据编码进行逻辑判断,在"显示器"上使用 "显示/隐藏单位"函数 播放 Bad Apple!! ↓↓↓
  1. t1=0.0625;
  2. // 每一帧停留时间,其等于最小游戏周期,对应16帧的帧率,这是实现音画同步的关键。
  3. for(i=1;i<3505;i+=1){
  4.     for(j=1;j<1601;j+=1){
  5.         m=j+1600;
  6.         n=j+3200;
  7.         if(StringSub(p1[i],j,j)=="1"){
  8.             libNtve_gf_ShowHideUnit(RegionGetAttachUnit(rg[j]), false);
  9.         }
  10.         else{
  11.             libNtve_gf_ShowHideUnit(RegionGetAttachUnit(rg[j]), true);
  12.         }
  13.         if(StringSub(p2[i],j,j)=="1"){
  14.             libNtve_gf_ShowHideUnit(RegionGetAttachUnit(rg[m]), false);
  15.         }
  16.         else{
  17.             libNtve_gf_ShowHideUnit(RegionGetAttachUnit(rg[m]), true);
  18.         }
  19.         if(StringSub(p3[i],j,j)=="1"){
  20.             libNtve_gf_ShowHideUnit(RegionGetAttachUnit(rg[n]), false);
  21.         }
  22.         else{
  23.             libNtve_gf_ShowHideUnit(RegionGetAttachUnit(rg[n]), true);
  24.         }
  25.     }
  26.     Wait(t1, c_timeReal);
  27. }
复制代码
回复

使用道具 举报

 楼主| 发表于 2020-9-6 22:27:49 | 显示全部楼层
本帖最后由 枪兵打巨像 于 2020-10-19 18:51 编辑

编码表获取方法:

1、用PR或者AE把《Bad Apple!!》原版视频输出为图片序列。由于PR只支持常规帧率输出,不支持16帧的特殊帧率输出,所以以下以AE举例说明:

(1) 将视频拖入AE渲染轨道内,点击输出模式,输出格式选择"JPEG Sequence",分辨率设定为80*60(根据实际需要设定)↓↓↓

BA Code 002.jpg


(2) 点击渲染设置,将帧率设定为16(根据实际需要设定)↓↓↓

BA Code 001.jpg


(3) 设定图片序列命名规则,选择图片输出路径,最后点击"Render"输出图片序列 ↓↓↓

BA Code 004.jpg


(4) 输出的图片序列如下所示,按16帧的帧率,最终输出了3504张帧画面 ↓↓↓

BA Code 01.jpg


2、使用Matlab的 rgb2gray函数 处理图片序列,遍历每一张帧画面的所有像素点,获取像素点的灰度值,输出编码表。
     如果灰度值大于200,则输出"0",否则输出"1"。Matlab代码如下 ↓↓↓
  1. str='C:\\Picture queue\picture queue 4\BA';
  2. FID=fopen('C:\\Pixel\BA4.txt','a+');

  3. for i=1:10
  4.     I=imread([str,'000',num2str(i-1),'.jpg']);
  5.     I1=rgb2gray(I);
  6.     for i1=1:60
  7.        for i2=1:80
  8.            if(I1(i1,i2)>200)
  9.                fprintf(FID,'0 ');
  10.            else
  11.                fprintf(FID,'1 ');
  12.            end
  13.        end
  14.        fprintf(FID,'\r\n');
  15.    end
  16. end

  17. for i=11:100
  18.     I=imread([str,'00',num2str(i-1),'.jpg']);
  19.     I1=rgb2gray(I);
  20.     for i1=1:60
  21.        for i2=1:80
  22.            if(I1(i1,i2)>200)
  23.                fprintf(FID,'0 ');
  24.            else
  25.                fprintf(FID,'1 ');
  26.            end
  27.        end
  28.        fprintf(FID,'\r\n');
  29.    end
  30. end

  31. for i=101:1000
  32.     I=imread([str,'0',num2str(i-1),'.jpg']);
  33.     I1=rgb2gray(I);
  34.     for i1=1:60
  35.        for i2=1:80
  36.            if(I1(i1,i2)>200)
  37.                fprintf(FID,'0 ');
  38.            else
  39.                fprintf(FID,'1 ');
  40.            end
  41.        end
  42.        fprintf(FID,'\r\n');
  43.    end
  44. end

  45. for i=1001:3504
  46.     I=imread([str,num2str(i-1),'.jpg']);
  47.     I1=rgb2gray(I);
  48.     for i1=1:60
  49.        for i2=1:80
  50.            if(I1(i1,i2)>200)
  51.                fprintf(FID,'0 ');
  52.            else
  53.                fprintf(FID,'1 ');
  54.            end
  55.        end
  56.        fprintf(FID,'\r\n');
  57.    end
  58. end

  59. sta=fclose(FID);
复制代码


3、Matlab输出的文本格式编码表 ↓↓↓

BA Code 03.jpg


4、将文本格式的编码表导入Excel,进行后续处理 ↓↓↓

BA Code 04.jpg


5、使用Excel VBA将编码表转化为Galaxy字符串。
     由于Galaxy字符串的长度限制为2045个字符,而每一帧有80*60=4800个"0/1"字符编码,所以设定每一个字符串存储每一帧1/3的字符编码,即1600个字符编码。
     Excel VBA代码如下 ↓↓↓
  1. Sub GalaxyPixel()

  2. Dim i As Long
  3. Dim j As Long
  4. Dim k As Long
  5. Dim n1 As Long
  6. Dim n2 As Long
  7. Dim n3 As Long
  8. Dim Pixel As Long
  9. Dim PixelArray As String

  10. For k = 1 To 3504
  11.     PixelArray = ""
  12.     For i = 1 To 20
  13.         For j = 1 To 80
  14.                 n1 = 3 * k - 2
  15.                 Pixel = Sheet1.Cells((k - 1) * 60 + i, j)
  16.                 PixelArray = PixelArray & Pixel
  17.         Next j
  18.     Next i
  19.     Sheet3.Cells(n1, 1) = "p1[" & k & "]=""" & PixelArray & """;"
  20. Next k

  21. For k = 1 To 3504
  22.     PixelArray = ""
  23.     For i = 21 To 40
  24.         For j = 1 To 80
  25.                 n2 = 3 * k - 1
  26.                 Pixel = Sheet1.Cells((k - 1) * 60 + i, j)
  27.                 PixelArray = PixelArray & Pixel  
  28.         Next j
  29.     Next i
  30.     Sheet3.Cells(n2, 1) = "p2[" & k & "]=""" & PixelArray & """;"
  31. Next k

  32. For k = 1 To 3504
  33.     PixelArray = ""
  34.     For i = 41 To 60
  35.         For j = 1 To 80
  36.                 n3 = 3 * k
  37.                 Pixel = Sheet1.Cells((k - 1) * 60 + i, j)
  38.                 PixelArray = PixelArray & Pixel
  39.         Next j
  40.     Next i
  41.     Sheet3.Cells(n3, 1) = "p3[" & k & "]=""" & PixelArray & """;"
  42. Next k

  43. End Sub
复制代码


6、Excel VBA输出的Galaxy字符串,可以直接复制到Galaxy编辑器中使用 ↓↓↓

BA Code 06.jpg
回复

使用道具 举报

 楼主| 发表于 2020-9-7 01:19:54 | 显示全部楼层
本帖最后由 枪兵打巨像 于 2020-10-20 00:08 编辑

StringSub函数的用法:

1、StringSub函数 是 Native.galaxy 函数库中的一个本地函数,可以在星际争霸2编辑器中直接使用。
     函数功能:按照字符开始到字符结束的计数抽取一个子字符串。
     函数在 Native.galaxy 中的描述为:
  1. native string   StringSub (string s, int start, int end);
复制代码

2、参数描述:
参数
描述
数据类型
string s
目标字符串
字符串
int start
子字符串起始指针
整型
int end
子字符串结束指针
整型
返回值         
子字符串
字符串              

3、用法示例:
输入
返回值
StringSub ("abcdefg", 1, 1) "a"
StringSub ("abcdefg", 1, 3) "abc"
StringSub ("abcdefg", 4, 7) "defg"                           

4、注意事项:
     StringSub函数 存在 赋值次数 的限制,具体数值是 59546 次,超过这个限制就会溢出。但是,函数不存在 执行次数 的限制。以下举例说明:
      (1) 会出现溢出的代码,说明函数存在 赋值次数 的限制:
  1. for(i=1;i<2798;i+=1){
  2.     for(j=1;j<433;j+=1){
  3.         px[i][j]=StringSub(p[i],j,j);
  4.     }
  5. }
复制代码

     (2) 不会出现溢出的代码1,说明函数不存在 执行次数 的限制:
  1. for(i=1;i<2798;i+=1){
  2.     for(j=1;j<433;j+=1){
  3.         StringSub(p[i],j,j);
  4.     }
  5. }
复制代码

     (3) 不会出现溢出的代码2,说明函数不存在 返回值逻辑判断次数 的限制:
  1. //--------------------------------------------------------------------------------
  2. // 使用 StringSub函数 遍历字符串,读取编码。
  3. // 根据编码进行逻辑判断,在"显示器"上使用 "显示/隐藏单位"函数 播放 Bad Apple!!
  4. //--------------------------------------------------------------------------------
  5. t1=0.0625;
  6. for(i=1;i<3505;i+=1){
  7.     for(j=1;j<1601;j+=1){
  8.         if(StringSub(p1[i],j,j)=="1"){
  9.             libNtve_gf_ShowHideUnit(RegionGetAttachUnit(rg[j]), false);
  10.         }
  11.         else{
  12.             libNtve_gf_ShowHideUnit(RegionGetAttachUnit(rg[j]), true);
  13.         }
  14.     Wait(t1, c_timeReal);
  15. }
复制代码

5、函数点评:
     相比 C语言Galaxy 的字符串处理函数比较薄弱。C语言可以通过 strncpy函数 直接提取字符串中的指定字符,而Galaxy只能通过 StringSub函数 提取子字符串的方式间接实现。这也和Galaxy中没有 字符 这一数据类型有关。


回复

使用道具 举报

 楼主| 发表于 2020-9-7 01:20:29 | 显示全部楼层
本帖最后由 枪兵打巨像 于 2020-10-19 18:34 编辑

全局内存上限问题:

      在导入编码表的过程中,还出现了 无法分配全局内存 的错误。当编译到 第3441帧 时,编码表的占用的内存按纯文本计算达到了 16.1MB,这超过了Galaxy的限制,于是出现了这个错误。后来我通过空白帧替代,以及局部减帧的妥协办法压缩编码,才将编码表占用的内存勉强减小到了16.1MB以内,解决了这个问题。

      这个问题也说明了 字符串导入算法 的潜力已经被榨干了,80×60 的分辨率已经达到了的极限,没有提高的空间了。

      如果要进一步提高分辨率,需要开发新的编码表导入算法。现在我已经有思路了,连续区域统一编码算法 可以担此重任。在 Bad Apple!! 中,大部分黑/白区域都是连续的,连续区域可以只用 1 个"0"或者"1"来统一编码,而不是和之前一样,每一个像素独立编码。

      连续区域统一编码算法 可以大幅压缩编码,提高分辨率。当前视频只占用了地图20%的面积,如果使用新算法,预计可以把 整张地图 都铺满。到了这个时候,瓶颈就不是编码了,而是星际2的地图面积限制(256×256)和CPU性能。

BA Error 01.jpg

回复

使用道具 举报

发表于 2020-9-7 16:22:05 | 显示全部楼层
枪兵打巨像 发表于 2020-9-6 22:27
编码表获取方法:

1、用PR或者AE把《Bad Apple!!》原版视频输出为图片序列。由于PR只支持常规帧率输出, ...

感谢分享!!!
回复

使用道具 举报

发表于 2020-9-7 18:20:19 | 显示全部楼层
不错,画质改进很多。
回复

使用道具 举报

发表于 2020-9-7 18:30:57 | 显示全部楼层
顺便,你以前是用替换单位来做显示和隐藏。但是替换单位的本质是删除和创建单位,如果改成显示隐藏单位的话,或许效率会更高一点。
回复

使用道具 举报

 楼主| 发表于 2020-9-7 22:37:12 | 显示全部楼层
yxxiaobin 发表于 2020-9-7 18:30
顺便,你以前是用替换单位来做显示和隐藏。但是替换单位的本质是删除和创建单位,如果改成显示隐藏单位的话 ...

现在我用的就是显示/隐藏单位。替换单位我试过,在高分辨率下根本用不了,电脑卡爆了。
回复

使用道具 举报

发表于 2020-10-14 13:25:31 | 显示全部楼层
厉害啊。。。。。。。。。。。。
回复

使用道具 举报

发表于 2020-10-14 20:26:13 | 显示全部楼层
大佬 原来是你做的啊

点评

"原来"你在哪里看过呢?(* ̄(エ) ̄)  详情 回复 发表于 2020-10-18 23:25
回复

使用道具 举报

 楼主| 发表于 2020-10-18 23:25:03 | 显示全部楼层
Prinny 发表于 2020-10-14 20:26
大佬 原来是你做的啊

"原来"你在哪里看过呢?(* ̄(エ) ̄)

点评

在大厅里找图玩的时候,点进去了...然后就播放你这个..动画 我还想着以后星际2可以看MV了  详情 回复 发表于 2020-11-8 22:03
回复

使用道具 举报

发表于 2020-11-8 22:03:39 | 显示全部楼层
本帖最后由 Prinny 于 2021-8-13 04:34 编辑
枪兵打巨像 发表于 2020-10-18 23:25
"原来"你在哪里看过呢?(* ̄(エ) ̄)

在大厅里找图玩的时候,点进去了...然后就播放你这个..
回复

使用道具 举报

发表于 2020-11-8 22:05:26 | 显示全部楼层
本帖最后由 Prinny 于 2021-8-13 04:33 编辑

大佬有什么先进的技术 给我这个萌新的地图一点支持啊 我图名字叫重装机兵[MetalMax]
里面的很多东西都是吸取论坛的技术做出来的

点评

我也是刚开始学,没啥先进技术,都是现学现卖的 ╮( ̄▽ ̄)╭  详情 回复 发表于 2021-1-20 21:18
回复

使用道具 举报

发表于 2020-12-8 17:06:41 | 显示全部楼层
b站过来的,太强了
回复

使用道具 举报

 楼主| 发表于 2021-1-20 21:18:23 | 显示全部楼层
Prinny 发表于 2020-11-8 22:05
大佬有什么先进的技术 给我这个萌新的地图一点支持啊 我图名字叫重装机兵[MetalMax]
里面的很多东西都是吸 ...

我也是刚开始学,没啥先进技术,都是现学现卖的 ╮( ̄▽ ̄)╭
回复

使用道具 举报

发表于 2021-1-28 10:54:37 | 显示全部楼层
本帖最后由 Nostalie 于 2021-1-28 11:38 编辑

最新版可以的,比初版好多了。。。
虽然我的3070最低只有20多帧。估计垃圾配置的人看这个够呛。

点评

由于是单核争霸,所以吃CPU不吃显卡。运行的时候可以开任务管理器看一下,3070使用率应该不是满的,我的1650都没到100%,但是CPU爆炸了  详情 回复 发表于 2021-1-29 00:28
你在战网上看到46帧的最新版了吗?把画质调到 "中" 或 "低" 会流畅很多  详情 回复 发表于 2021-1-29 00:26
回复

使用道具 举报

 楼主| 发表于 2021-1-29 00:26:24 | 显示全部楼层
Nostalie 发表于 2021-1-28 10:54
最新版可以的,比初版好多了。。。
虽然我的3070最低只有20多帧。估计垃圾配置的人看这个够呛。

你在战网上看到46帧的最新版了吗?把画质调到 "中" 或 "低" 会流畅很多
回复

使用道具 举报

 楼主| 发表于 2021-1-29 00:28:26 | 显示全部楼层
Nostalie 发表于 2021-1-28 10:54
最新版可以的,比初版好多了。。。
虽然我的3070最低只有20多帧。估计垃圾配置的人看这个够呛。

由于是单核争霸,所以吃CPU不吃显卡。运行的时候可以开任务管理器看一下,3070使用率应该不是满的,我的1650都没到100%,但是CPU爆炸了
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 点一下

本版积分规则

Archiver|移动端|小黑屋|地精研究院

GMT+8, 2024-4-24 06:15 , Processed in 0.185831 second(s), 33 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表