![2f57165385074de8205ea4f54f54bc1b.png](https://img-blog.csdnimg.cn/img_convert/2f57165385074de8205ea4f54f54bc1b.png)
论我要在HP39GS计算器上弄3D图像程序的动机:无聊。
在一个无聊的下午,我在刷视频的时候偶然看见了有关讲述透视投影的原理。我看了看公式,又看了看我的计算器,我一个大胆的念头油然而生:我是不是可以在计算器上做一个3D引擎呢?
没错,我大胆的想法驱使着我研究这个东西,不过,我在网上搜了一堆有关透视投影的公式,我仍然没有看得明白(我不懂矩阵运算,现在也一样。。。)
不过我还是硬着头皮弄了下去。。。
歪门邪道的想法
hohoho,现在回想起来还真是有点 哈子噶系 ,说到底,要是论当时我为了做出一个三维变换到底弄了些什么幺蛾子,那就有点意思了。
起初,我受到了以前一个像素游戏 《德军总部3D》 的启发,然后想着能不能先做一个可以除开俯视和仰视功能的3d变换程序出来,然后。。。当时因为是在高中,我看着一个幂函数有点眼熟,然后就把这个公式当作中心点进行设计。
幂函数法:通过幂函数对应的x与y值来实现一个视野旋转的效果
当然,这么搞,不仅是内行人,连外行人可能也会说我脑子有点不灵通
对数函数法。。。。。算了,这个就不说了吧
。。。后来有那么一次,我不知道我是哪个值改对了,计算器在显示平面的时候异常得可以,不过很可惜,它也就只能上下前后移动,没有左右,很快就被我淘汰掉了;
PS:当时我知道3D变换确实是由相似三角形和向量知识结合而成,只怪我当时学艺不精,哎。
偶然的一次设计成功(也不能算成功吧):
当我在学到向量与角度的关系时,我又有了新的想法:用判断向量与向量之间的夹角的方式能不能做到透视变换的效果呢?
答案是:一开始是不可以的。
原因很简单,我第一个想法就是用基于坐标轴上,在相机的左方,上方与前方分别放置一个向量,三个向量同时判断顶点在相机的方位,但是问题也很明显,性能损耗太大,算一个向量已经够hp39gs喝一壶的了,再加上39GS原有的hpbasic语言的编译仅仅只是编译到汇编语言中,那慢得。。。也是可想而知。后来我去除掉了上方和右方的向量,改为前方测定顶点与向量的夹角,高度差则由顶点高度减去相机高度,再乘以一个可变因数,然后,一个伪三维变换的程序出生了!
但是,角度计算。。。它计算的只有正角,没有负角。这也意味着,如果我把用于判断夹角的向量放在正前方,那么它所得到的结果就是,(当时用的画线,画线的x和y是基于FUNCTION的PLOT面板定义的)在y轴右边,呈现的是正确的图像,而在y轴左边,呈现的则是镜像,那我一定不能忍,然后就把PLOT的中心点从(0,0)改为了(6,3),也就是把y轴左边的内容遮挡住,那么呈现的内容就没有问题了。
我消不了你,我不看还不行吗。
后来,在某一次39gs断电清数据后,我的心态差点就炸开了,因为我还没备份。。。
过了一段自闭期后,我又重新会想起之前的透视变换程序,我想到了之前写的好像功能并不完善,于是我又重振旗鼓再一次开始了,两天过后,一个近代的透视投影程序出现了,它的名字叫3DViewPort(Viewport的取名源于虚幻4引擎的viewport函数)它相比于上一次的程序,它变得功能多了,那时,我也接触到了grob(hp39gs里面的一种graphic类型的已定义变量,从G0-G9总共有10帧)这个东西,说它好,是真的好,得益于它还不错的图像回放速度,我用它一并整合进3DViewPort内作为图像录制的工具,这也是衍生程序graphplayer(我写这个基本上是为了回放3DViewPort录制进grob的内容)的出现。
那一次,我有了前车之鉴,立马做了个备份。然后它就一直在我的备份里面和计算器里面躺着了。
3DViewPort
一个不合群的三维变换软件
总共分有3个功能:相机放置区,物体编辑区,3D视野构造面板
相机放置区:仅用于移动相机用的面板,同时也是动画录制的地方
物体编辑区:功能有创建物体,选择物体,物体位移,物体顶点编辑(这个最后还是没弄好),物体移除,复制和保存
问题:3D变换不精确;在x轴隐隐约约的有鱼眼的效果;y轴倒是不会;而且无法俯仰;物体编辑时,如果不小心按错其它键,那就要再等它加载一次物体数据;由于我在里面使用了距离公式的问题,当相机xz点与顶点xz重合时会报错Bad Argument Type,所以我一般在放置相机时尽量确保相机与物体顶点有一定的距离。。。
本人对这种妥协感到强烈的不满意,于是新的3d变换公式就要出现了
论重制后的“3DViewPort”-PLOT3D的来由
实际上,这个也不能说是3dviewport的更新版了,因为,它的3d引擎与它的一切功能都被重新设计了,3DViewPort完全不能和我最近写的PLOT3D沾的上什么边。
新的PLOT3D相比我之前写的3DViewPort有什么区别呢?
说实话,哪几天,有关向量的知识可能算是我想得最多的了吧,我已经不记得我这个学渣为了这个简单的公式画了多少个三角形,也不知道我到底弄了多少公式。。。
当时唯一不明白的问题就是。。。如何将世界坐标转换到相机相关的本地坐标?
起初,我在用UNITY开发游戏的时候偶然遇见了向量Vector3里面的Vector3.Dot( Vector3,Vector3)与Cross,也就是点乘和叉乘(网上有一篇文章说的是这两者搭配可以达到判断物体在向量前后左右的效果),我也同时发现了,我在Unity进行游戏人物在不同方位的脚步的正常运动方向可以通过这两个函数来完成操作,我就试着用草稿本算了一下,等写到计算器后,数值与自己想的相差了很多,而且非常离谱,我突然又郁闷起来了。。。不过,过了一会,我发现:如果想要得到顶点在相机前方的本地坐标,只要让顶点坐标乘以相机前方的单位向量即可!
即设顶点p(x,y,z),相机单位向量C(x1,y1,z1)
这两个这么一乘 p*C=x*x1+y*y1+z*z1=结果
顶点相对于相机的本地坐标就出来了
这一发现最终成为了PLOT3D诞生的源头,我一开始写的PLOT3D测试版并不叫本名,而是叫“VectorTest”,也就是向量测试,整个三维变换是由向量组成的。故以此命名
后来过了那么两天,完整的透视变换最终出现在了我的笔记本上
![2655256107bb83a0c7fcf1272ae4d44f.png](https://img-blog.csdnimg.cn/img_convert/2655256107bb83a0c7fcf1272ae4d44f.png)
整个推导式的话,唯一不足就是fov没法正常求到,我只能用相关符号进行标记
与此同时,我也发现了,当把笔记中的zDepth改为1时,视角会变成正交投影视角。
有了这些
我最终用了一个星期把这个东西做出来了。
PLOT3D的功能
知乎视频www.zhihu.com这次的PLOT3D由之前的三面板变成了双面板(三维变换面板)(物体与相机的操作面板)
而且,物体的编辑相比3DViewPort要更加有效率的多
举个例子:PLOT3D是矩阵型顶点编辑,之间把顶点列出来以供修改,而3DViewPort是指定一个顶点,编辑一个顶点,两者耗费的时间可想而知。
由于hp39gs在程序上的硬性限制,我没法将全部的功能都写在一个程序中。。。
于是,分模块出现了
程序包含4个模块:
1.PLOT3D(主程序)
2.grobwritter(9帧动画录制模块,会在3d模式且开启了录制的情况下运行)
3.slotfun(一个可扩展的后处理程序,会在3d模式的透视视角下运行)
4.graphplayer(当录制完后可以使用它播放动画,注意,它会使用你的计算器里面G1到G9的grob图像数据,与grobwritter一样)
(PS:顺带一提,贴心的我为了防止使用者随便打开里面的任意一个程序造成一些不痛不痒的问题,我顺便加了主程序未打开,模块不能被打开的温馨提示)
目前,这个slotfun程序还未完成,我会在此之后完善,当然,你也可以自己写。。。
相机的变换(透视投影与正交投影)
PS:整个坐标轴的定义是按照Unity的y轴为上,x轴为右,z轴为前进行定义
标题的配图中的场景是我专门为了测试它的3d变换的可行性而手动构造的,旨在让观者看出透视投影与正交投影的区别
这是透视投影视角下的场景
![66b7aa3064fe4a3707488d9c267cf9de.png](https://img-blog.csdnimg.cn/img_convert/66b7aa3064fe4a3707488d9c267cf9de.png)
这是正交投影下的场景
![08b73ca46eb158f2021845790896b279.png](https://img-blog.csdnimg.cn/img_convert/08b73ca46eb158f2021845790896b279.png)
两者的视角均没有发生变化
后话
总之,程序,终究是有待开发的东西,以后我希望还能再加入一些更加好的功能。。。当然,如果你手上刚好有一台Hp39gs,也对我所设计的程序感到兴趣的话,欢迎你下载我的程序
(目前的bug与不足:
1.在特定情况下,可能会发生bad argument问题,但极少,可以忽略
2.3d视角下,在物体跨越相机后可能会出现显示异常的问题,这是我的算法问题,但是没办法,我没法在有限的性能内再加入一个性能耗费颇高的物体渲染功能
3.由于39gs的尿性,每秒只能运算1-2个顶点。)