games101,作业2

2023-10-27

需要补充的函数

rasterize_triangle(): 执行三角形栅格化算法
static bool insideTriangle(): 测试点是否在三角形内。你可以修改此函 数的定义,这意味着,你可以按照自己的方式更新返回类型或函数参数。

判断点是否在三角形内

若三角形ABC中有一点p,则AP x AB, BP x BC,CP x CA三个向量的叉乘方向相同。
若在平面上,则两向量叉乘方向平行z轴,为正为负取决于屏幕坐标向内为正为负。

代码

Eigen::Vector2f p;
    p << x, y;

    Eigen::Vector2f AB = _v[1].head(2) - _v[0].head(2);
    Eigen::Vector2f BC = _v[2].head(2) - _v[1].head(2);
    Eigen::Vector2f CA = _v[0].head(2) - _v[2].head(2);

    Eigen::Vector2f AP = p - _v[0].head(2);
    Eigen::Vector2f BP = p - _v[1].head(2);
    Eigen::Vector2f CP = p - _v[2].head(2);

    // 判断每个z坐标是否统一,因为在这个着色器中z轴正向指向显示屏内部,所以内部点p叉乘值大于0.
    return AB[0] * AP[1] - AB[1] * AP[0] > 0
        && BC[0] * BP[1] - BC[1] * BP[0] > 0
        && CA[0] * CP[1] - CA[1] * CP[0] > 0;

三角形栅格化算法

算法不难,理解了整个程序就好写了。
至于下面的函数
auto p = computeBarycentric2D(x, y, t.v);
可查看我的另一篇博客 games101 Lecture 9 线性插值(对三角形内部的线性插值)

 	auto v = t.toVector4();

    // TODO : Find out the bounding box of current triangle.
    float l, r, top, bom;
    //+0.5 是为了四舍五入
    l = min(v.at(0).x(), v.at(1).x(), v.at(2).x())+0.5f;
    r = max(v.at(0).x(), v.at(1).x(), v.at(2).x()) + 0.5f;
    bom = min(v.at(0).y(), v.at(1).y(), v.at(2).y()) + 0.5f;
    top = max(v.at(0).y(), v.at(1).y(), v.at(2).y()) + 0.5f;
    // iterate through the pixel and find if the current pixel is inside the triangle
    for (int x = l;x <= r;x++) {
        for (int y = bom;y <= top;y++) {
            Eigen::Vector3f res[3];
            std::transform(std::begin(v), std::end(v), res, [](auto& vec) { return Eigen::Vector3f(vec.x()+0.5, vec.y()+0.5, vec.z()); });
            if (insideTriangle(x, y, res)) {
                //std::cout << x<<","<<y << std::endl;
                // If so, use the following code to get the interpolated z value.
                auto p = computeBarycentric2D(x, y, t.v);//计算x,y点线性插值系数
                float alpha = std::get<0>(p);
                float beta = std::get<1>(p);
                float gamma = std::get<2>(p);
                float w_reciprocal = 1.0/(alpha / v[0].w() + beta / v[1].w() + gamma / v[2].w());
                float z_interpolated = alpha * v[0].z() / v[0].w() + beta * v[1].z() / v[1].w() + gamma * v[2].z() / v[2].w();
                z_interpolated *= w_reciprocal;
                // TODO : set the current pixel (use the set_pixel function) to the color of the triangle 
                //(use getColor function) if it should be painted.
                if (z_interpolated < depth_buf[get_index(x, y)]) {
                    set_pixel(Eigen::Vector3f(x, y, z_interpolated), t.getColor());
                }
            }
        }
    }

MASS(super-sampling Anti-aliasing)

超采样:一个像素分隔为多个像素点采样,然后求多个像素点采样的平均值。

出现黑边

先说结论:

黑边恰恰说明我们对图像做了mass采样,但这种效果并不好!

