GAMES101-Assignment4

2024-01-09 23:52
文章标签 games101 assignment4

本文主要是介绍GAMES101-Assignment4,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、问题总览

实现de Casteljau算法来绘制由4个控制点表示的Bézier曲线。需要修改main.cpp中的如下函数:

  • bezier:该函数实现绘制Bézier曲线的功能。它使用一个控制点序列和一个OpenCV::Mat对象作为输入,没有返回值。它会使t在0到1的范围内进行迭代,并在每次迭代中使t增加一个微小值。对于每个需要计算的t,将调用另一个函数recursive_bezier,然后该函数将返回在Bézier曲线上t处的点。最后,将返回的点绘制在OpenCV::Mat 对象上。
  • recursive_bezier:该函数使用一个控制点序列和一个浮点数t作为输入,实现de Casteljau 算法来返回Bézier曲线上对应点的坐标。

二、参考答案

2.1 算法思想

De Casteljau 算法说明如下:

  1. 考虑一个p0, p1, … pn 为控制点序列的Bézier曲线。首先,将相邻的点连接
    起来以形成线段。
  2. 用t : (1 − t) 的比例细分每个线段,并找到该分割点。
  3. 得到的分割点作为新的控制点序列,新序列的长度会减少一。
  4. 如果序列只包含一个点,则返回该点并终止。否则,使用新的控制点序列并转到步骤1。

使用[0,1] 中的多个不同的t来执行上述算法

  • 例子如下
    在这里插入图片描述

    • b 0 b_0 b0, b 1 b_1 b1, b 2 b_2 b2为三个参考点;
      • b 0 b 1 b_0b_1 b0b1 上找一点 b 0 1 b_0^1 b01,使得 b 0 b 0 1 b_0b_0^1 b0b01 : b 0 1 b 1 b_0^1b_1 b01b1 = t : (1 - t)
      • b 1 1 b_1^1 b11 同理
    • b 0 1 b_0^1 b01 b 1 1 b_1^1 b11 作为新的参考点,找点 b 0 2 b_0^2 b02,使比例关系满足t : (1 - t)
    • b 0 2 b_0^2 b02 就是贝塞尔曲线上的一点,使用[0,1] 中的多个不同的t来执行上述算法

2.2 代码实现

2.2.1 Bezier函数的实现

  • t=0 -> t=1, 调用de Casteljau算法
//cv::Mat &window:表示屏幕矩阵;矩阵内元素为CV_8UC3类型(无符号8位整数,RGB三通道,cv::Vec3b)
void bezier(const std::vector<cv::Point2f> &control_points, cv::Mat &window) 
{// TODO: Iterate through all t = 0 to t = 1 with small steps, and call de Casteljau's // recursive Bezier algorithm.for(double t = 0.0; t < 1.0; t += 0.001){cv::Point2f point = recursive_bezier(control_points, t);// 绘制坐标(point.y, point.x)的颜色为绿色,[1]表示RGB中的Gwindow.at<cv::Vec3b>(point.y, point.x)[1] = 255;}
}

2.2.2 Recursive_bezier函数的实现

  • 实现de Casteljau 算法来返回Bézier曲线上对应点的坐标
//cv::Point2f  float类型的二维点坐标
cv::Point2f recursive_bezier(const std::vector<cv::Point2f> &control_points, float t) 
{// TODO: Implement de Casteljau's algorithmif(control_points.size() == 1) return control_points[0];std::vector<cv::Point2f> next_layer_control_points;for(int i = 0; i < control_points.size() - 1; i++){cv::Point2f p0 = control_points[i];cv::Point2f p1 = control_points[i+1];cv::Point2f p2 = p0 + t * (p1 - p0);next_layer_control_points.push_back(p2);}return recursive_bezier(next_layer_control_points, t);
}

