3.8【Q】cv
这个draw_line函数的逻辑和功能是什么?代码思路是什么?怎么写的?
这个t是什么?t.v[0]和t.v[1],[2]又是什么?
void rst::rasterizer::draw(rst::pos_buf_id pos_buffer, rst::ind_buf_id ind_buffer, rst::Primitive type)
{if (type != rst::Primitive::Triangle){throw std::runtime_error("Drawing primitives other than triangle is not implemented yet!");}auto& buf = pos_buf[pos_buffer.pos_id];auto& ind = ind_buf[ind_buffer.ind_id];float f1 = (100 - 0.1) / 2.0;float f2 = (100 + 0.1) / 2.0;Eigen::Matrix4f mvp = projection * view * model;for (auto& i : ind){Triangle t;Eigen::Vector4f v[] = {mvp * to_vec4(buf[i[0]], 1.0f),mvp * to_vec4(buf[i[1]], 1.0f),mvp * to_vec4(buf[i[2]], 1.0f)};for (auto& vec : v) {vec /= vec.w();}for (auto & vert : v){vert.x() = 0.5*width*(vert.x()+1.0);vert.y() = 0.5*height*(vert.y()+1.0);vert.z() = vert.z() * f1 + f2;}for (int i = 0; i < 3; ++i){t.setVertex(i, v[i].head<3>());t.setVertex(i, v[i].head<3>());t.setVertex(i, v[i].head<3>());}t.setColor(0, 255.0, 0.0, 0.0);t.setColor(1, 0.0 ,255.0, 0.0);t.setColor(2, 0.0 , 0.0,255.0);rasterize_wireframe(t);}
}
这个draw函数的输入参数都是什么?有什么意义?内部处理逻辑是什么?
void rst::rasterizer::rasterize_triangle(const Triangle& t) {auto v = t.toVector4();// TODO : Find out the bounding box of current triangle.// iterate through the pixel and find if the current pixel is inside the triangle// If so, use the following code to get the interpolated z value.//auto[alpha, beta, gamma] = computeBarycentric2D(x, y, 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;// TODO : set the current pixel (use the set_pixel function) to the color of the triangle (use getColor function) if it should be painted.
}
这里为什么有一个“ auto v = t.toVector4();”操作?作用是什么?
什么叫“支持透视投影下的正确深度插值和透视校正属性插值”?还是没理解,形象地说明?为什么要拓展到四维?
void rst::rasterizer::rasterize_triangle(const Triangle& t) {auto& v0 = t.v;auto& v1 = t.v;auto& v2 = t.v;// 计算三角形的包围盒float min_x = std::min({v0.x(), v1.x(), v2.x()});float max_x = std::max({v0.x(), v1.x(), v2.x()});float min_y = std::min({v0.y(), v1.y(), v2.y()});float max_y = std::max({v0.y(), v1.y(), v2.y()});
这些 v0,v1,v2是什么意思?原代码里写的不是 auto v = t.toVector4();吗?
void rst::rasterizer::rasterize_triangle(const Triangle& t) {auto v = t.toVector4();// 计算包围盒float min_x = std::min({t.a().x(), t.b().x(), t.c().x()});float max_x = std::max({t.a().x(), t.b().x(), t.c().x()});float min_y = std::min({t.a().y(), t.b().y(), t.c().y()});float max_y = std::max({t.a().y(), t.b().y(), t.c().y()});// 转换为整数像素范围并钳位int x_begin = std::max(static_cast<int>(std::floor(min_x)), 0);int x_end = std::min(static_cast<int>(std::ceil(max_x)), width);int y_begin = std::max(static_cast<int>(std::floor(min_y)), 0);int y_end = std::min(static_cast<int>(std::ceil(max_y)), height);// 遍历包围盒内的所有像素for (int x = x_begin; x < x_end; ++x) {for (int y = y_begin; y < y_end; ++y) {float center_x = x + 0.5f;float center_y = y + 0.5f;if (insideTriangle(center_x, center_y, t)) {// 计算重心坐标Eigen::Vector2f A(v0.x(), v0.y());Eigen::Vector2f B(v1.x(), v1.y());Eigen::Vector2f C(v2.x(), v2.y());Eigen::Vector2f P(center_x, center_y);float denominator = (B.y() - C.y()) * (A.x() - C.x()) + (C.x() - B.x()) * (A.y() - C.y());if (denominator == 0) continue;float u = ((B.y() - C.y()) * (P.x() - C.x()) + (C.x() - B.x()) * (P.y() - C.y())) / denominator;float v = ((C.y() - A.y()) * (P.x() - C.x()) + (A.x() - C.x()) * (P.y() - C.y())) / denominator;float w = 1 - u - v;if (u >= 0 && v >= 0 && w >= 0) {// 插值深度float z_interpolated = u * v0.z() + v * v1.z() + w * v2.z();int index = get_index(x, y);// 深度测试if (z_interpolated < depth_buf[index]) {// 颜色插值Eigen::Vector3f color = u * t.color + v * t.color + w * t.color;set_pixel(Eigen::Vector3f(x, y, 1.0f), color);depth_buf[index] = z_interpolated;}}}}} // TODO : Find out the bounding box of current triangle.// iterate through the pixel and find if the current pixel is inside the triangle// If so, use the following code to get the interpolated z value.//auto[alpha, beta, gamma] = computeBarycentric2D(x, y, 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;// TODO : set the current pixel (use the set_pixel function) to the color of the triangle (use getColor function) if it should be painted.
}
在遍历包围盒内所有像素时,为什么要定义出center_x和center_y?在计算重心坐标时,各行代码操作的意义和作用又是什么?
在
void rst::rasterizer::rasterize_triangle(const Triangle& t) {
auto v = t.toVector4();中,为什么一开始要定义出一个v?v在后续的计算中有什么用?
这个v的w维度,是在传入t后进行扩展的,并没有经过mvp矩阵的变化,那么三个点的w维度上的值不都是1吗?后面 float w_reciprocal = 1.0 / (alpha / v[0].w() + beta / v[1].w() + gamma / v[2].w());又有什么意义?
不是,mvp矩阵是在draw函数中进行计算的,在draw函数最后调用了rasterize_triangle(t);,在rasterize_triangle(t);中配置auto v = t.toVector4();,那么t的第四维度w不该是1吗?mvp矩阵并没有在此时发挥作用?
static bool insideTriangle(int x, int y,const Vector3f* _v)
{ Vector3f P(x+0.5f,y+0.5f,1.0f);const Vector3f& A = _v[0];const Vector3f& B = _v[1];const Vector3f& C = _v[2];// 计算三个边的向量和点P到顶点的向量Vector3f AB = B - A;Vector3f BC = C - B;Vector3f CA = A - C;Vector3f AP = P - A;Vector3f BP = P - B;Vector3f CP = P - C;// 计算叉积符号float cross1 = AB.cross(AP).z();float cross2 = BC.cross(BP).z();float cross3 = CA.cross(CP).z();// 检查符号是否一致return (cross1 > 0 && cross2 > 0 && cross3 > 0) || (cross1 < 0 && cross2 < 0 && cross3 < 0);// TODO : Implement this function to check if the point (x, y) is inside the triangle represented by _v[0], _v[1], _v[2]
}
这段代码能实现判断点是否在内外部的原理是什么?cross1等取z是什么意思?有什么意义?
为什么Vector3f P(x+0.5f,y+0.5f,1.0f);可以确保测试点为像素中心?什么叫像素中心?为什么要保证在像素中心?
static std::tuple<float, float, float> computeBarycentric2D(float x, float y, const Vector3f* v)
{float c1 = (x*(v[1].y() - v[2].y()) + (v[2].x() - v[1].x())*y + v[1].x()*v[2].y() - v[2].x()*v[1].y()) / (v[0].x()*(v[1].y() - v[2].y()) + (v[2].x() - v[1].x())*v[0].y() + v[1].x()*v[2].y() - v[2].x()*v[1].y());float c2 = (x*(v[2].y() - v[0].y()) + (v[0].x() - v[2].x())*y + v[2].x()*v[0].y() - v[0].x()*v[2].y()) / (v[1].x()*(v[2].y() - v[0].y()) + (v[0].x() - v[2].x())*v[1].y() + v[2].x()*v[0].y() - v[0].x()*v[2].y());float c3 = (x*(v[0].y() - v[1].y()) + (v[1].x() - v[0].x())*y + v[0].x()*v[1].y() - v[1].x()*v[0].y()) / (v[2].x()*(v[0].y() - v[1].y()) + (v[1].x() - v[0].x())*v[2].y() + v[0].x()*v[1].y() - v[1].x()*v[0].y());return {c1,c2,c3};
}
这个函数是在干什么?有什么用?传入参数的意义和输出是什么意思?
std::tie(alpha, beta, gamma) = tup;
这句什么意思?tie什么意思?
//MSAA 4Xif (MSAA) {// 格子里的细分四个小点坐标std::vector<Eigen::Vector2f> pos{{0.25,0.25},{0.75,0.25},{0.25,0.75},{0.75,0.75},};for (int x = min_x; x <= max_x; x++) {for (int y = min_y; y <= max_y; y++) {// 记录最小深度float minDepth = FLT_MAX;// 四个小点中落入三角形中的点的个数int count = 0;// 对四个小点坐标进行判断 for (int i = 0; i < 4; i++) {// 小点是否在三角形内if (insideTriangle((float)x + pos[i][0], (float)y + pos[i][1], t.v)) {// 如果在,对深度z进行插值auto tup = computeBarycentric2D((float)x + pos[i][0], (float)y + pos[i][1], t.v);float alpha;float beta;float gamma;// std::tie表示打散tup到 alpha beta gamma三个分量std::tie(alpha, beta, gamma) = tup;// reciprocal 倒数float w_reciprocal = 1.0 / (alpha / v[0].w() + beta / v[1].w() + gamma / v[2].w());// 按照三角形三个点的权重,对当前点插值,求出z值,注意,这里的reciprocal用的有点莫名其妙,先不用管// 而且alpha beta gamma用起来是需要矫正的// 此处留个疑问:为什么不能在投影变换时,求出每个点的z坐标映射值呢?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;// 求出当前点中四个小点对应的深度,以代表当前点的z值,用来和其他点的z做对比minDepth = std::min(minDepth, z_interpolated);// 包含一个点count +1count++;}}if (count != 0) {if (depth_buf[get_index(x, y)] > minDepth) {// 简单的对color/4也可以,处理的比较粗糙。// 注意getColor其实就只用了一个值,三角形三个点的颜色相同// 这里还考虑了当前缓冲里面存贮的颜色值Vector3f color = t.getColor()*count/4 + (4-count)*frame_buf[get_index(x,y)]/4;Vector3f point(3);point << (float)x, (float)y, minDepth;// 替换深度depth_buf[get_index(x, y)] = minDepth;// 修改颜色set_pixel(point, color);}}}}}
详细解释这段代码每一句的作用和意义?如何实现MSAA抗锯齿的?
Vector3f color = t.getColor()*count/4 + (4-count)*frame_buf[get_index(x,y)]/4;这个color的计算是什么意思?怎么做的?
为什么不能在投影变换时,求出每个点的z坐标映射值呢?什么意思?思路是什么?
当前代码开启了超采样,但是if (count != 4)std::cout << "current count test: " << count << '\n';并没有输出,说明count要么是0要么是4,为什么会发生这种情况?为什么?如何处理?使其去锯齿?
就是这个函数static bool insideTriangle(float x, float y,const Vector3f* _v)的传入参数一开始设置为int的原因;此外,想要进一步提升抗锯齿的效果,该怎么做?给出修改代码
/ 修改后的抗锯齿核心逻辑
void rst::rasterizer::rasterize_triangle(const Triangle& t) {auto v = t.toVector4();// 8x旋转采样点布局std::vector<Eigen::Vector2f> pos { /* 上述8个点 */ };// 包围盒扩展(增加1像素冗余)min_x = static_cast<int>(std::floor(min_x - 1.0f));max_x = static_cast<int>(std::ceil(max_x + 1.0f));for (int x = min_x; x <= max_x; x++) {for (int y = min_y; y <= max_y; y++) {int count = 0;float minDepth = FLT_MAX;// 第一层8x采样for (int i=0; i<8; ++i) {float sx = x + pos[i][0], sy = y + pos[i][1];if (insideTriangle(sx, sy, t.v)) {// 计算深度...count++;}}// 边缘区域二次采样if (count>0 && count<8) {std::vector<Eigen::Vector2f> edge_pos {/* 4个点 */};for (auto& ep : edge_pos) {if (insideTriangle(x+ep[0], y+ep[1], t.v)) count++;}}// 深度加权颜色混合if (count > 0) {float weight = count / 12.0; // 最大12采样Vector3f color = /* 加权混合公式 */;set_pixel(point, color);}}}// 后处理阶段post_process();
}
完成这个代码里省略的部分
增加采样数量后,在原来4*的基础上,8*的图形边缘出现了黑边,且抗锯齿效果并没有显著提升,甚至有所倒退,这是为什么?
相关文章:
3.8【Q】cv
这个draw_line函数的逻辑和功能是什么?代码思路是什么?怎么写的? 这个t是什么?t.v[0]和t.v[1],[2]又是什么? void rst::rasterizer::draw(rst::pos_buf_id pos_buffer, rst::ind_buf_id ind_buffer, rst::Primitive ty…...
STM32F10XXX标准库函数及外设结构体
时钟 APB1 void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState):使能或失能 APB1 时钟 参数 可赋值 描述 RCC_APB1Periph RCC_APB1Periph_TIM2 RCC_APB1Periph_TIM3 RCC_APB1Periph_TIM4 RCC_APB1Periph_TIM5 RCC_APB1Peri…...
计算机毕业设计SpringBoot+Vue.js车辆管理系统(源码+文档+PPT+讲解)
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...
剖析Manus:AI领域的创新先锋还是虚假泡沫?
在AI技术迅猛发展的当下,新的智能体不断涌现,其中Manus的出现可谓是一石激起千层浪。近期,OpenManus以极快速度复刻Manus,引发了广泛关注,但这也让我们更有必要深入剖析Manus,探究它究竟是货真价实的创新突…...
编程考古-Borland历史:《.EXE Interview》对Anders Hejlsberg关于Delphi的采访内容(中)
为了纪念Delphi在2002年2月14日发布的25周年(2020.2.12),这里有一段由.EXE杂志编辑Will Watts于1995年对Delphi首席架构师Anders Hejlsberg进行的采访记录。在这次采访中,Anders讨论了Delphi的设计与发展,以及即将到来的针对Windows 95的32位版本。 Q. 编译器引擎本身是用…...
GB28181视频平台LiveGBS在设置公网IP收流时,如何自定义修改收流端口区间
LiveGBS GB28181流媒体服务在接收视频的时候默认是使用30000-30249, webrtc流播放端口区间默认是UDP的30250-30500区间。有些网络环境不方便开放这么大的端口区间,下面介绍下如何修改配置这个区间。 从页面上修改这个区间,端口区间尽量设置大…...
【ubuntu20】--- 搭建 gerrit 最新最详细
在编程的艺术世界里,代码和灵感需要寻找到最佳的交融点,才能打造出令人为之惊叹的作品。而在这座秋知叶i博客的殿堂里,我们将共同追寻这种完美结合,为未来的世界留下属于我们的独特印记。 【ubuntu20】--- 搭建 gerrit 最新最详细…...
HCIA-DHCP
1、定义:DHCP即动态主机配置协议,通过C/S模型架构,无需主机配置IP地址,自动分配网络配置参数的网络协议。 2、作用 对比项目无 DHCP有 DHCP配置难度配置多,容易出错自动为客户端分配 IP 地址及其他网络配置参数&…...
wxWidgets GUI 跨平台 入门学习笔记
准备 参考 https://wiki.wxwidgets.org/Microsoft_Visual_C_NuGethttps://wiki.wxwidgets.org/Tools#Rapid_Application_Development_.2F_GUI_Buildershttps://docs.wxwidgets.org/3.2/https://docs.wxwidgets.org/latest/overview_helloworld.htmlhttps://wizardforcel.gitb…...
OmniParser技术分析(一)
1.引言 通过上篇文章介绍 OmniParser:下一代纯视觉UI自动化测试先驱相信大家已经对OmniParser有初步了解,接下来详细介绍下OmniParser使用了哪些技术模型实现了对UI纯视觉的检测和理解。 2.整体方案 通过阅读OmniParser提供的运行Demo代码知道,其实整…...
什么是hive
Apache Hive 是一个基于 Hadoop 生态系统构建的数据仓库工具,主要用于处理和分析大规模的结构化数据。它允许用户通过类似 SQL 的查询语言(HiveQL)进行数据操作,而无需直接编写复杂的 MapReduce 程序。以下是 Hive 的核心特点和应…...
PyTorch系列教程:Tensor.view() 方法详解
这篇简明扼要的文章是关于PyTorch中的tensor.view()方法的介绍与应用,与reshape()方法的区别,同时给出示例进行详细解释。 Tensor基础 Tensor(张量)的视图是一个新的Tensor,它与原始Tensor共享相同的底层数据,但具有不同的形状或…...
从零开始了解Manus(文末附教程)
大家好,我是樱木。 《从零开始了解Manus》,这个教程对于想了解 Manus的同学,全部都在里面了! Manus 是一款能像真人一样帮你干活的AI助手,运行在云端,不占电脑内存。 它可以自动完成复杂任务,…...
不同开发语言之for循环的用法、区别总结
一、Objective-C (1)标准的c风格 for (int i 0; i < 5; i) {NSLog("i %d", i); } (2)for in循环。 NSArray *array ["apple", "banana", "orange"]; for (NSString *fruit in …...
CentOS 7 aarch64上制作kernel rpm二进制包 —— 筑梦之路
环境说明 centos 7 aarch64 gcc 8.3.1 kernel 5.4.290 准备编译制作 # 安装必要的工具和包yum install rpm-devel rpmdevtools yum groupinstall "Development Tools"yum install ncurses-devel bc elfutils-libelf-devel openssl-devel # 安装gcc 8.3.1# 修改…...
Cursor 使用经验,一个需求开发全流程
软件开发中 Cursor 的使用经验成为关注焦点,尤其是处理大型数据集的需求。用户提到“Cursor 使用经验,一个需求开发全流程”,但“Cursor”可能指数据库游标,涉及逐行处理数据。本文将详细探讨开发一个需求的完整流程,包…...
2025-03-08 学习记录--C/C++-PTA 习题9-2 计算两个复数之积
合抱之木,生于毫末;九层之台,起于累土;千里之行,始于足下。💪🏻 一、题目描述 ⭐️ 二、代码(C语言)⭐️ #include <stdio.h>struct complex{int real;int imag; …...
DeepSeek-R1本地化部署(Mac)
一、下载 Ollama 本地化部署需要用到 Ollama,它能支持很多大模型。官方网站:https://ollama.com/ 点击 Download 即可,支持macOS,Linux 和 Windows;我下载的是 mac 版本,要求macOS 11 Big Sur or later,Ol…...
【时时三省】(C语言基础)赋值语句
山不在高,有仙则名。水不在深,有龙则灵。 ----CSDN 时时三省 赋值语句 在C程序中,最常用的语句是:赋值语句和输入输出语句。其中最基本的是赋值语句程序中的计算功能大部分是由赋值语句实现的,几乎每一个有实用价值的程序都包括赋值语句。有的程序中的大部分语句都是赋值…...
如何提取图片文字
如何分析图片风格: 分析下图片是什么风格,用即梦AI的提示语描述。我要使用描述语去即梦生成同样的图...
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以? 在 Golang 的面试中,map 类型的使用是一个常见的考点,其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...
五年级数学知识边界总结思考-下册
目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解:由来、作用与意义**一、知识点核心内容****二、知识点的由来:从生活实践到数学抽象****三、知识的作用:解决实际问题的工具****四、学习的意义:培养核心素养…...
P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...
苍穹外卖--缓存菜品
1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据,减少数据库查询操作。 缓存逻辑分析: ①每个分类下的菜品保持一份缓存数据…...
高危文件识别的常用算法:原理、应用与企业场景
高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...
ServerTrust 并非唯一
NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...
Spring Boot面试题精选汇总
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...
【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)
升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点,但无自动故障转移能力,Master宕机后需人工切换,期间消息可能无法读取。Slave仅存储数据,无法主动升级为Master响应请求ÿ…...
IP如何挑?2025年海外专线IP如何购买?
你花了时间和预算买了IP,结果IP质量不佳,项目效率低下不说,还可能带来莫名的网络问题,是不是太闹心了?尤其是在面对海外专线IP时,到底怎么才能买到适合自己的呢?所以,挑IP绝对是个技…...
RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)
RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发,后来由Pivotal Software Inc.(现为VMware子公司)接管。RabbitMQ 是一个开源的消息代理和队列服务器,用 Erlang 语言编写。广泛应用于各种分布…...
