如果你喜欢我写的文章,可以把我的公众号设为星标 ,这样每次有更新就可以及时推送给你啦。

前面两天画了点和线,今天我们来画一个最简单也是最强大的面——三角形

本文主要讲解三角形绘制算法的推导和思路(只涉及到一点点的向量知识),最后会给出代码实现,大家放心的看下去就好。

本文源码 :toyRenderer-day3-draw-triangle

1.如何画一个三角形?

在正式开始这一小节前,我们先想一下如何利用上一节的画线算法绘制一个实心的三角形。

假设现在平面内有三个不共线的点组成一个三角形,我们可以利用上一节的直线算法轻易的连接三角形的三条边,这时候我们会生成一个空心的封闭的三角形。

那么这时候问题就转换为,如何把这个空心的三角形变为一个实心的三角形?

我想大家这时候已经有思路了,就是一行一行地扫描像素,把两个边界点之间的像素全部涂满上色就可以了。


day03_scanLineDrawTriangle

这个方法肯定是可以的,但是实现不是很优雅,也不是业内的主流实现方式。因为基于行扫描的算法不是本文的重点,所以详细的推导和代码实现就不提供了,感兴趣的同学可以自己尝试实现一下。

2.利用向量叉乘画三角形

开始本节前先简单复习一下向量叉乘的几何意义。

2.1 数学推导

在三维空间中,两个三维向量 和 做叉乘,会得到一个和已知两个向量垂直的新向量 。

既然叉乘产生的是一个新向量,那么它肯定有个方向,我们一般用右手定则来判断:将右手食指指向 的方向、中指指向 的方向,则此时拇指的方向即为 的方向。


右手定则

综上所述,我们可以对向量叉乘做一个严谨的定义:

其中 表示 和 在它们所定义的平面上的夹角()。 和 是向量 和 的模长,而 则是一个与 、 所构成的平面垂直的单位向量,方向由右手定则决定。

有上面的理论,我们就可以判断两个向量的相对位置:

  • 向量叉乘 向量,如果值为,则表示 向量在 向量
  • 向量叉乘 向量,如果值为,则表示 向量在 向量
  • 向量叉乘 向量,如果值为,则表示 向量与 向量共线

会判断两条线的相对位置了,我们可以做个理论迁移,利用向量叉乘判断点和三角形的位置关系

例如下面这里例子,对于三角形 来说,把三条边看作 、 、 三条首尾相连的向量,平面内有一个点 ,我们通过向量叉乘来判断相对位置:


day03_cross_product
  • ,值为,故 在 左侧
  • ,值为,故 在 左侧
  • ,值为,故 在 左侧

综合以上三个限制条件,我们可以判断 在 内。

如果上面三个计算中有值为负的情况,说明 在三角形外;如果有值为 0 的情况,说明 在三角形的边或顶点上。

2.2 代码实现

理论基础复习完了,我们就可以写代码了。代码实现相当简单,我们构建一个函数 crossProduct,传入三角形的三个顶点和平面上的任意一点 ,然后根据四个顶点构建出向量计算叉乘就可以了:

// 利用叉乘判断是否在三角形内部
Vec3i crossProduct(Vec2i *pts, Vec2i P) {
    // 构建出三角形 ABC 三条边的向量
    Vec2i AB(pts[1].x - pts[0].x, pts[1].y - pts[0].y);
    Vec2i BC(pts[2].x - pts[1].x, pts[2].y - pts[1].y);
    Vec2i CA(pts[0].x - pts[2].x, pts[0].y - pts[2].y);
    
    // 三角形三个顶点和 P 链接形成的向量
    Vec2i AP(P.x - pts[0].x, P.y - pts[0].y);
    Vec2i BP(P.x - pts[1].x, P.y - pts[1].y);
    Vec2i CP(P.x - pts[2].x, P.y - pts[2].y);
    
    return Vec3i(AB^AP, BC^BP, CA^CP);
}

代码非常的简单,我们跑一个简单的例子验证一下:

void drawSingleTriangle() {
    // 图片的宽高
    int width  = 200;
    int height = 200;

    TGAImage frame(width, height, TGAImage::RGB);
    Vec2i pts[3] = {Vec2i(10, 10), Vec2i(150, 30), Vec2i(70, 160)};

    Vec2i P;
    // 遍历图片中的所有像素
    for (P.x = 0; P.x <= width - 1; P.x++) {
        for (P.y = 0; P.y <= height - 1; P.y++) {
            Vec3i bc_screen  = crossProduct(pts, P);

            // bc_screen 某个分量小于 0 则表示此点在三角形外(认为边也是三角形的一部分)
            if (bc_screen.x<0 || bc_screen.y<0 || bc_screen.z<0) {
                continue;
            }
            
            image.set(P.x, P.y, color);
        }
    }
    
    frame.flip_vertically();
    frame.write_tga_file("output/day03_cross_product_triangle.tga");
}

看输出图像,我们已经成功绘制了一个三角形:


day03_cross_product_triangle

触不及防的安利:大家可以看我头像关注