2.2.3 实现对贝塞尔曲线的反走样(奖励分数)

  • 对于一个曲线上的点,不只把它对应于一个像
    素,需要根据到像素中心的距离来考虑与它相邻的像素的颜色
    在这里插入图片描述

    • P是贝塞尔曲线上t对应的一点,P0是周围四个像素区域的交点,像素框的中心点为其余四个黑点
    • 像素外框都是处于window矩阵整数部分(默认一个window单元格为一个像素),所以p所在的像素框的较近一竖边为min(floor(p.x), ceil(p.x)),横边min(floor(p.y), ceil(p.y))
      • 计算出p0坐标( min(floor(p.x), ceil(p.x)),min(floor(p.y), ceil(p.y)) )
    • 由于像素框大小为1 * 1,所以知道P0之后可以计算出周围四个像素中心点坐标
    • 根据像素中心点到P点的距离来分配颜色
      • 比如距离p点距离为dist,则该点所在像素的G通道 = 255 * (3 - dist)/3
        • 使用的是哈夫曼距离,p离像素中心点最大哈夫曼距离为3
double get_dist(cv::Point2f point1, cv::Point2f point2){//计算两点的哈夫曼距离return fabs(point1.x - point2.x) + fabs(point1.y - point2.y);
}//cv::Mat &window:表示屏幕矩阵;矩阵内元素为CV_8UC3类型(无符号8位整数,RGB三通道,cv::Vec3b)
void bezier(const std::vector<cv::Point2f> &control_points, cv::Mat &window) 
{// TODO: Iterate through all t = 0 to t = 1 with small steps, and call de Casteljau's // recursive Bezier algorithm.for(double t = 0.0; t < 1.0; t += 0.001){cv::Point2f point = recursive_bezier(control_points, t);cv::Point2f point0( std::min(floor(point.x), ceil(point.x)), std::min(floor(point.y), ceil(point.y)) );double dist;std::vector<double> bias{0.5, -0.5};for(int i = 0; i < 4; i++){cv::Point2f centerPoint(point0.x + bias[i % 2], point0.y + bias[i % 2]);//计算中心点dist = get_dist(point, centerPoint);window.at<cv::Vec3b>(centerPoint.y, centerPoint.x)[1] = 255 * (3 - dist) / 3;} }
}

三、编译

如往常一样

$ mkdir build
$ cd build
$ cmake ..
$ make$ ./BezierCurve  

通过点击屏幕来设置控制点


附件

作业4连接

这篇关于GAMES101-Assignment4的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/588856

相关文章

GAMES101(5~6节,光栅化)

光栅化Rasterization 透视投影已知field和近平面,如何推导宽度? 根据三角函数:tan field / 2 = (height / 2) / ||n||近平面,从而可以求出高度 因为知道宽高比,所以可以求出宽度,高度 * 宽/高 视口变换 经过MVP变换,顶点位于正则化空间坐标,是一个在 [-1,1] ^3 之间的 x, y, z 坐标构成(标准立方体),我们下一步需要做

Games101学习 - 线性代数综述

1. 叉积矩阵形式 叉乘矩阵形式通常在物理模拟中有运用,处理四元数旋转也类似这样的形式。 // 定义两个向量 A 和 BFVector A(1.0f, 2.0f, 3.0f);FVector B(4.0f, 5.0f, 6.0f);// 计算叉积FVector CrossProduct = FVector::CrossProduct(A, B);if (GEngine){GEngine

GAMES101图形学笔记1

一、图形学的应用 1.游戏渲染、光照 2.电影特效 3.面部、动作捕捉,如Avatar(阿凡达)中的面部捕捉 4.设计 建筑设计,汽车设计 5.虚拟现实VR 增强现实AR 6.数码插画 笔刷 PS软件等 7.模拟、仿真 8.GUI 界面设计等 9.字体设计typography 二、为什么学习图形学 1.图形学是一门Awesome的学科,能够创造很多有意思的东西,有意思的图像 2.了解并学习一

