当前位置: 首页 > news >正文

games101 作业2

题目

光栅化一个三角形
1. 创建三角形的 2 维 bounding box。
2. 遍历此 bounding box 内的所有像素(使用其整数索引)。然后,使用像素中心的屏幕空间坐标来检查中心点是否在三角形内。
3. 如果在内部,则将其位置处的插值深度值 (interpolated depth value) 与深度缓冲区 (depth buffer) 中的相应值进行比较。
4. 如果当前点更靠近相机,请设置像素颜色并更新深度缓冲区 (depth buffer)。

题解

本次作业需要实现代码框架中的两个接口:

void rst::rasterizer::rasterize_triangle(const Triangle& t);
static bool insideTriangle(int x, int y, const Vector3f* _v);

1. 在2D空间中,计算一个三角形的轴对称boundbox

只需要计算出三角形的三个顶点坐标中,x最大最小值,y最大最小值。即 ( x m i n , y m i n ) , ( x m a x , y m a x ) (x_{min},y_{min}),(x_{max},y_{max}) (xmin,ymin),(xmax,ymax)
使用<math.h>库实现如下:

    int xMin, yMin, xMax, yMax;xMin = std::floor(std::min(std::min(v[0].x(),v[1].x()),v[2].x()));yMin = std::floor(std::min(std::min(v[0].y(), v[1].y()), v[2].y()));xMax = std::ceil(std::max(std::max(v[0].x(), v[1].x()), v[2].x()));yMax = std::ceil(std::max(std::max(v[0].y(), v[1].y()), v[2].y()));

注意:顶点坐标都是浮点数,但是我们计算出的包围盒必须是整型。左上角下取整,右下角上去整。

2. 判断像素的中心点是否在三角形内部

其实方法有很多种,具体可以参考这个博客。
最常用最高效的有两种:重心坐标法和向量叉积。
本次作业选用向量叉积法:
代码如下

static bool insideTriangle(int x, int y, const Vector3f* _v)
{   // TODO : Implement this function to check if the point (x, y) is inside the triangle represented by _v[0], _v[1], _v[2]auto v0_v1 = _v[1] - _v[0];auto v1_v2 = _v[2] - _v[1];auto v2_v0 = _v[0] - _v[2];auto v0_P = Vector3f(x, y, _v[0].z()) - _v[0];auto v1_P = Vector3f(x, y, _v[1].z()) - _v[1];auto v2_P = Vector3f(x, y, _v[2].z()) - _v[2];auto v0pCross = v0_v1.cross(v0_P);auto v1pCross = v1_v2.cross(v1_P);auto v2pCross = v2_v0.cross(v2_P);if (v0pCross.dot(v1pCross) >= 0 && v0pCross.dot(v2pCross) >= 0)return true;return false;
}

因为我们判断的是一个像素的中心点是否在三角形内部,所以需要给x,y 分别加0.5,即insideTriangle(x+0.5,y+0.5,t.v)
注意:Vector3f Triangle::v[3] 中存放的就是三角形的三个顶点。

3.根据插值得到的深度值和深度缓冲的深度值比较。