【十天自制软渲染器】DAY 03:画一个三角形(向量叉乘算法 & 重心坐标算法)的更多相关文章

  1. 【十天自制软渲染器】DAY 01:图形学学习建议与环境搭建

    推荐直接阅读博客原文,更新更及时,阅读体验更佳 「十天自制软渲染器」这个标题我承认标题党了.在对图形学一无所知的情况下想十天自制一个软渲染器,就好似一节课没上过却试图一个晚上看完<30 天精通 ...

  2. 【十天自制软渲染器】DAY 02:画一条直线(DDA 算法 & Bresenham’s 算法)

    推荐关注公众号「卤蛋实验室」或访问博客原文,更新更及时,阅读体验更佳 第一天我们搭建了 C++ 的运行环境并画了一个点,根据 点 → 线 → 面 的顺序,今天我们讲讲如何画一条直线. 本文主要讲解直线 ...

  3. CSharpGL(34)以从零编写一个KleinBottle渲染器为例学习如何使用CSharpGL

    CSharpGL(34)以从零编写一个KleinBottle渲染器为例学习如何使用CSharpGL +BIT祝威+悄悄在此留下版了个权的信息说: 开始 本文用step by step的方式,讲述如何使 ...

  4. 基于物理渲染的渲染器Tiberius计划

    既然决定实现一个光栅化软件渲染器,我又萌生了一个念头:实现一个基于物理渲染的渲染器.

  5. Django:之Sitemap站点地图、通用视图和上下文渲染器

    Django中自带了sitemap框架,用来生成xml文件 Django sitemap演示: sitemap很重要,可以用来通知搜索引擎页面的地址,页面的重要性,帮助站点得到比较好的收录. 开启si ...

  6. 基于OpenGL编写一个简易的2D渲染框架-08 重构渲染器-整体架构

    事实上,前面编写的渲染器 Renderer 非常简陋,虽然能够进行一些简单的渲染,但是它并不能满足我们的要求. 当渲染粒子系统时,需要开启混合模式,但渲染其他顶点时却不需要开启混合模式.所以同时渲染粒 ...

  7. 29.渲染器Renderer

    什么是渲染器     渲染器就是将服务器生成的数据格式转为http请求的格式   渲染器触发及参数配置 在DRF配置参数中,可用的渲染器作为一个类的列表进行定义 但与解析器不同的是,渲染器的列表是有顺 ...

  8. 用 windows GDI 实现软光栅化渲染器--gdi3d(开源)

    尝试用windows GDI实现了一个简单的软光栅化渲染器,把OpenGL渲染管线实现了一遍,还是挺有收获的,搞清了以前一些似是而非的疑惑. ----更新2015-10-16代码已上传.gihub地址 ...

  9. Restful framework【第十篇】响应器(渲染器)

    基本使用 -响应器(一般用默认就可以了) -局部配置 renderer_classes=[JSONRenderer,] -全局配置 'DEFAULT_RENDERER_CLASSES': ( 'res ...

随机推荐

  1. Android驱动-Java入门学习(java安装)

    在ubuntu 14.04上java开发环境. 下载 jdk-7u75-linux-x64.tar.gz 使用tar xvf jdk-7u75-linux-x64.tar.gz 解压 在/usr/li ...

  2. sqlite嵌入式数据库简介及特性

    p.p1 { margin: 0; font: 12px "Helvetica Neue"; color: rgba(69, 69, 69, 1) } p.p2 { margin: ...

  3. Redis性能篇(二)CPU核和NUMA架构的影响

    Redis被广泛使用的一个很重要的原因是它的高性能.因此我们必要要重视所有可能影响Redis性能的因素.机制以及应对方案.影响Redis性能的五大方面的潜在因素,分别是: Redis内部的阻塞式操作 ...

  4. Centos7安装(本文档采用CentOS7 mini版本)

    选择[语言],点击[继续]等待出现以下界面 一.下载 centos: centos/7/isos/x86_64/CentOS-7-x86_64-Minimal-1611.iso 二.VMware Wo ...

  5. CPU性能测试——CoreMark篇

    本文将介绍使用CoreMark测试程序对我们小组自研芯片进行性能的测试,记录了CoreMarK工具的使用以及对其测试结果进行分析 测试环境: PC OS: Ubuntu20.04 LTS CPU: 自 ...

  6. 短信平台开发,G客短信系统功能介绍

    G客短信群发平台功能介绍 支持HTTP 接口 .CMPP SMPP等 这里只有基本功能介绍 联系微信:290615413 QQ:290615413 一:客户端功能 1:首页仪表盘 首页包含 2:发送短 ...

  7. 魔法方法推开Python进阶学习大门

    热爱Python Python是Guido van Rossum设计出来的让使用者觉得如沐春风的一门编程语言.2020年11月12日,64岁的Python之父宣布由于退休生活太无聊,自己决定加入Mic ...

  8. 常用的N个网站建议收藏

    类型网站路径学习资源及博客论坛网站 书栈网:https://www.bookstack.cn 52 download: http://www.52download.cn/wpcourse/ 菜鸟教程: ...

  9. awk -v参数

    -v var=val --assign var=val Assign the value val to the variable var, before execution of the progra ...

  10. 【Web】CSS实现鼠标悬停实现显示与隐藏 特效

    鼠标悬停实现显示与隐藏特效 简单记录 - 慕课网 Web前端 步骤四:鼠标悬停实现显示与隐藏特效 初步掌握定位的基本使用,以及CSS选择器更高级的运用,完成一个网页中必会的鼠标经过隐藏显示特效. 实现 ...