Games101-动画与模拟(求解常微分方程,刚体与流体)

Single Particle Simulation 规定了任何一个物体任何时刻的速度,知道它的初始位置,求它某个时间后的位置? 如果一个物体是匀速直线运动,用初始位置加上速度和时间的乘积即可 如上图,如果想描述一个粒子在一个速度场(理想的情况:只要知道位置,就知道它这个时刻的速度)中如何运动 任何一个粒子在上面的速度场会沿着类似水流的方向往前走 任何一个位置x和任何时间t,都知道有一个速度

Games101-相机与透镜

成像:光栅化成像(上图)和光线追踪成像(下图) 都是用合成的方法来成像。还可以用捕捉的方法来成像 利用小孔成像原理制作的相机就是针孔相机 如果一个相机没有针孔/透镜,是无法拍照的。 因为任何一个点都有可能收集到来自不同方向上的光。这个点本身作为传感器是不区分来自各个方向上的radiance。则各个方向上能量都被收集到一起,该点收集到的是irradiance,而不是radiance。最终所有东

Programming Languages B(Coursera / University of Washington) Assignment4

原文件已上传到GitHub: 点这里 本次作业需要racket标准库文档:https://docs.racket-lang.org/ Scheme 大法好 天灭过程式 退C保平安 人在做 天在看 赋值语句留祸患 指针乱用天地灭 赶紧重写保平安 诚心诚念SICP好 Scheme大法平安保 众生都为函数来 现世险恶忘前缘 Scheme弟子说真相 教你编程莫拒绝 早日摆脱面向过程 早日获得新生

Games101 光栅化笔记, 作业二

光栅化笔记 1、屏幕、像素、屏幕空间: (1)屏幕: 1、像素的二维数组 2、分辨率:数组的规模 3、典型的光栅成像设备 (2)像素的抽象理解: 1、内部颜色不会变化的小方块 2、RGB三者的颜色混合 (3)对光栅化的理解:对像素进行着色 (4)屏幕空间(在闫老师课上的规定): 1、屏幕的左下角是原点 2、x和y坐标都取整数,下图中蓝色像素坐标为(2,1) 3、像素的索引范围是(0,0)->

Games101 作业一 构建模型变换,和透视投影矩阵

知识总结:变换的流程 (1) 模型(Model)变换,pa中模型只绕z轴旋转 (2)视图(View)变换,作用是调整摄像机的位置 (3)投影(Projection)变换,pa中要求是透视投影,透视投影可看成挤压 + 正交变换 (4)视口(Viewport)变换,将投影变换所得的[-1,1]²变换到屏幕空间 代码分析: (1)获得视图变换矩阵(main.cpp) 视图变换的作用是移动摄像机,可看

17 - Games101 - 笔记 - 材质与外观

**17 **材质与外观 材质与BRDF 自然界中的材质:丝绸、头发、蝴蝶翅膀表面、寿司表面等等 图形学中的材质:同一个模型之所以渲染出不同结果的原因就是因为材质。在图形学中是给不同的物体指定不同的材质,知道它们如何和光线作用后就能正确的渲染。 漫反射 BRDF 漫反射材质:光线打到一个点上后均匀分散到各个不同方向上。 漫反射材质可以定义它在任何一个点上可以有不同的漫反射系数,虽

14 Games101 - 笔记 - 光线追踪(利用包围盒技术加速光线追踪(KD-Tree and BVH)

14 光线追踪(利用包围盒技术加速光线追踪(KD-Tree and BVH) 在上一节中,我们介绍了whited-style光线追踪的原理,以及实现细节。相比与光栅化中所使用的的Blinn-Phong模型,光线追踪显著了提升了图像质量,但随之而来的问题是渲染速度过慢。因为在判断光线与场景交点的时候,需要去进行所有三角形面与光线的求交,而且这仅仅是对一个像素而言。 那么总体来说光是进行光线与三角形