插值运算使用代码框架,所以这块比较简单。
代码如下

     for (int i = xMin; i <= xMax; i++){for (int j = yMin; j <= yMax; j++){if (insideTriangle(i+0.5f, j+0.5f,t.v)){auto[alpha, beta, gamma] = computeBarycentric2D(i, j, t.v);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;int index = get_index(i, j);if (depth_buf[index] > z_interpolated){depth_buf[index] = z_interpolated; // 更新深度缓冲区set_pixel(Vector3f(i,j,z_interpolated),t.getColor());}}}}

注意:如果当前z值小于深度缓冲区的深度值,一定要更新深度缓冲区。

结果

在这里插入图片描述

代码:

static bool insideTriangle(int x, int y, const Vector3f* _v)
{   // TODO : Implement this function to check if the point (x, y) is inside the triangle represented by _v[0], _v[1], _v[2]auto v0_v1 = _v[1] - _v[0];auto v1_v2 = _v[2] - _v[1];auto v2_v0 = _v[0] - _v[2];auto v0_P = Vector3f(x, y, _v[0].z()) - _v[0];auto v1_P = Vector3f(x, y, _v[1].z()) - _v[1];auto v2_P = Vector3f(x, y, _v[2].z()) - _v[2];auto v0pCross = v0_v1.cross(v0_P);auto v1pCross = v1_v2.cross(v1_P);auto v2pCross = v2_v0.cross(v2_P);if (v0pCross.dot(v1pCross) >= 0 && v0pCross.dot(v2pCross) >= 0)return true;return false;
}void rst::rasterizer::rasterize_triangle(const Triangle& t) {auto v = t.toVector4();int xMin, yMin, xMax, yMax;xMin = std::floor(std::min(std::min(v[0].x(),v[1].x()),v[2].x()));yMin = std::floor(std::min(std::min(v[0].y(), v[1].y()), v[2].y()));xMax = std::ceil(std::max(std::max(v[0].x(), v[1].x()), v[2].x()));yMax = std::ceil(std::max(std::max(v[0].y(), v[1].y()), v[2].y()));for (int i = xMin; i <= xMax; i++){for (int j = yMin; j <= yMax; j++){if (insideTriangle(i+0.5f, j+0.5f,t.v)){auto[alpha, beta, gamma] = computeBarycentric2D(i, j, t.v);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;int index = get_index(i, j);if (depth_buf[index] > z_interpolated){depth_buf[index] = z_interpolated;set_pixel(Vector3f(i,j, z_interpolated),t.getColor());}}}}
}

参考文献
判断点是否在三角形内

相关文章:

games101 作业2

题目 光栅化一个三角形 1. 创建三角形的 2 维 bounding box。 2. 遍历此 bounding box 内的所有像素&#xff08;使用其整数索引&#xff09;。然后&#xff0c;使用像素中心的屏幕空间坐标来检查中心点是否在三角形内。 3. 如果在内部&#xff0c;则将其位置处的插值深度值 (…...

二叉树链式存储结构

目录 1.二叉树链式存储结构 2.二叉树的遍历 2.1 前、中、后序遍历 2.2 层序遍历 3.二叉树的其他递归问题 3.1 二叉树的结点个数 ​3.2 二叉树的叶子结点个数 3.3 二叉树第k层结点个数 3.4 二叉树的深度 3.5 二叉树查找 3.6 二叉树销毁 4.二叉树的基础OJ题 4.1 单值…...

Claude 使用指南 | 可与GPT-4媲美的语言模型

本文全程干货&#xff0c;让你轻松使用上claude&#xff0c;这也是目前体验cluade的唯一途径&#xff01;废话不多说&#xff0c;直接上教程&#xff0c;cluade的能力不逊于GPT4&#xff0c;号称是ChatGPT4.0最强竞品。相对Chatgpt来说&#xff0c;Claude不仅是完全免费的&…...

【汇编】微处理器

【汇编】微处理器 文章目录 【汇编】微处理器1、微处理器概念1.1 关键词1.2 分类 2、微处理器结构2.1 寄存器2.2 寄存器&汇编助记符2.3 寄存器组成结构 3、地址空间3.1 存储空间3.1.1 虚拟空间&#xff08;编程空间&#xff09;3.1.2 线性空间 3.2 I/O空间 4、工作模式4.1 …...

按键点亮led灯

原理图: K0这个按键按下时&#xff0c;开发板D1这个灯亮&#xff0c;松开&#xff0c;灯灭 代码如下: #include "stm32f4xx.h" void LED_Init(void) {//1.定义一个GPIO外设的结构体变量 GPIO_InitTypeDef GPIO_InitStructure;//RCC_AHB1PeriphClockCmd(RCC_AHB1Pe…...

Java常见面试题

目录 1、mysql并发事务会带来哪些问题&#xff0c;如何解决&#xff1f;2、请详细描述Redis持久化机制&#xff1f;3、简述Redis缓存雪崩和缓存穿透的问题和解决方案&#xff1f;4、RabbitMQ消息丢失及对应解决方案5、什么叫线程安全&#xff1f;举例说明6、举例说明常用的加密…...

笔记1.5:计算机网络体系结构

从功能上描述计算机网络结构 分层结构 每层遵循某个网络协议完成本层功能 基本概念 实体&#xff1a;表示任何可发送或接收信息的硬件或软件进程。 协议是控制两个对等实体进行通信的规则的集合&#xff0c;协议是水平的。 任一层实体需要使用下层服务&#xff0c;遵循本层…...

【Python】Python 连接字符串应优先使用 join 而不是 +

Python 连接字符串应优先使用 join 而不是 简介 字符串处理在大多数编程程序语言中都不可避免&#xff0c;字符串的连接也是在编程过程中经常需要面对的问题。 Python中的字符串与其他一些程序语言如C、Java有一些不同&#xff0c;它为不 可变对象。 一旦创建便不能改变&…...

uniapp 小程序 父组件调用子组件方法

答案&#xff1a;配合小程序API > this.selectComponent("")&#xff0c;来选择组件&#xff0c;再使用$vm选择组件实例&#xff0c;再调用方法&#xff0c;或者data 1 设置组件的id,如果你的多端&#xff0c;请跟据情况设置ref,class,id&#xff0c;以便通过小…...

Vue-01:MVVM数据双向绑定与Vue的生命周期

一、Vue介绍 1.1 什么是Vue &#xff1f; Vue是一个渐进式的JavaScript框架&#xff0c;用于构建用户界面。"渐进式"意味着Vue的设计理念是逐步增强应用的功能和复杂性&#xff0c;而不是一次性地引入所有功能。这使得开发者可以根据项目需求选择性地使用Vue的不同特…...

数据通信网络之OSPFv3基础

文章及资源归档至【AIShareLab】&#xff0c;回复 通信系统与网络 可获取。 文章目录 一、目的二、拓扑三、需求四、步骤 一、目的 掌握路由器的IPv6 基础配置。掌握OSPFv3&#xff08;单区域&#xff09;的基础配置。 二、拓扑 如图1 所示&#xff0c;三台路由器R1、R2 和R…...

FPGA-结合协议时序实现UART收发器(五):串口顶层模块UART_TOP、例化PLL、UART_FIFO、uart_drive

FPGA-结合协议时序实现UART收发器&#xff08;五&#xff09;&#xff1a;串口顶层模块UART_TOP、例化PLL、UART_FIFO、uart_drive 串口顶层模块UART_TOP、例化PLL、UART_FIFO、uart_drive&#xff0c;功能实现。 文章目录 FPGA-结合协议时序实现UART收发器&#xff08;五&…...

我学编程全靠B站了,真香-国外篇(第三期)

你好&#xff0c;我是Martin。 今天来点猛料&#xff0c;给大家推荐点我的压箱收藏-国外知名大学的公开课。 我推荐的不多&#xff0c;本着少就是多的原则&#xff0c;只给大家推荐我看过最好的五门视频&#xff0c;主要是来自两所国外高校&#xff1a;MIT美国麻省理工、CMU卡…...

c++ 变量常量指针练习题

Q1:在win32 x86模式下&#xff0c;int *p; int **pp; double *q; 请说明p、pp、q各占几个字节的内存单元。 p 占 4 个字节 pp 占 4 个字节 q 占 4 个字节 Q2常量1、1.0、“1”的数据类型是什么&#xff1f; 1 是 整形 int 1.0 是 浮点型 double “1” 是 const char * Q3 语句&…...

Linux底层基础知识

一.汇编&#xff0c;C语言&#xff0c;C&#xff0c;JAVA之间的关系 汇编&#xff0c;C语言&#xff0c;C可以通过不同的编译器&#xff0c;编译成机器码。而java只能由Java虚拟机识别。Java虚拟机可以看成一个操作系统&#xff0c;Java虚拟机是由汇编&#xff0c;C&#xff0c…...

JUC并发编程--------线程安全篇

目录 什么是线程安全性问题&#xff1f; 如何实现线程安全&#xff1f; 1、线程封闭 2、无状态的类 3、让类不可变 4、加锁和CAS 并发环境下的线程安全问题有哪些&#xff1f; 1、死锁 2、活锁 3、线程饥饿 什么是线程安全性问题&#xff1f; 我们可以这么理解&#…...

机器视觉之Basler工业相机使用和配置方法(C++)

basler工业相机做双目视觉用&#xff0c;出现很多问题记录一下&#xff1a; 首先是多看手册&#xff1a;https://zh.docs.baslerweb.com/software 手册内有所有的源码和参考示例&#xff0c;实际上在使用过程中&#xff0c;大部分都是这些源码&#xff0c;具体项目选择对应的…...

Centos nginx配置文档

1、安装nginx: yum install nginx 2、Nginx常用命令 查看版本:nginx -v 启动:nginx -c /etc/nginx/nginx.conf 重新加载配置:nginx -s reload 停止:nginx -s stop 3、Nginx反向代理配置 nginx配置详解 1、Nginx配置图 详情可以查看:http://nginx.org/ru/docs/example…...

2023/9/14 -- C++/QT

作业&#xff1a; 仿照Vector实现MyVector&#xff0c;最主要实现二倍扩容 #include <iostream>using namespace std;template <typename T> class MyVector { private:T *data;size_t size;size_t V_capacity; public://无参构造MyVector():data(nullptr),size(…...

golang在goland编译时获取环境变量失效

在golang中&#xff0c; 我们通常使用os包来获取环境变量&#xff0c;如&#xff1a; os.Getenv() os.LookupEnv() 等。 但如果我们使用goland编译器&#xff0c;在编译是&#xff0c;这时操作环境变量&#xff0c;会发现os包读取到的环境变量值不变&#xff1a; 新增后&am…...

flac3d台阶法开挖命令流,5.0版本,计算结果有效合理,支护方式为初衬单元与锚杆联合支护...

flac3d台阶法开挖命令流&#xff0c;5.0版本&#xff0c;计算结果有效合理&#xff0c;支护方式为初衬单元与锚杆联合支护&#xff0c;初衬采用shell单元&#xff0c;锚杆为cable单元&#xff0c;可为相关计算提供参考 直接开整吧&#xff01;最近在搞隧道台阶法开挖模拟&#…...

OpenClaw/阿里copaw/阿里QoderWork/腾讯Qclaw/腾讯workbuddy综合对比

1、功能介绍 核心能力&#xff1a;自然语言交互、本地文件操作、代码执行 支持模型&#xff1a;Qwen、Deepseek、OpenAI 等主流厂家模型均支持&#xff08;硬件条件允许&#xff0c;也可通过ollama连接本地模型&#xff09; 机器人助手&#xff1a;飞书、企业微信、QQ等创建…...

《信息系统项目管理师教程(第4版)》——成本管理知识要点

成本管理知识要点一、成本管理基础概念 项目成本管理是为确保项目在批准预算内完成&#xff0c;对成本进行规划、估算、预算、融资、筹资、管理和控制的过程。其核心目标是平衡成本与价值&#xff0c;既关注项目活动所需资源的成本&#xff0c;也考虑项目决策对产品/服务后续使…...

RK平台USB调试避坑指南:当你的U盘插上没反应时,先检查这三点(PHY/供电/DTS)

RK平台USB调试实战&#xff1a;从PHY供电到DTS配置的深度排障手册 当你把U盘插入RK3588开发板的USB接口&#xff0c;系统却毫无反应——这种场景对嵌入式工程师来说再熟悉不过。上周我在调试一块RK3568核心板时&#xff0c;就遇到了完全相同的困境&#xff1a;硬件焊接经过三遍…...

嵌入式系统链接器脚本(ld文件)详解

嵌入式系统中的链接器脚本(ld文件)深度解析1. 链接器脚本概述链接器脚本(linker script)是控制链接过程的关键文件&#xff0c;通常以.lds作为文件后缀名。它主要规定了如何将输入文件中的section放入输出文件&#xff0c;并控制输出文件内各部分在程序地址空间中的布局。每个链…...

ai辅助开发对比:github copilot与快马多模型在学生项目中的表现

最近在折腾学生项目时&#xff0c;发现AI编程助手的选择越来越多。作为通过GitHub学生认证的开发者&#xff0c;原本一直用Copilot当主力工具&#xff0c;但偶然接触到InsCode(快马)平台的多模型支持后&#xff0c;突然想做个系统性对比。于是花了周末时间搭建了个AI辅助开发评…...

Qt 数据QByteArray与QString高效转换实战技巧

1. QByteArray与QString的本质区别 在Qt开发中&#xff0c;QByteArray和QString这两个类经常让新手开发者感到困惑。我第一次接触Qt时&#xff0c;也曾经把两者混为一谈&#xff0c;结果在中文显示时出现了乱码问题。后来才发现&#xff0c;它们的根本区别在于&#xff1a;QByt…...

RMBG-2.0实战教程:结合FFmpeg实现‘原图→去背→合成视频’流水线

RMBG-2.0实战教程&#xff1a;结合FFmpeg实现‘原图→去背→合成视频’流水线 1. 引言&#xff1a;从单张抠图到批量视频合成 如果你用过RMBG-2.0&#xff0c;一定会被它精准的抠图效果惊艳到。它能轻松地把照片里的人或物“抠”出来&#xff0c;背景变得干干净净。但你想过没…...

清华大学提出统一多模态模型新突破:让AI同时学会“看“和“画“

这项由清华大学、西安交通大学和中科院大学联合开展的研究发表于2026年的arXiv预印本&#xff08;论文编号&#xff1a;arXiv:2603.12793v1&#xff09;&#xff0c;研究团队开发了一个名为CHEERS的全新AI模型&#xff0c;能够同时具备图像理解和图像生成两种截然不同的能力。对…...

STM32水质检测系统设计与实现

基于STM32的水质检测系统设计与实现1. 项目概述1.1 系统架构本水质检测系统采用模块化设计架构&#xff0c;以STM32F103RCT6微控制器为核心&#xff0c;集成多种水质参数传感器、显示模块和无线通信模块。系统硬件架构分为三个主要层次&#xff1a;传感层&#xff1a;包含水温、…...