光栅渲染器(七)线框模型绘制和背部剔除实现

来源:互联网 发布:阿里云远程桌面连接 编辑:程序博客网 时间:2024/04/28 21:11

我们曾经完成过按多边形顶点输入完成无填充多边形顶点的绘制,所以现在可以按同样的思路绘制线框模型

设置状态

 enum _State {     normal,     wireframe }; _State _state = normal;

我们利用这个状态改变模型是之前渲染出的彩色模型还是线框模型

设置状态改变条件

我们选择用space按键改变当前模型的状态

//************************键盘输入*******************void myKeyBoard(unsigned char theKey, int MouseX, int MouseY){    switch (theKey)    {    case 'w':        CameraPos -= 0.1;        myDisplay();        break;    case 's':        CameraPos += 0.1;        myDisplay();        break;    case 'a':        Alpha += 0.1;        myDisplay();        break;    case 'd':        Alpha -= 0.1;        myDisplay();        break;    case ' ':        switch (_state)        {            case normal:                _state = wireframe;                myDisplay();                break;            case wireframe:                _state = normal;                myDisplay();                break;            default:                break;        }        break;    default:        break;    }}

更改之前的画面函数

void draw_plane( int a, int b, int c, int d) {    vertex_t p1 = mesh[a], p2 = mesh[b], p3 = mesh[c], p4 = mesh[d];    vector<vertex_t> vs{ p1,p2,p3,p4 };    switch (_state)    {        case normal:            DrawTriangle(p1, p2, p3);            DrawTriangle(p3, p4, p1);            break;        case wireframe:            DrawTriangle_wire(vs);            break;        default:            break;    }}

绘制线框模型

//绘制线框多边形void DrawTriangle_wire(vector<vertex_t> vs){    int size = vs.size();    vector<vertex_t> ps;    for (int i = 0; i < size; i++)    {        vertex_t vss=vs[i];        point_t c, v;        point_t p = vs[i].pos;        transform_apply(&Transform, &c, &p);        if (transform_check_cvv(&c) != 0) return;        transform_homogenize(&Transform, &v, &c);        vss.pos = v;        vss.pos.w = c.w;        vss.color.r = 1;        vss.color.g = 1;        vss.color.b = 1;        vss.color.a = 1;        ps.push_back(vss);    }    for (int i = 0; i < size; i++)    {        if(i+1<=size-1)            DrawLine(ps[i], ps[i+1]);        else            DrawLine(ps[i], ps[0]);    }}

这里写图片描述
由于没有加入背部剔除,所以我们视野内有多余的线段

背部剔除

只要规定好画正方体时顶点数据的输入顺序,利用方向叉乘和点积判断
这里写图片描述
我们所见的面点的顺序应为顺时针,不能见到的为逆时针
所有修改的顶点顺序为如下

vertex_t mesh[8] = {    { { 1, -1,  1, 1 },{ 1.0f, 0.2f, 0.2f } },    { { -1, -1,  1, 1 },{ 0.2f, 1.0f, 0.2f } },    { { -1,  1,  1, 1 },{ 0.2f, 0.2f, 1.0f }},    { { 1,  1,  1, 1 },{ 1.0f, 0.2f, 1.0f } },    { { 1, -1, -1, 1 },{ 1.0f, 1.0f, 0.2f } },    { { -1, -1, -1, 1 },{ 0.2f, 1.0f, 1.0f } },    { { -1,  1, -1, 1 },{ 1.0f, 0.3f, 0.3f }},    { { 1,  1, -1, 1 },{ 0.2f, 1.0f, 0.3f } },};//************************画立方体*******************void DrawBox(){    matrix_t m;    //matrix_set_rotate(&m, -1,1, 1, Alpha);    matrix_set_rotate(&m, -1, -1, 1, Alpha);    Transform.world = m;    transform_update(&Transform);    draw_plane( 0, 1, 2, 3);    draw_plane(4, 7, 6, 5);    draw_plane( 0, 4, 5, 1);    draw_plane( 1, 5, 6, 2);    draw_plane(2, 6, 7, 3);    draw_plane( 3, 7, 4, 0);}

接下来是背部剔除的代码

// 背部剔除bool DeleteBack(vertex_t ve1, vertex_t ve2, vertex_t ve3){    vector_t direction = {0,0,-1,1}//视角所见的方向矢量;    vector_t normal;//法线    vector_t v1, v2;    vector_sub(&v1,&ve2.pos, &ve1.pos);    vector_sub(&v2, &ve3.pos, &ve2.pos);    v1.z = 0;    v2.z = 0;    vector_crossproduct(&normal, &v1, &v2);    float dot = vector_dotproduct(&normal, &direction);    if (dot<0) return true;    return false;} 

利用叉乘获得面的方向,通过点积正负判断法线的方向,从而得知面顶点的方向
修改的绘制线框模型的代码如下

//绘制线框多边形void DrawTriangle_wire(vector<vertex_t> vs){    int size = vs.size();    vector<vertex_t> ps;    for (int i = 0; i < size; i++)    {        vertex_t vss=vs[i];        point_t c, v;        point_t p = vs[i].pos;        transform_apply(&Transform, &c, &p);        if (transform_check_cvv(&c) != 0) return;        transform_homogenize(&Transform, &v, &c);        vss.pos = v;        vss.pos.w = c.w;        vss.color.r = 1;        vss.color.g = 1;        vss.color.b = 1;        vss.color.a = 1;        ps.push_back(vss);    }    if (DeleteBack(ps[0], ps[1], ps[2])) return;    for (int i = 0; i < size; i++)    {        if (i + 1 <= size - 1)        {            DrawLine(ps[i], ps[i + 1]);        }               else if(i == size - 1)        {            DrawLine(ps[i], ps[0]);        }    }}

这里写图片描述
完成

原创粉丝点击