黑边出现的原因:
在非三角形内的像素点,由于增加了偏移量,使得非三角形内像素点在判断时有一个或两个偏移位置在三角形内,使得该像素点有count/4的颜色,颜色较暗但并非黑色。
消除黑边的办法
  1. 先判断该像素点是否在三角形内,如果在三角形内再进行MASS采样,即只会模糊化三角形内像素点,不会改变三角形外像素点的颜色和深度。
  2. 换一种思考方式,如果像素点在图像内部,则count值一般情况下都>=3(但这也会有bug情况出现)。

测试案例

出现黑边
在这里插入图片描述
增大采样偏移数

std::vector<Eigen::Vector2f> offset{
            { 1.5f, 1.5f},
            { 1.5f,-1.5f},
            {-1.5f, 1.5f},
            {-1.5f,-1.5f}
        };

在这里插入图片描述
考虑出现黑边的原因是采样范围过大,修改偏移量为

std::vector<Eigen::Vector2f> offset{
            { 0.2f, 0.2f},
            { 0.2f,-0.2f},
            {-0.2f, 0.2f},
            {-0.2f,-0.2f}
        };

得到
在这里插入图片描述
可以看出只有一小部分任由黑边。
考虑黑边像素点采样时有一部分(count == 1或2)采样会采到三角形内.
故修改像素填充条件:

if (count>2) {
	......
}

在这里插入图片描述
可以看到,虽然我们消除了黑边,但是右边三角形的锯齿状却变得明显。

使用内部MASS抗锯齿:

if (!insideTriangle(x, y, res)) continue;

在这里插入图片描述

效果对比

内部MASS抗锯齿
在这里插入图片描述
无抗锯齿
在这里插入图片描述
MASS抗锯齿(有黑边)
在这里插入图片描述

代码

void rst::rasterizer::rasterize_triangle(const Triangle& t) {
    auto v = t.toVector4();

    // TODO : Find out the bounding box of current triangle.
    float l, r, top, bom;
    //Triangle& t中的x,y为(700,700)内的小数
    l = min(v.at(0).x(), v.at(1).x(), v.at(2).x())-1;
    r = max(v.at(0).x(), v.at(1).x(), v.at(2).x())+1;
    bom = min(v.at(0).y(), v.at(1).y(), v.at(2).y())-1;
    top = max(v.at(0).y(), v.at(1).y(), v.at(2).y())+1;
    // iterate through the pixel and find if the current pixel is inside the triangle
    bool Mass = true;
    if (Mass) {
        std::vector<Eigen::Vector2f> offset{
            { 0.1f, 0.2f},
            { 0.2f,-0.1f},
            {-0.2f, 0.1f},
            {-0.1f,-0.2f}
        };
        //得到三角形三个顶点,记录在res【3】中
        Eigen::Vector3f res[3];
        std::transform(std::begin(v), std::end(v), res,
            [](auto& vec) {
                return Eigen::Vector3f(vec.x(), vec.y(), vec.z());
            });
        for (int x = l;x <= r;x++) {
            for (int y = bom;y <= top;y++) {
                //if (!insideTriangle(x, y, res)) continue;
                int count = 0;//记录细分像素覆盖数量
                int maxcount = offset.size();
                for (int k = 0;k < maxcount;k++) {
                    if (insideTriangle(offset.at(k).x() + x, offset.at(k).y() + y , res)) {
                        ++count;
                    }
                }
                if (count) {
                    //计算(x,y)的深度
                    auto p = computeBarycentric2D(x, y, t.v);
                    float alpha = std::get<0>(p);
                    float beta = std::get<1>(p);
                    float gamma = std::get<2>(p);
                    float w_reciprocal = 1.0 / (alpha / v[0].w() + beta / v[1].w() + gamma / v[2].w());
                    float z_interpolated = alpha * v[0].z() / v[0].w() + beta * v[1].z() / v[1].w() + gamma * v[2].z() / v[2].w();
                    z_interpolated *= w_reciprocal;
                    if (z_interpolated < depth_buf[get_index(x, y)]) {//如果深度小,则MASS
                        Eigen::Vector3f color = t.getColor()* count / maxcount + frame_buf[get_index(x,y)]*(4-count)/4;
                        set_pixel(Eigen::Vector3f(x, y, z_interpolated), color );
                        depth_buf[get_index(x, y)] = z_interpolated;
                    }
                }
            }
        }
    }
    else {
        for (int x = l;x <= r;x++) {
            for (int y = bom;y <= top;y++) {
                Eigen::Vector3f res[3];
                std::transform(std::begin(v), std::end(v), res, [](auto& vec) { return Eigen::Vector3f(vec.x() + 0.5f, vec.y() + 0.5f, vec.z()); });
                if (insideTriangle(x, y, res)) {
                    //std::cout << x<<","<<y << std::endl;
                    // If so, use the following code to get the interpolated z value.
                    auto p = computeBarycentric2D(x, y, t.v);//我也不知道这个函数是在干嘛,反正最后用它得到了一个深度值
                    float alpha = std::get<0>(p);
                    float beta = std::get<1>(p);
                    float gamma = std::get<2>(p);
                    float w_reciprocal = 1.0 / (alpha / v[0].w() + beta / v[1].w() + gamma / v[2].w());
                    float z_interpolated = alpha * v[0].z() / v[0].w() + beta * v[1].z() / v[1].w() + gamma * v[2].z() / v[2].w();
                    z_interpolated *= w_reciprocal;
                    // TODO : set the current pixel (use the set_pixel function) to the color of the triangle 
                    //(use getColor function) if it should be painted.
                    if (z_interpolated < depth_buf[get_index(x, y)]) {
                        set_pixel(Eigen::Vector3f(x, y, z_interpolated), t.getColor());
                        depth_buf[get_index(x, y)] = z_interpolated;
                    }
                }
            }
        }
    }
}

