【算法】在文曲星平台上,用gvmaker实现3D场景渲染!(附:文曲星GVMaker开发环境下载,GVMaker模拟器下载,源码下载)
注:本文所指的“文曲星”是“文曲星A2008”机型。。文曲星不支持浮点数运算,而且运行也十分缓慢——其实不是文曲星慢,而是它上面运行的gvmaker虚拟机太慢了。所以我使用定点数来代替浮点数进行运算。
所谓定点数,就是小数点位置被固定到指定位置的一种数据类型,比如我存储1.0,对于定点数,我把小数点固定在第10位,那么我实际存储的数值就是0x400(十进制1024)。这样的话,我的定点数的精度,最低也是1/1024。
定点数的加减法和整数无异,直接+ - 就好。但乘除法的话,如果你用一个定点数去乘一个定点数,并且你直接用的是整数的乘法的处理方式的话,你需要把得到的积再除以定点数表示的1.0,你才能得到正确的结果。比如你的定点数1.0用整数方式存储是1024的话,为了得到2.0 * 2.0 = 4.0的效果,你实际做的整数乘法是2048 * 2048,得到的是4194304,你需要再除以1024(也就是你的定点数的1.0),你才能得到4096。同理除法也需要经过这样的处理,只不过除法是先让被除数乘上定点数1.0,再除以除数。比如1.0 / 2.0 = 0.5,用定点数做运算的话,就是1024 * 1024 / 2048 = 512。
和浮点数做对比,定点数运算比较快,并且它的精度是可控的——因为浮点数的小数点位置是浮动的,它的精度与数值的大小有密切的关系,所以用定点数能保证精度的统一,而浮点数则不能。
但定点数的缺点在于做乘除法的时候,会严重地损失精度,尤其是圆周率,32位浮点数能存储3.1415927,而定点数假设小数点在第10位,那么它只能用 3216 来表示圆周率(3216 = π×1024 取整)。而如果我把小数点放在第16位的位置上(1.0用65536表示)的话,我虽然能精确到1/65536,但我能存储的最大的数值也从之前的4294966272变成了65536,而且我每次做乘除法的时候,我都要用一个64位的整数来存储中间值,这会严重降低运算的效率(然而x86平台还好)。
有关3D渲染的算法,其实就是很简单的矩阵变换和投影,其它并没有什么玄妙。顺带一提,很多人以为用了DirectX或者OpenGL才能算真3D,但其实3D渲染的“真伪”只取决于你用的算法,和你使用的媒介无关。事实上就算你用的是正交投影,某种程度上也算是“真3D”的。我之前就写过一篇帖子,讲如何用VB自带的Line进行3D画面的绘制的。
文曲星运行用户程序,用的是一款叫“gvmaker”的开发环境,和它的启动器。这里放出下载:
gvmaker开发环境:
文曲星端的gvmaker启动器:
源码:(320x240,64K色)
#define FIXED 1024
#define FIXED_SHIFT 10
#define MSTACK_SIZE 16 // 矩阵栈的大小
#define VP_WIDTH 320
#define VP_HEIGHT 240
#define VP_CENTERX 160
#define VP_CENTERY 120
#define VP_RIGHT 319
#define VP_BOTTOM 239
// 触屏判断
struct point
{
int x;
int y;
};
struct point pt;
struct point pt_old;
//向量
struct vec3
{
long x,y,z;
};
struct vec4
{
long x,y,z,w;
};
// 矩阵
struct mat4
{
struct vec4 x,y,z,w;
};
// 矩阵栈
struct mat4 m_stack;
int m_stacktop; // 栈顶
struct mat4 m; // 临时矩阵(gvmaker不能把结构体变量作为局部变量定义)
struct mat4 m_modelview; // 模型矩阵
struct mat4 m_projection; // 投影矩阵
struct vec3 eye_pos; // 眼睛位置
long eye_yaw, eye_pitch; // 眼睛角度
struct vec3 eye_xaxis; // 眼睛右方向
struct vec3 eye_yaxis; // 眼睛上方向
struct vec3 eye_zaxis; // 眼睛前方向
long time_global; // 全局时间
long time_delta; // 帧时间
void mat_init();
void mat_push();
void mat_pop();
void mat_mult();
void mat_transpose();
void mat_load_identity();
void mat_load_RotXAxis(long deg);
void mat_load_RotYAxis(long deg);
void mat_load_RotZAxis(long deg);
void mat_load_RotAxis(long ax, long ay, long az, long deg);
void mat_load_EulerRotation(long yaw, long pitch, long roll);
void mat_load_view_lh(long x, long y, long z, long yaw, long pitch, long roll);
void mat_load_perspective_lh(long fovy, long aspect, long zn, long zf);
void mat_load_modelview();
void mat_load_projection();
void mat_set_modelview();
void mat_set_projection();
void mat_print(int x, int y);
long tan(long deg)
{
return (sin(deg) << FIXED_SHIFT) / cos(deg);
}
long cot(long deg)
{
return (cos(deg) << FIXED_SHIFT) / sin(deg);
}
// 初始化矩阵栈
void mat_init()
{
m_stacktop = 0;
mat_load_identity();
}
// 压入新矩阵
void mat_push()
{
m_stacktop = (m_stacktop + 1) % MSTACK_SIZE;
}
// 压入栈顶
void mat_pushtop()
{
int prev;
prev = m_stacktop;
m_stacktop = (m_stacktop + 1) % MSTACK_SIZE;
memcpy(&m_stack.x.x, &m_stack.x.x, 64);
}
// 弹出矩阵
void mat_pop()
{
m_stacktop = m_stacktop - 1;
if(m_stacktop < 0)
m_stacktop = m_stacktop + MSTACK_SIZE;
}
// 将栈顶两个矩阵做矩阵乘法
void mat_mult()
{
long ptr2;
ptr2 = m_stacktop;
mat_pop();
m.x.x = (m_stack.x.x * m_stack.x.x >> FIXED_SHIFT) + (m_stack.x.y * m_stack.y.x >> FIXED_SHIFT) + (m_stack.x.z * m_stack.z.x >> FIXED_SHIFT) + (m_stack.x.w * m_stack.w.x >> FIXED_SHIFT);
m.x.y = (m_stack.x.x * m_stack.x.y >> FIXED_SHIFT) + (m_stack.x.y * m_stack.y.y >> FIXED_SHIFT) + (m_stack.x.z * m_stack.z.y >> FIXED_SHIFT) + (m_stack.x.w * m_stack.w.y >> FIXED_SHIFT);
m.x.z = (m_stack.x.x * m_stack.x.z >> FIXED_SHIFT) + (m_stack.x.y * m_stack.y.z >> FIXED_SHIFT) + (m_stack.x.z * m_stack.z.z >> FIXED_SHIFT) + (m_stack.x.w * m_stack.w.z >> FIXED_SHIFT);
m.x.w = (m_stack.x.x * m_stack.x.w >> FIXED_SHIFT) + (m_stack.x.y * m_stack.y.w >> FIXED_SHIFT) + (m_stack.x.z * m_stack.z.w >> FIXED_SHIFT) + (m_stack.x.w * m_stack.w.w >> FIXED_SHIFT);
m.y.x = (m_stack.y.x * m_stack.x.x >> FIXED_SHIFT) + (m_stack.y.y * m_stack.y.x >> FIXED_SHIFT) + (m_stack.y.z * m_stack.z.x >> FIXED_SHIFT) + (m_stack.y.w * m_stack.w.x >> FIXED_SHIFT);
m.y.y = (m_stack.y.x * m_stack.x.y >> FIXED_SHIFT) + (m_stack.y.y * m_stack.y.y >> FIXED_SHIFT) + (m_stack.y.z * m_stack.z.y >> FIXED_SHIFT) + (m_stack.y.w * m_stack.w.y >> FIXED_SHIFT);
m.y.z = (m_stack.y.x * m_stack.x.z >> FIXED_SHIFT) + (m_stack.y.y * m_stack.y.z >> FIXED_SHIFT) + (m_stack.y.z * m_stack.z.z >> FIXED_SHIFT) + (m_stack.y.w * m_stack.w.z >> FIXED_SHIFT);
m.y.w = (m_stack.y.x * m_stack.x.w >> FIXED_SHIFT) + (m_stack.y.y * m_stack.y.w >> FIXED_SHIFT) + (m_stack.y.z * m_stack.z.w >> FIXED_SHIFT) + (m_stack.y.w * m_stack.w.w >> FIXED_SHIFT);
m.z.x = (m_stack.z.x * m_stack.x.x >> FIXED_SHIFT) + (m_stack.z.y * m_stack.y.x >> FIXED_SHIFT) + (m_stack.z.z * m_stack.z.x >> FIXED_SHIFT) + (m_stack.z.w * m_stack.w.x >> FIXED_SHIFT);
m.z.y = (m_stack.z.x * m_stack.x.y >> FIXED_SHIFT) + (m_stack.z.y * m_stack.y.y >> FIXED_SHIFT) + (m_stack.z.z * m_stack.z.y >> FIXED_SHIFT) + (m_stack.z.w * m_stack.w.y >> FIXED_SHIFT);
m.z.z = (m_stack.z.x * m_stack.x.z >> FIXED_SHIFT) + (m_stack.z.y * m_stack.y.z >> FIXED_SHIFT) + (m_stack.z.z * m_stack.z.z >> FIXED_SHIFT) + (m_stack.z.w * m_stack.w.z >> FIXED_SHIFT);
m.z.w = (m_stack.z.x * m_stack.x.w >> FIXED_SHIFT) + (m_stack.z.y * m_stack.y.w >> FIXED_SHIFT) + (m_stack.z.z * m_stack.z.w >> FIXED_SHIFT) + (m_stack.z.w * m_stack.w.w >> FIXED_SHIFT);
m.w.x = (m_stack.w.x * m_stack.x.x >> FIXED_SHIFT) + (m_stack.w.y * m_stack.y.x >> FIXED_SHIFT) + (m_stack.w.z * m_stack.z.x >> FIXED_SHIFT) + (m_stack.w.w * m_stack.w.x >> FIXED_SHIFT);
m.w.y = (m_stack.w.x * m_stack.x.y >> FIXED_SHIFT) + (m_stack.w.y * m_stack.y.y >> FIXED_SHIFT) + (m_stack.w.z * m_stack.z.y >> FIXED_SHIFT) + (m_stack.w.w * m_stack.w.y >> FIXED_SHIFT);
m.w.z = (m_stack.w.x * m_stack.x.z >> FIXED_SHIFT) + (m_stack.w.y * m_stack.y.z >> FIXED_SHIFT) + (m_stack.w.z * m_stack.z.z >> FIXED_SHIFT) + (m_stack.w.w * m_stack.w.z >> FIXED_SHIFT);
m.w.w = (m_stack.w.x * m_stack.x.w >> FIXED_SHIFT) + (m_stack.w.y * m_stack.y.w >> FIXED_SHIFT) + (m_stack.w.z * m_stack.z.w >> FIXED_SHIFT) + (m_stack.w.w * m_stack.w.w >> FIXED_SHIFT);
memcpy(&m_stack.x.x, &m.x.x, 64);
}
// 矩阵转置
void mat_transpose()
{
long t;
t = m_stack.x.y;
m_stack.x.y = m_stack.y.x;
m_stack.y.x = t;
t = m_stack.x.z;
m_stack.x.z = m_stack.z.x;
m_stack.z.x = t;
t = m_stack.x.w;
m_stack.x.w = m_stack.w.x;
m_stack.w.x = t;
t = m_stack.y.z;
m_stack.y.z = m_stack.z.y;
m_stack.z.y = t;
t = m_stack.y.w;
m_stack.y.w = m_stack.w.y;
m_stack.w.y = t;
t = m_stack.z.w;
m_stack.z.w = m_stack.w.z;
m_stack.w.z = t;
}
// 载入单位矩阵
void mat_load_identity()
{
m_stack.x.x=FIXED;m_stack.x.y=0;m_stack.x.z=0;m_stack.x.w=0;
m_stack.y.y=FIXED;m_stack.y.x=0;m_stack.y.z=0;m_stack.y.w=0;
m_stack.z.z=FIXED;m_stack.z.x=0;m_stack.z.y=0;m_stack.z.w=0;
m_stack.w.w=FIXED;m_stack.w.x=0;m_stack.w.y=0;m_stack.w.z=0;
}
// 载入平移矩阵
void mat_load_translate(long x, long y, long z)
{
m_stack.x.x=FIXED;m_stack.x.y=0;m_stack.x.z=0;m_stack.x.w=0;
m_stack.y.y=FIXED;m_stack.y.x=0;m_stack.y.z=0;m_stack.y.w=0;
m_stack.z.z=FIXED;m_stack.z.x=0;m_stack.z.y=0;m_stack.z.w=0;
m_stack.w.w=FIXED;m_stack.w.x=x;m_stack.w.y=y;m_stack.w.z=z;
}
// 载入绕X轴旋转矩阵
void mat_load_RotXAxis(long deg)
{
m_stack.x.x = FIXED;
m_stack.x.y = 0;
m_stack.x.z = 0;
m_stack.x.w = 0;
m_stack.y.x = 0;
m_stack.y.y = cos(deg);
m_stack.y.z =-sin(deg);
m_stack.y.w = 0;
m_stack.z.x = 0;
m_stack.z.y = sin(deg);
m_stack.z.z = cos(deg);
m_stack.z.w = 0;
m_stack.w.x = 0;
m_stack.w.y = 0;
m_stack.w.z = 0;
m_stack.w.w = FIXED;
}
// 载入绕Y轴旋转矩阵
void mat_load_RotYAxis(long deg)
{
m_stack.x.x = cos(deg);
m_stack.x.y = 0;
m_stack.x.z = sin(deg);
m_stack.x.w = 0;
m_stack.y.x = 0;
m_stack.y.y = FIXED;
m_stack.y.z = 0;
m_stack.y.w = 0;
m_stack.z.x =-sin(deg);
m_stack.z.y = 0;
m_stack.z.z = cos(deg);
m_stack.z.w = 0;
m_stack.w.x = 0;
m_stack.w.y = 0;
m_stack.w.z = 0;
m_stack.w.w = FIXED;
}
// 载入绕Z轴旋转矩阵
void mat_load_RotZAxis(long deg)
{
m_stack.x.x = cos(deg);
m_stack.x.y = sin(deg);
m_stack.x.z = 0;
m_stack.x.w = 0;
m_stack.y.x =-sin(deg);
m_stack.y.y = cos(deg);
m_stack.y.z = 0;
m_stack.y.w = 0;
m_stack.z.x = 0;
m_stack.z.y = 0;
m_stack.z.z = FIXED;
m_stack.z.w = 0;
m_stack.w.x = 0;
m_stack.w.y = 0;
m_stack.w.z = 0;
m_stack.w.w = FIXED;
}
// 载入绕轴旋转矩阵
void mat_load_RotAxis(long ax, long ay, long az, long deg)
{
m_stack.x.x = (((FIXED - cos(deg)) * ax >> FIXED_SHIFT) * ax >> FIXED_SHIFT) + cos(deg);
m_stack.x.y = (((FIXED - cos(deg)) * ax >> FIXED_SHIFT) * ay >> FIXED_SHIFT) - sin(deg) * az >> FIXED_SHIFT;
m_stack.x.z = (((FIXED - cos(deg)) * ax >> FIXED_SHIFT) * az >> FIXED_SHIFT) + sin(deg) * ay >> FIXED_SHIFT;
m_stack.x.w = 0;
m_stack.y.x = (((FIXED - cos(deg)) * ay >> FIXED_SHIFT) * ax >> FIXED_SHIFT) + sin(deg) * az >> FIXED_SHIFT;
m_stack.y.y = (((FIXED - cos(deg)) * ay >> FIXED_SHIFT) * ay >> FIXED_SHIFT) + cos(deg);
m_stack.y.z = (((FIXED - cos(deg)) * ay >> FIXED_SHIFT) * az >> FIXED_SHIFT) - sin(deg) * ax >> FIXED_SHIFT;
m_stack.y.w = 0;
m_stack.z.x = (((FIXED - cos(deg)) * az >> FIXED_SHIFT) * ax >> FIXED_SHIFT) - sin(deg) * ay >> FIXED_SHIFT;
m_stack.z.y = (((FIXED - cos(deg)) * az >> FIXED_SHIFT) * ay >> FIXED_SHIFT) + sin(deg) * ax >> FIXED_SHIFT;
m_stack.z.z = (((FIXED - cos(deg)) * az >> FIXED_SHIFT) * az >> FIXED_SHIFT) + cos(deg);
m_stack.z.w = 0;
m_stack.w.x = 0;
m_stack.w.y = 0;
m_stack.w.z = 0;
m_stack.w.w = FIXED;
}
// 载入欧拉角旋转矩阵
void mat_load_EulerRotation(long yaw, long pitch, long roll)
{
mat_load_RotZAxis(roll);
mat_push();
mat_load_RotXAxis(pitch);
mat_mult();
mat_push();
mat_load_RotYAxis(yaw);
mat_mult();
}
// 载入左手坐标系观察矩阵
void mat_load_view_lh(long x, long y, long z, long yaw, long pitch, long roll)
{
long t;
mat_load_EulerRotation(yaw, pitch, roll);
eye_xaxis.x = m_stack.x.x;
eye_xaxis.y = m_stack.x.y;
eye_xaxis.z = m_stack.x.z;
eye_yaxis.x = m_stack.y.x;
eye_yaxis.y = m_stack.y.y;
eye_yaxis.z = m_stack.y.z;
eye_zaxis.x = m_stack.z.x;
eye_zaxis.y = m_stack.z.y;
eye_zaxis.z = m_stack.z.z;
m_stack.w.x = -((eye_xaxis.x * x >> FIXED_SHIFT) + (eye_xaxis.y * y >> FIXED_SHIFT) + (eye_xaxis.z * z >> FIXED_SHIFT));
m_stack.w.y = -((eye_yaxis.x * x >> FIXED_SHIFT) + (eye_yaxis.y * y >> FIXED_SHIFT) + (eye_yaxis.z * z >> FIXED_SHIFT));
m_stack.w.z = -((eye_zaxis.x * x >> FIXED_SHIFT) + (eye_zaxis.y * y >> FIXED_SHIFT) + (eye_zaxis.z * z >> FIXED_SHIFT));
m_stack.w.w = FIXED;
t = m_stack.x.y;
m_stack.x.y = m_stack.y.x;
m_stack.y.x = t;
t = m_stack.x.z;
m_stack.x.z = m_stack.z.x;
m_stack.z.x = t;
t = m_stack.y.z;
m_stack.y.z = m_stack.z.y;
m_stack.z.y = t;
m_stack.x.w = 0;
m_stack.y.w = 0;
m_stack.z.w = 0;
}
// 载入左手坐标系投影矩阵
void mat_load_perspective_lh(long fovy, long aspect, long zn, long zf)
{
long xscale,yscale;
long zdiff;
zdiff = zf-zn;
yscale = cot(fovy / 2);
xscale = (yscale << FIXED_SHIFT) / aspect;
m_stack.x.x = xscale; m_stack.x.y = 0; m_stack.x.z = 0; m_stack.x.w = 0;
m_stack.y.x = 0; m_stack.y.y = yscale; m_stack.y.z = 0; m_stack.y.w = 0;
m_stack.z.x = 0; m_stack.z.y = 0; m_stack.z.z = (zf<<FIXED_SHIFT)/zdiff; m_stack.z.w = FIXED;
m_stack.w.x = 0; m_stack.w.y = 0; m_stack.w.z = -zn*zf/zdiff; m_stack.w.w = 0;
}
// 将模型矩阵复制到栈顶
void mat_load_modelview()
{
memcpy(&m_stack.x.x, &m_modelview.x.x, 64);
}
// 将投影矩阵复制到栈顶
void mat_load_projection()
{
memcpy(&m_stack.x.x, &m_projection.x.x, 64);
}
// 将栈顶的矩阵复制到模型矩阵
void mat_set_modelview()
{
memcpy(&m_modelview.x.x, &m_stack.x.x, 64);
}
// 将栈顶的矩阵复制到投影矩阵
void mat_set_projection()
{
memcpy(&m_projection.x.x, &m_stack.x.x, 64);
}
// 打印矩阵的值到屏幕上
void mat_print(int x, int y)
{
char buf;
sprintf(buf, "%d:",m_stacktop);
TextOut(x,y,buf);y=y+GetFontSize();
sprintf(buf, "%d,%d,%d,%d", m_stack.x.x,m_stack.x.y,m_stack.x.z,m_stack.x.w);
TextOut(x,y,buf);y=y+GetFontSize();
sprintf(buf, "%d,%d,%d,%d", m_stack.y.x,m_stack.y.y,m_stack.y.z,m_stack.y.w);
TextOut(x,y,buf);y=y+GetFontSize();
sprintf(buf, "%d,%d,%d,%d", m_stack.z.x,m_stack.z.y,m_stack.z.z,m_stack.z.w);
TextOut(x,y,buf);y=y+GetFontSize();
sprintf(buf, "%d,%d,%d,%d", m_stack.w.x,m_stack.w.y,m_stack.w.z,m_stack.w.w);
TextOut(x,y,buf);
}
// 线性插值
long m_lerp(long v1, long v2, long s)
{
return v1 + ((v2 - v1) * s >> FIXED_SHIFT);
}
// 画线
void g_draw_line(long x1, long y1, long x2, long y2)
{
// gvmaker原版的画线函数不能处理坐标超出屏幕外的情况
// 所以要做一个插值处理
if(x1 < 0)
{
if(x2 < 0)
return; // 防止除零异常
y1 = y1 + (y2 - y1) *-x1 / (x2 - x1);
x1 = 0;
}
if(y1 < 0)
{
if(y2 < 0)
return;
x1 = x1 + (x2 - x1) *-y1 / (y2 - y1);
y1 = 0;
}
if(x2 < 0)
{
if(x1 <= 0)
return;
y2 = y2 + (y1 - y2) *-x2 / (x1 - x2);
x2 = 0;
}
if(y2 < 0)
{
if(y1 <= 0)
return;
x2 = x2 + (x1 - x2) *-y2 / (y1 - y2);
y2 = 0;
}
if(x1 > VP_RIGHT)
{
if(x2 > VP_RIGHT)
return;
y1 = y1 + (y2 - y1) * (x1 - VP_RIGHT) / (x1 - x2);
x1 = VP_RIGHT;
}
if(y1 > VP_BOTTOM)
{
if(y2 > VP_BOTTOM)
return;
x1 = x1 + (x2 - x1) * (y1 - VP_BOTTOM) / (y1 - y2);
y1 = VP_BOTTOM;
}
if(x2 > VP_RIGHT)
{
if(x1 >= VP_RIGHT)
return;
y2 = y2 + (y1 - y2) * (x2 - VP_RIGHT) / (x2 - x1);
x2 = VP_RIGHT;
}
if(y2 > VP_BOTTOM)
{
if(y1 >= VP_BOTTOM)
return;
x2 = x2 + (x1 - x2) * (y2 - VP_BOTTOM) / (y2 - y1);
y2 = VP_BOTTOM;
}
if(x1 == x2)
VLine(x1, y1, y2);
else if(y1 == y2)
HLine(x1, x2, y1);
else
Line(x1,y1,x2,y2);
}
// 画3D线,坐标将经过矩阵变换和投影处理。
void g_draw_3d_line(long x1, long y1, long z1, long x2, long y2, long z2)
{
long pxt, pyt, pzt, pwt; // 临时坐标
long px1, py1, pz1, pw1; // 坐标1
long px2, py2, pz2, pw2; // 坐标2
long ls;
pxt = (x1 * m_modelview.x.x >> FIXED_SHIFT) + (y1 * m_modelview.y.x >> FIXED_SHIFT) + (z1 * m_modelview.z.x >> FIXED_SHIFT) + m_modelview.w.x;
pyt = (x1 * m_modelview.x.y >> FIXED_SHIFT) + (y1 * m_modelview.y.y >> FIXED_SHIFT) + (z1 * m_modelview.z.y >> FIXED_SHIFT) + m_modelview.w.y;
pzt = (x1 * m_modelview.x.z >> FIXED_SHIFT) + (y1 * m_modelview.y.z >> FIXED_SHIFT) + (z1 * m_modelview.z.z >> FIXED_SHIFT) + m_modelview.w.z;
pwt = (x1 * m_modelview.x.w >> FIXED_SHIFT) + (y1 * m_modelview.y.w >> FIXED_SHIFT) + (z1 * m_modelview.z.w >> FIXED_SHIFT) + m_modelview.w.w;
px1 = (pxt * m_projection.x.x >> FIXED_SHIFT) + (pyt * m_projection.y.x >> FIXED_SHIFT) + (pzt * m_projection.z.x >> FIXED_SHIFT) + (pwt * m_projection.w.x >> FIXED_SHIFT);
py1 = (pxt * m_projection.x.y >> FIXED_SHIFT) + (pyt * m_projection.y.y >> FIXED_SHIFT) + (pzt * m_projection.z.y >> FIXED_SHIFT) + (pwt * m_projection.w.y >> FIXED_SHIFT);
pz1 = (pxt * m_projection.x.z >> FIXED_SHIFT) + (pyt * m_projection.y.z >> FIXED_SHIFT) + (pzt * m_projection.z.z >> FIXED_SHIFT) + (pwt * m_projection.w.z >> FIXED_SHIFT);
pw1 = (pxt * m_projection.x.w >> FIXED_SHIFT) + (pyt * m_projection.y.w >> FIXED_SHIFT) + (pzt * m_projection.z.w >> FIXED_SHIFT) + (pwt * m_projection.w.w >> FIXED_SHIFT);
pxt = (x2 * m_modelview.x.x >> FIXED_SHIFT) + (y2 * m_modelview.y.x >> FIXED_SHIFT) + (z2 * m_modelview.z.x >> FIXED_SHIFT) + m_modelview.w.x;
pyt = (x2 * m_modelview.x.y >> FIXED_SHIFT) + (y2 * m_modelview.y.y >> FIXED_SHIFT) + (z2 * m_modelview.z.y >> FIXED_SHIFT) + m_modelview.w.y;
pzt = (x2 * m_modelview.x.z >> FIXED_SHIFT) + (y2 * m_modelview.y.z >> FIXED_SHIFT) + (z2 * m_modelview.z.z >> FIXED_SHIFT) + m_modelview.w.z;
pwt = (x2 * m_modelview.x.w >> FIXED_SHIFT) + (y2 * m_modelview.y.w >> FIXED_SHIFT) + (z2 * m_modelview.z.w >> FIXED_SHIFT) + m_modelview.w.w;
px2 = (pxt * m_projection.x.x >> FIXED_SHIFT) + (pyt * m_projection.y.x >> FIXED_SHIFT) + (pzt * m_projection.z.x >> FIXED_SHIFT) + (pwt * m_projection.w.x >> FIXED_SHIFT);
py2 = (pxt * m_projection.x.y >> FIXED_SHIFT) + (pyt * m_projection.y.y >> FIXED_SHIFT) + (pzt * m_projection.z.y >> FIXED_SHIFT) + (pwt * m_projection.w.y >> FIXED_SHIFT);
pz2 = (pxt * m_projection.x.z >> FIXED_SHIFT) + (pyt * m_projection.y.z >> FIXED_SHIFT) + (pzt * m_projection.z.z >> FIXED_SHIFT) + (pwt * m_projection.w.z >> FIXED_SHIFT);
pw2 = (pxt * m_projection.x.w >> FIXED_SHIFT) + (pyt * m_projection.y.w >> FIXED_SHIFT) + (pzt * m_projection.z.w >> FIXED_SHIFT) + (pwt * m_projection.w.w >> FIXED_SHIFT);
// 处理近视距剪切
if(pz1 < FIXED)
{
if(pz2 < FIXED)
return;
if(pz1 == pz2)
return;
ls = ((pz2 - FIXED) << FIXED_SHIFT) / (pz2 - pz1);
px1 = m_lerp(px2, px1, ls);
py1 = m_lerp(py2, py1, ls);
pz1 = m_lerp(pz2, pz1, ls);
pw1 = m_lerp(pw2, pw1, ls);
}
if(pz2 < FIXED)
{
if(pz1 < FIXED)
return;
if(pz1 == pz2)
return;
ls = ((pz1 - FIXED) << FIXED_SHIFT) / (pz1 - pz2);
px2 = m_lerp(px1, px2, ls);
py2 = m_lerp(py1, py2, ls);
pz2 = m_lerp(pz1, pz2, ls);
pw2 = m_lerp(pw1, pw2, ls);
}
// 投影
px1 = px1 * VP_CENTERX / pw1 + VP_CENTERX;
py1 = VP_CENTERY - py1 * VP_CENTERY / pw1;
px2 = px2 * VP_CENTERX / pw2 + VP_CENTERX;
py2 = VP_CENTERY - py2 * VP_CENTERY / pw2;
g_draw_line(px1,py1,px2,py2);
}
// 用线条画长方体
void g_draw_cube(long dx, long dy, long dz)
{
// Up
g_draw_3d_line(-dx, dy, dz, dx, dy, dz);
g_draw_3d_line( dx, dy, dz, dx, dy,-dz);
g_draw_3d_line( dx, dy,-dz,-dx, dy,-dz);
g_draw_3d_line(-dx, dy,-dz,-dx, dy, dz);
// Down
g_draw_3d_line(-dx,-dy, dz, dx,-dy, dz);
g_draw_3d_line( dx,-dy, dz, dx,-dy,-dz);
g_draw_3d_line( dx,-dy,-dz,-dx,-dy,-dz);
g_draw_3d_line(-dx,-dy,-dz,-dx,-dy, dz);
// Pillars
g_draw_3d_line(-dx, dy, dz,-dx,-dy, dz);
g_draw_3d_line( dx, dy, dz, dx,-dy, dz);
g_draw_3d_line( dx, dy,-dz, dx,-dy,-dz);
g_draw_3d_line(-dx, dy,-dz,-dx,-dy,-dz);
}
// 输出16进制数
void XDigitOut(int x, int y, long digit)
{
int ch;
int w;
int shifts;
w = GetFontSize() / 2;
if(!digit)
{
TextOut(x, y, "00000000");
return;
}
x=x+w*7;
shifts=32;
while(shifts)
{
ch=digit&0xF;
if(ch>=10)
CharOut(x, y, ch-10+'A');
else
CharOut(x, y, ch+'0');
x=x-w;
digit=digit>>4;
shifts=shifts-4;
}
}
void main()
{
long i;
int x,y;
SetFontSize(12);
SetLCDMode(0);
eye_pos.x=0;
eye_pos.y=3 << FIXED_SHIFT;
eye_pos.z=-10 << FIXED_SHIFT;
mat_init();
time_global = GetTickCount();
for(;;)
{
// 帧时间处理
i = GetTickCount();
time_delta = i - time_global;
time_global = i;
ClearScreen();
// 设置投影矩阵
mat_load_perspective_lh(60, (VP_WIDTH << FIXED_SHIFT) / VP_HEIGHT, FIXED, 1000 << FIXED_SHIFT);
mat_set_projection();
// 设置旋转立方体的矩阵
mat_load_RotYAxis(time_global * 60 / 1000);
mat_push();
mat_load_translate(0,FIXED,0);
mat_mult();
mat_push();
mat_load_view_lh(eye_pos.x, eye_pos.y, eye_pos.z, eye_yaw, eye_pitch, 0);
mat_mult();
mat_set_modelview();
// 画立方体
g_draw_cube(FIXED, FIXED, FIXED);
// 设置地面的矩阵
mat_load_view_lh(eye_pos.x, eye_pos.y, eye_pos.z, eye_yaw, eye_pitch, 0);
mat_set_modelview();
// 画地面
for(x = -10; x <= 10; x++)
{
g_draw_3d_line( x << FIXED_SHIFT, 0, 10 << FIXED_SHIFT, x << FIXED_SHIFT, 0, -10 << FIXED_SHIFT);
}
for(y = -10; y <= 10; y++)
{
g_draw_3d_line( 10 << FIXED_SHIFT, 0, y << FIXED_SHIFT,-10 << FIXED_SHIFT, 0, y << FIXED_SHIFT);
}
// 根据触屏操作来转动镜头
if(GetMousePos(pt) == 2)
{
eye_yaw = eye_yaw + pt_old.x - pt.x;
eye_pitch = eye_pitch + pt_old.y - pt.y;
if(eye_yaw < 0)
eye_yaw = eye_yaw + 360;
if(eye_yaw > 360)
eye_yaw = eye_yaw - 360;
if(eye_pitch < 0)
eye_pitch = eye_pitch + 360;
if(eye_pitch > 360)
eye_pitch = eye_pitch - 360;
}
pt_old.x = pt.x;
pt_old.y = pt.y;
// 键盘移动操作
if(CheckKey(KEY_LEFT))
{
eye_pos.x = eye_pos.x - eye_xaxis.x * time_delta * 10 / 1000;
eye_pos.y = eye_pos.y - eye_xaxis.y * time_delta * 10 / 1000;
eye_pos.z = eye_pos.z - eye_xaxis.z * time_delta * 10 / 1000;
}
if(CheckKey(KEY_RIGHT))
{
eye_pos.x = eye_pos.x + eye_xaxis.x * time_delta * 10 / 1000;
eye_pos.y = eye_pos.y + eye_xaxis.y * time_delta * 10 / 1000;
eye_pos.z = eye_pos.z + eye_xaxis.z * time_delta * 10 / 1000;
}
if(CheckKey(KEY_UP))
{
eye_pos.x = eye_pos.x + eye_zaxis.x * time_delta * 10 / 1000;
eye_pos.y = eye_pos.y + eye_zaxis.y * time_delta * 10 / 1000;
eye_pos.z = eye_pos.z + eye_zaxis.z * time_delta * 10 / 1000;
}
if(CheckKey(KEY_DOWN))
{
eye_pos.x = eye_pos.x - eye_zaxis.x * time_delta * 10 / 1000;
eye_pos.y = eye_pos.y - eye_zaxis.y * time_delta * 10 / 1000;
eye_pos.z = eye_pos.z - eye_zaxis.z * time_delta * 10 / 1000;
}
Refresh();
}
}Src:
Bin:
本帖最后由 Ayala 于 2017-3-17 18:28 编辑
但定点数的缺点在于做乘除法的时候,会严重地损失精度,尤其是圆周率,32位浮点数能存储3.1415927,而定点数假设小数点在第10位,那么它只能用 3216 来表示圆周率(3216 = π×1024 取整)。而如果我把小数点放在第16位的位置上(1.0用65536表示)的话,我虽然能精确到1/65536,但我能存储的最大的数值也从之前的4294966272变成了65536,而且我每次做乘除法的时候,我都要用一个64位的整数来存储中间值,这会严重降低运算的效率(然而x86平台还好)
这个问题其实可以用1024* PI*2**8 (定点数 π×1024 * 256 =0xC90FE)来解决 当然也可以用 1024*PI*2**15更高数值
另外PI*1024 取整也应该是3216.990877≈3217 而不是 3216 Ayala 发表于 2017-3-17 18:07
这个问题其实可以用1024* PI*2**8 (定点数 π×1024 * 256 =0xC90FE)来解决 当然也可以用 1024*PI*2**15更 ...
其实是说错,不是取整,而是“商”,所以是没有四舍五入的 另外因为文曲星的解释器特征,优化方面侧重于多调用它的函数进行绘图,少进行自己的绘图方式。比如它的画线函数,其实虽然明明可以自己写一个不使用乘除法的画线函数,但依然还是推荐使用它自己的画线函数(VLine、HLine、Line)。因为自己写的画线函数在运行的时候需要GVMaker虚拟机对其进行指令层面的判断和模拟执行的操作,而它自己的画线函数则是用文曲星本机的处理器指令执行的。
页:
[1]