软件渲染笔记 03 模型线框
在上篇文章中,我们已经掌握了如何画线. 这次我们将基于画线函数来画模型线框.
伪代码
不同格式的模型文件,数据多多少少都有些不同.我们这里不考虑模型的存储方式,先以直观感受来写伪代码.
for face in facesOfModel:
for i to numOfVerticesInFace:
draw(vertexi,(vertexi+1 )%numOfVerticesInFace)
简单解释下上述伪码的含义:我们首先遍历模型中所有的面.然后遍历模型中的点,把相邻的点都连成线.
waveobj格式
完整的waveobj格式描述可以看
waveobj wiki .
由于我们只绘制线框,所以只看对我们有用的信息.
关于面:
有三种表达面的方式:
1. f v/vt
2. f v//vn
3. f v/vt/vn
其中,f是面的意思.v是顶点坐标索引.vt是纹理坐标索引.vn是顶点法向量索引.
关于顶点:
顶点的表示方式为:
v x y z (w)
其中,w可以省略.
到此为止,需要画模型线框的数据格式我们已经掌握.
源码分析
首先,按照上述wavefront obj的格式说明来解析文件读入内存.然后,直接翻译伪码即可. 代码如下:
Model *model= new Model("model/african_head.obj" );
for (int i=0 ;infaces();i++)
{
vector <int > face=model->face(i);
for (int j=0 ;jvert(face[j]);
Vec3f vertexTo=model->vert(face[(j+1 )%face.size()]);
line(image,green,
(1 +vertexFrom.x)*0.5 *CANVAS_WIDTH,
(1 +vertexFrom.y)*0.5 *CANVAS_HEIGHT,
(1 +vertexTo.x)*0.5 *CANVAS_WIDTH,
(1 +vertexTo.y)*0.5 *CANVAS_HEIGHT);
}
}
需要额外注意的是,代码里的顶点坐标范围为[-1,1].所以乘以了CANVAS尺寸的一半.默认原点为左下角,所以加上了半屏的偏移值.忽略z值.
效果图如下:
点击这里下载完整代码