FXAA(Fast Approximate AA)

在图像层面做的抗锯齿。快速的对有锯齿的图像做处理使得锯齿变的平滑。

TAA(Temporal AA)

将MSAA复用的像素分布在时间上(前几帧的像素上),用于动态模糊。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

games101,作业2 的相关文章

随机推荐

  • spring报错 XXX will not be managed by Spring

    如上提醒表示当前不是Spring管理着呢 是你的数据库插件Mybatis或者MybatisPlus给你管理呢 所以Spring给你温馨提醒了一下而已 又没有报错 解决的办法是在数据查找的方法上添加 Transactional 然后就会变成s
  • error LNK2005: _DllMain@12 已经在 MSVCRTD.lib(dllmain.obj) 中定义 找到一个或多个多重定义的符号

    今天在搞一个动态链接库的时候 出现了这样的错误 1 gt mfcs100ud lib dllmodul obj error LNK2005 DllMain 12 已经在 MSVCRTD lib dllmain obj 中定义 1 gt E
  • HTTPS之TLS1.2连接详解

    本文说一下HTTPS的会话连接详情 HTTPS连接除了正常的TCP三次连接 还引入了TLS连接 本文说的是基于 1 三次握手连接 首先通过三次握手连接来建立连接 接下来就是TLS连接 2 TLS第一次握手 ClientHello 客户端首先
  • Linux Kibana :nohup: 忽略输入并把输出追加到"nohup.out

    nohup 忽略输入并把输出追加到 nohup out 不要使用下面的命令启动 nohup kibana 改用 nohup kibana gt dev null 2 gt 1
  • 后台的BigDecimal字段,传到前端丢失精度问题

    后台的BigDecimal字段 传到前端丢失精度问题 后台的BigDecimal类型的字段 传到前端丢失精度 相关字段 private BigDecimal acreage 例如 该字段的值为 100 00 到前端就变成了 100 前端要求
  • HCNP路由交换学习指南--- 路由的基本概念

    文章目录 HCNP路由交换学习指南 路由的基本概念 交换机路由表学习 路由信息来源 路由的优先级 路由的度量值 HCNP路由交换学习指南 路由的基本概念 交换机路由表学习 路由是一种逐跳 HopByHop 的行为 也就是说 数据从源被发出直
  • 量化投资策略回测框架(一):胜率的估算

    上次简单介绍了回测之前的一些准备工作 这里 将进一步介绍如何对一个投资策略就行完整的回测 杂言 人啊 还是要做自己喜欢做的事情 勇于尝试 是非常好的 当感觉不合适的时候 要尽早跳出 年轻人 还是不要太安逸 所以从财富跳到了私募 事情也是自己
  • JWT解析库-nimbus-jose-jwt

    07 JWT解析库 nimbus jose jwt JWT解析库 nimbus jose jwt 是最受欢迎的JWT开源库 基于Apache2 0开源协议 支持所有标准的签名JWS和加密JWE算法 1 JWT JWS JWE是什么 1 1
  • Mac使用Appium连接真机与appium-inspector配置

    文章目录 1 配置Java SDK与Android SDK 2 连接真机 3 配置Appium与appium inspector安装 4 配置appium inspector 5 尝试连接 6 报错解决 gt No route found
  • 定时器控制数码管扫描显示

    功能 定时器控制两位数码管扫描显示 器件 STC12C5A32S2 两个数码管 include config h define uint unsigned int define uchar unsigned char define ulon
  • 一步步学习k8s(三)

    一步步学习k8s 三 将apollo交付到K8S中 apollp是携程公司开源的软件 apollp官网 https github com ctripcorp apollo 安装数据库 Mariadb 版本要高于10 1 对应mysql版本要
  • TrafficMonitor之Windows10监控小工具

    TrafficMonitor之Windows10监控小工具 安装 基本设置 软件下载地址 https gitee com xiaoha1234 soft ware blob master TrafficMonitor zip 1 基本设置
  • Swift学习笔记之---使用if和let处理空变量

    在Swift程序中 结合if和let 可以方便地处理空变量 nullable variable 使用可选绑定 optional binding 来判断可选类型是否包含值 如果包含就把值赋给一个临时常量或者变量 可选绑定可以用在if和whil
  • HashMap的get、put、resize过程

    get 1 先计算出key对应的hash值 2 对超出数组范围的hash值进行处理 3 根据正确的hash值 下标值 找到所在的链表的头结点 4 遍历链表 如果key值相等 返回对应的value值 否则返回null put 1 先计算出ke
  • 关于网络问题:WARNING: ROS_MASTER_URI [http://EPRobot:11311] host is not set to this machine

    关于网络问题 WARNING ROS MASTER URI http EPRobot 11311 host is not set to this machine 如果需要远程链接 需要在远程服务器将ROS MASTER URI变为启动ros
  • assimp批量转模型,[OpenGL] 使用Assimp导入模型(Qt)

    最近终于决定要在本身的demo中加入模型了 本次选择的是开源库Assimp 以前一直嫌麻烦没有去落实这件事 但实际上 assimp的配置意外的没有我想象中的那么麻烦 html 下载源码后 须要使用cmake进行编译 在上方选择源码位置 和b
  • RouterOS 动态IP接入上网设置教程(超详细)

    根据动态IP接入拓扑图对RouterOS做如下设置 首先启动RouterOS软路由 并且连接电脑 然后打开winbox登录ROS 1 正取区分内 外网 目的是为了方便记忆和区分 2 建立DHCP Client 客户端 进行自动获取外网IP地
  • 数据结构单链表之合并两个有序链表笔记。

    1 0题目描述 将两个升序链表合并为一个新的 升序 链表并返回 新链表是通过拼接给定的两个链表的所有节点组成的 2 0例子演示 输入 l1 1 2 4 l2 1 3 4 输出 1 1 2 3 4 4 示例 2 输入 l1 l2 输出 示例
  • react 之 umi(乌米)--入门介绍

    介绍 umi 中文可发音为乌米 是一个可插拔的企业级 react 应用框架 umi 以路由为基础的 支持类 next js 的约定式路由 以及各种进阶的路由功能 并以此进行功能扩展 比如支持路由级的按需加载 然后配以完善的插件体系 覆盖从源
  • games101,作业2

    需要补充的函数 rasterize triangle 执行三角形栅格化算法 static bool insideTriangle 测试点是否在三角形内 你可以修改此函 数的定义 这意味着 你可以按照自己的方式更新返回类型或函数参数 判断点是