第一章:从3D到2D

本文是《从0开始图形学》的第一章内容。讲解如何将3D的模型"画"到2D的图形山。

概念解说

图形学渲染,就是将3D的东西"画"到2D的屏幕上,和拍照的效果是一样的,这也是为什么很多3D渲染引擎会有"相机"这个概念,这一节我们来看一下怎么把3D变成2D。

场景定义

首先,我们定义一个渲染场:一个定义好的坐标系中某个3D的箱子,黄色的球体代表相机,如下图所示

我们的渲染结果就应该同相机视角看到的结果一样,如下图所示,透过半透明的"画布",可以看到箱子在"画布"上的样子

问题提出

那么,如何实现上面效果呢?我们先从箱子的整体轮廓入手,很简单,只要将箱子的八个顶点坐标的Z轴分量去掉,找到图片上对应的X,Y就是对应顶点的渲染位置(图中红色的点),再将点和点之间用线连接起来,也就是箱子的8条边(图中黄色的线)

是不是马上就有点立体感了!那代码上要怎么实现呢,很简单!

C核心代码

首先,定义需要渲染的点,以及这些点的关系索引

复制代码
// 定义渲染数据
float _points[8][3] =       // 点的数据
{
    {469.70839522142523, 181.86451044628149, 268.14698315693755}, // x, y, z
    {741.60073227608791, 149.05001503297740, 390.61234945175556},
    {741.60073227608791, 535.42034601093997, 494.13996576730500},
    {469.70839522142523, 568.23484142424411, 371.67459947248699},
    {258.39926772391209, 64.579653989059977, 705.86003423269506},
    {530.29160477857477, 31.765158575755891, 828.32540052751301},
    {530.29160477857477, 418.13548955371851, 931.85301684306251},
    {258.39926772391209, 450.94998496702260, 809.38765054824444},
};

int _planes[6][4] =      // 面的数据
{
    {0, 1, 2, 3},     // 每个面4个角的顶点对应于索引值
    {4, 5, 6, 7},
    {1, 5, 6, 2},
    {3, 2, 6, 7},
    {0, 4, 7, 3},
    {0, 1, 5, 4}
};

第二步,根据上述的实现原理,将其画在结果图上,为方便,我们直接在ShowCGRst函数中对结果图进行修改,这里我们使用了OpenCV的画点函数cv::circle和画线函数cv::line

复制代码
    // 将_points画到结果上
    int x, y, z;

    for (int i = 0; i < 8; ++i)
    {
        x = _points[i][0];
        y = _points[i][1];
        z = _points[i][2];
        cv::circle(cvRst, cv::Point(x, y), 5, cv::Scalar(0, 0, 255), -1);     // 使用OpenCV的画点函数
    }

    // 将点之间的关系(即箱子的边缘线)画出来
    int x1, y1, z1;

    for (int i = 0; i < 6; ++i)
    {
        for (int j = 0; j < 3; ++j)
        {
            x = _points[_planes[i][j]][0];
            y = _points[_planes[i][j]][1];
            z = _points[_planes[i][j]][2];
            x1 = _points[_planes[i][j + 1]][0];
            y1 = _points[_planes[i][j + 1]][1];
            z1 = _points[_planes[i][j + 1]][2];
            cv::line(cvRst, cv::Point(x, y), cv::Point(x1, y1), cv::Scalar(0, 255, 255), 2);
        }

        x = _points[_planes[i][0]][0];
        y = _points[_planes[i][0]][1];
        z = _points[_planes[i][0]][2];
        cv::line(cvRst, cv::Point(x, y), cv::Point(x1, y1), cv::Scalar(0, 255, 255), 2);
    }

完整代码见开头的下载资源,百度网盘下载处

这里已经画出了箱子的"骨",下一步我们将绘制箱子的"皮"

相关推荐
清风笑烟语1 天前
rustfs 集群部署
3d
还是大剑师兰特1 天前
Unity 从零搭建简易3D场景(新手分步教程)
3d·unity·游戏引擎
EQ-雪梨蛋花汤1 天前
Android 3D 开发教程(三):Sceneform-EQR 配置 PBR 材质、光照、相机与实时阴影
android·3d·材质
弈语道破AI1 天前
3D渲染不再熬时间!即梦 Seedance 2.5 具备3D白模渲染功能的AI视频生成工具
人工智能·3d·音视频
答案—answer2 天前
VibeCoding 能做到什么程度?我用它做了一座 3D 数字博物馆
3d·ai编程·threejs·vibecoding
玖玥拾2 天前
Unity3D RPG 入门项目(四)背包拖拽、物品悬浮提示、项目开发思维
3d·unity·游戏引擎
cyadyx3 天前
【Three.js】Three.js 中加载 3D 模型
前端·javascript·3d
chaoyuanl3 天前
悬空玻璃剧场源头厂家选型全解析|270°裸眼3D悬空玻璃剧场投资避坑指南
大数据·人工智能·3d·xr·娱乐·mr
在下胡三汉3 天前
GLTF vs OBJ vs FBX vs GLB:选择合适的 3D 文件格式,怎么获取下载
3d
fanfan_hongyun3 天前
Cesium for unity (可加载3dTileset)
3d