光栅化(Rasterization)

MVP复习

1)Model transformation(placing objects) = 找好一个场景,让人物摆好姿势

2)View transformation(placing camera) = 放置好照相机

利用camera和物体的相对运动关系,始终让camera从任一位置变换到原点看向-z方向且向上为y,其余物体也跟着camera做相同的变换,从而保证model transformation应用到每一个model上,并且view transformation也应用到了每一个model上。

3)Projection transformation = 按下快门,将三维物体表现在二维平面上

在view transformation之后我们知道场景中的所有物体都是由一个标准位置的camera看过去的,接着将所看到的东西从3D投影成2D的一张照片。又分为正交投影(忽略深度信息)和透视投影(拥有近打远小的效果)。

经过mvp变换矩阵之后的所有东西都会在一个 [ − 1 , 1 ] 3 [-1,1]^3 [1,1]3的立方体里,那么下一步该干什么呢?答案是“光栅化”!

但在讲光栅化之前先看如果根据已知的Near、Far、Fov、Aspect来定义frustum:

在这里插入图片描述

aspect是宽高比,说的是Near和Far。

而Fov则是从camera,点A处,往上下两边的中点各连一条线,而两条线的夹角叫垂直可视角度。同理也可以求出水平可视角度,往左右两边的中点各连一条线,而两条线的夹角叫水平可视角度。

Near和Far是两个面的位置。

在这里插入图片描述

有了这些已知条件就可以计算推导出Near和Far的面积有多大,以及知道一个垂直可视角度就可以推导出水平可视角度。

接下来我们来了解如何将 [ − 1 , 1 ] 3 [-1,1]^3 [11]3的立方体画在屏幕上

光栅化概念导入

对于图形学来说,我们抽象的将屏幕定义为一个二维的数组,数组中的每一个元素是一个像素(an array of pixels)。

(tips:例如1920 * 1080分辨率,就是说长为1920个像素点,宽为1080个像素点,总像素为1920 * 1080个像素,也叫做1080P。)

屏幕是一个典型的光栅成像设备。Raster的由来是德语中屏幕的意思,而光栅化(Rasterize)就是把东西画在屏幕上的意思。所以把东西画在屏幕上的过程就是光栅化的过程

像素:

像素名字的由来是picture element,我们将其缩写为pixel

在图形学中我们将像素看为:

  • 是一个一个的小的方块.
  • 每个方块内的颜色是完全一致的,像素就是最小的单位了,像素内部不会再发生变化。
  • 我们用256个等级0-255来表示灰度(如等级0表示是黑的,等级255表示是白的),一个像素内的颜色可以用rgb(red,green,blue)三个值来定义,用红绿蓝的各种组合来表示每一种红色蓝色绿色的密度,例如红色是(255,0,0),白色是(255,255,255)。
  • 一个像素内颜色不会发生任何差异。

屏幕空间:

屏幕空间就是以屏幕左下角为原点建立一个二维坐标系,如下图:

在这里插入图片描述

  • 用(x,y)表示像素的位置。(蓝色像素表示为(2,1)坐标来表示,从0开始数。)
  • 如果一个屏幕分辨率为width * height,那么我们定义像素下标从(0,0)到(width - 1,height - 1),且(x,y)像素的中心在(x + 0.5, y + 0.5),如蓝色像素的中心为(2.5, 1.5)。
  • 屏幕范围从(0,0)到(width,height)

现在我们需要把这个中心在坐标原点 [ − 1 , 1 ] 3 [-1,1]^3 [1,1]3的立方体显示在长为height、宽为width的屏幕中,先不考虑Z值,如下图所示:

在这里插入图片描述

第二步的具体操作是进行一次视口变换(viewport),准确地说是通过缩放平移变换将原本的 [ − 1 , 1 ] 2 [-1,1]^2 [1,1]2拉伸到屏幕空间中并将中心移动到屏幕空间中心,视口变换矩阵(viewport transform matrix)如下:
M v i e w p o r t = [ w i d t h 2 0 0 w i d t h 2 0 h e i g h t 2 0 h e i g h t 2 0 0 1 0 0 0 0 1 ] M_{viewport}= \left[ \begin{matrix} width \over 2 & 0 & 0 & width \over2 \\ 0 & height \over2 & 0 & height \over2 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{matrix} \right] Mviewport= 2width00002height0000102width2height01
至此我们得到了一张映射在屏幕空间的2D场景图,接下来我们要将场景中的多边形其离散成一系列的像素画在屏幕空间上。

Drawing to Raster Displays

光栅化的过程实际上就是将多边形拆分成一系列的像素,从而将3D空间中的多边形或多边形的顶点变换到屏幕空间上去。

一般将图像拆分成许多不同的三角形 进行显示,下图是由三角形表示的二维空间的不同的图形。

在这里插入图片描述

我们可以看到三角形的表达能力很强,不论是在3D还是2D中,之所以选择三角形是因为:

  • 三角形是最最基础的多边形。
  • 任何多边形均可以拆解成多个三角形。

三角形具有不错的性质:

Ⅰ. 三角形的三个点连接在一起,其三点一定在一个平面上。

Ⅱ. 三角形的内外部定义的很清楚,可以通过向量的叉积判断点是否在三角形内部。

A Simple Approach: Sampling(采样)

在这里插入图片描述

我们知道一个像素内部是不会再发生颜色变化的,那三角形三条边上只包含了像素一部分的这些区域该如何设置颜色呢?是有颜色还是无颜色呢?

因此我们需要判断一个像素和三角形之间的位置关系,更确切的来说是判断像素的中心点与三角形之间的位置关系

而这个关系的判断我们可以通过采样实现。

采样:采样就是把一个函数给离散化的过程,可以理解为给你一个连续的函数,在不同地方问此处的函数值是多少,这就是采样.

例如f(x) = sinx,让你求x=1,x=3,x=5或者x=-1时候的对应的f(x)的值是多少,如:

在这里插入图片描述

采样就是把一个函数离散化的过程。

我们这里的采样是通过利用像素中心对屏幕空间进行采样,也就是算出定义在屏幕空间上的某一函数在不同像素中心的值是多少。

采样是图形学的核心理念,可以采样的:时间(1D)、面积(2D)、方向(2D)、体积(3D)等。

光栅化作为2D采样

在这里插入图片描述

给你一个三角形,我们需要在像素中心来判断其是否在三角形内。

在这里插入图片描述

我们可以定义一个inside函数,来判断像素是否在三角形内:

在这里插入图片描述

for (int x = 0; x < xmax; ++x)for (int y = 0; y < ymax; ++y)image[x][y] = inside(tri,  x + 0.5,  y + 0.5);x,y不必为整数,是实数。

屏幕空间是[0,width] x [0,height]这么一个区域,我们利用像素中心来进行采样就是指算出需要某一个定义在屏幕空间内的函数在不同的像素中心的值是多少

比如我们在这里采样的就是在屏幕空间中定义的inside函数在不同像素中心的值,在不同像素中心采样到的结果是1则在三角形内,是0则在三角形外,通过这个值我们来判断此像素是否在三角形内.

这个函数具体是如何判断像素点在不在三角形内部则是通过向量叉乘运算得到的。如果正巧点在三角形边线上,那可以自己定义一个规则。

遍历像素

接下来就可以遍历屏幕像素将三角形显示在屏幕中了

有两种较为高效的扫描遍历策略Bounding BoxIncremental Triangle Traversal

(Bounding Box) 检测像素的步骤:

  1. 首先通过三角形三个顶点的 x,y 的坐标从最小值到最大值选出包围盒(Bounding Box)。即蓝色包围部分,去掉第一列白色部分。

  2. 严格来说这个又叫做轴向包围盒=AABB包围盒(Axis-aligned bounding box)

  3. 在蓝色区域内进行采样,使用inside函数确定像素中心点的值。

在这里插入图片描述

(Incremental Triangle Traversal)增量三角形遍历:

对三角形所覆盖的区域每一行找覆盖的最左和最右,相当于在每一行确定一个包围盒。

这种方法适用于实际上覆盖了很少的像素但AABB包围盒范围却很大的情况,也就是一个窄长三角形经历了旋转的情况下。

在这里插入图片描述

最终我们采样信号显示为:

在这里插入图片描述

我们找到了那些像素是在三角形内部的,接着我们对其进行颜色填充。

锯齿

在像素内进行颜色填充之后会变为下图,我们称这种情况为锯齿(Jaggies)现象。出现的原因是 因为像素本身具有大小,采样率不高,从而信号走样(Aliasing)。

在这里插入图片描述

与我们想要的效果不一样:

在这里插入图片描述

锯齿一直是图形学在不断改进的问题,下节课将介绍如何解决“锯齿”问题,引入抗锯齿和反走样的概念。

光栅化的过程其实就是我们将3D空间的多边形离散成屏幕空间一系列的点(像素的中心点),并通过采样某一定义在屏幕空间的函数的结果判断那些像素需要着色从而将多边形显示在屏幕空间上。

Anti-aliasing

反走样的主要思想是,在采样之前进行模糊处理(Antialiasing idea:bluring before sampling).

如果不先进行模糊处理而是直接对三角形采样,由于我们是通过像素中心点来采样,得到的结果这个像素点要么在三角形内像素点纯红,要么在三角形外像素点纯白,最终会导致锯齿:

在这里插入图片描述

如果我们先做一遍模糊处理在进行采样:

在这里插入图片描述

我们会发现采样点增加了,并且在边缘处有一些颜色比较淡的点,也就是采样到了模糊三角形的边界。

三角形的原锯齿边缘的像素取了一个介于红色和白色之间的像素值,离边界近就接近红色,离边界远就接近白色,再进行染色时,边缘的像素点就会染色为中间值,边缘就能够获得一些更加平滑的效果,起到抗锯齿的作用。

这也就是对原始的函数或者信号进行了一个模糊或者滤波的处理,然后再去做采样,从而解决了锯齿的问题。

先采样再模糊并不能实现抗锯齿的效果,其仍然得到的是一个走样的结果,只不过在走样之后又进行了模糊操作,称其为Blurred Aliasing,并不是Anti-Aliasing。

硬件支持:提高显示器分辨率。如果用一个640*480的显示器,光栅化一个三角形,就能够明显发现锯齿很严重,但是如果使用1920 * 1080的显示器就能够明显改善这种情况,采样的密集了,走样现象也就会减少。但是这种情况需要依赖于高分辨率的显示器,若是显示器分辨率不能改变时,这种方法就不行了。

MSAA(Antialiasing By Supersampling)

MSAA是一个对反走样的近似,之前采样的最小单位是像素的中心点,在MSAA中,我们将以划分的每个像素再进行划分,将原有的一个像素分为更多个小像素.如下图,我们将原来的一个像素的区域又重新划分为了4*4 = 16 个像素的新区域.

在这里插入图片描述

而重新划分的每一个小像素也都有一个像素中心,然后可以对这个小像素进行采样,判断这些小像素在不在三角形内,然后将最后的结果平均起来,就能够求的三角形对一个像素的区域的近似的覆盖。比如:

在这里插入图片描述

可以看到一个三角形覆盖了若干个很大的原像素.

现在假设说我们将原有的一个大像素分为四个小像素,也就是在像素内部多加一些采样点,这就导致了时域上我们采样的间隔变小,频域上的频谱搬移空间变大,从而进行了反走样.

在这里插入图片描述

然后每个点都可以判断是否在三角形内,如果四个点都在三角形内就是100%覆盖,也就是100%的红色,如果只有三个点在三角形内,则三角形对这个像素就是75%覆盖,其颜色也就是75%的红色+25%的白色。于是就可以得出每个像素的覆盖结果:

在这里插入图片描述

MSAA通过更多的样本,来近似的进行反走样的第一步,模糊这个过程。模糊完了之后就相当于每一个像素内部都已经知道了三角形的覆盖率,求了平均之后是什么,就会得到上图的结果。

到了这一步,就相当于模糊做完了,就相当于用卷积核对图像进行了一次卷积得到了模糊的效果。

然后再采样,这时采样就会十分简单,因为我们规定像素是最小的单位格子,每个格子的颜色都是平均的(像素内的颜色都是一样的),采样完也就会得到上图的结果。

注意!!!

  • MSAA所进行的是一个模糊的操作,而采样这一步隐含在了MSAA的过程中.
  • MSAA并不是一个提升分辨率直接解决的走样问题. (我们增加采样点只是为了近似一个合理的三角形在像素点上的覆盖率,并没有真的提升分辨率.)
  • MSAA的缺陷就是,我们增加了采样点也就是增加了计算量,将一个像素划分为多个区域,就要对每个区域进行多次计算,最后就提高了计算的成本。

Z-buffering

Painter’s Algorithm:画家算法,由远及近画画,近处画面覆盖远处画面。无法处理复杂的深度判断,例如三个三角形互相重叠。如果事先把深度排序的话时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn).

Z-buffer:额外开辟一块屏幕大小的空间存放像素深度。渲染之前先于存放的值进行比较,如果深度更近则进行绘制,并更新值。空间换时间,时间复杂度 O ( n ) O(n) O(n)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/115660.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mvc 异常处理源码解析(3)

目录 准备源码跟踪ExceptionHandlerExceptionResolver初始化ExceptionHandlerExceptionResolver注入ExceptionHandlerExceptionResolver中exceptionHandlerAdviceCache初始化ExceptionHandlerMethodResolver中mappedMethods初始化 结尾 准备 准备一个controller类, 里面抛出一…

9. 微积分 - 导数

文章目录 导数求导实例代码演示:迭代法求解二次函数最小值阶Hi, 大家好。我是茶桁。 我们终于结束了极限和连续的折磨,开启了新的篇章。 不过不要以为我们后面的就会很容易,只是相对来说, 没有那么绕而已。 那么,我们今天开始学习「导数」。 导数 在之前的导论,也就是…

嵌入式岗位笔试面试专栏 - 岗位介绍

文章目录 一、嵌入式岗位的分类二、热门领域及公司三、发展前景四、技能要求沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇我们将讲解嵌入岗位的工作职责 。 一、嵌入式岗位的分类 嵌入式软件工程师大致可以分为两种类型: 应用开发工程师驱动开发工程师应用工程…

ShardingSphere——弹性伸缩原理

摘要 支持自定义分片算法&#xff0c;减少数据伸缩及迁移时的业务影响&#xff0c;提供一站式的通用弹性伸缩解决方案&#xff0c;是 Apache ShardingSphere 弹性伸缩的主要设计目标。对于使用单数据库运行的系统来说&#xff0c;如何安全简单地将数据迁移至水平分片的数据库上…

【重要】NAND Flash基础知识简介

NAND Flash是一种非易失存储介质&#xff08;掉电后数据不会丢失&#xff09;&#xff0c;常见的U盘、TF卡/SD卡&#xff0c;以及大部分SSD&#xff08;固态硬盘&#xff09;都是由它组成的。 本文主要介绍其组成及工作原理。 为了表述方便&#xff0c;后面所说的Flash仅指NAN…

【原创】H3C路由器OSPF测试

网络拓扑图 路由器配置&#xff1a; 路由器1上接了4跟线&#xff0c;分别为这四个接口配置IP地址。 # interface GigabitEthernet0/0/0port link-mode routecombo enable copperip address 2.1.1.2 255.255.255.0 # interface GigabitEthernet0/0/1port link-mode routecombo…

【UI 设计】触摸界面设计

触摸界面设计是一种以触摸操作为主的用户界面设计。以下是一些触摸界面设计的要点&#xff1a; 界面布局&#xff1a;设计简洁、直观的界面布局&#xff0c;使用户可以快速找到所需的功能和信息。避免过于拥挤的布局&#xff0c;保持按钮和菜单的大小适中&#xff0c;以便用户能…

Android DataBinding 基础入门(学习记录)

目录 一、DataBinding简介二、findViewById 和 DataBinding 原理及优缺点1. findViewById的优缺点2. DataBinding的优缺点 三、Android mvvm 之 databinding 原理1. 简介和三个主要的实体DataViewViewDataBinding 2.三个功能2.1. rebind 行为2.2 observe data 行为2.3 observe …

MacOS 为指定应用添加指定权限(浏览器无法使用摄像头、麦克风终极解决方案)

起因&#xff1a;需要浏览器在线做一些测评&#xff0c;但我的 Chrome 没有摄像头/麦克风权限&#xff0c;并且在设置中是没有手动添加按钮的。 我尝试了重装软件&#xff0c;更新系统&#xff08;上面的 13.5 就是这么来的&#xff0c;我本来都半年懒得更新系统了&#xff09…

开始MySQL之路——MySQL存储引擎概念

一、存储引擎概念 MySQL数据库和大多数的数据库不同, MySQL数据库中有一个存储引擎的概念, 针对不同的存储需求可以选择最优的存储引擎。 ​ 存储引擎就是存储数据&#xff0c;建立索引&#xff0c;更新查询数据等等技术的实现方式 。存储引擎是基于表的&#xff0c;而不是基…

error: ‘std::_hypot‘ has not been declared using std::hypot;

Cmake 使用qt的编译器 编译opencv时 执行mingw32-make时出现了错误 本质原因就是 _hypot 没有声明。所以找到对应的文件声明一下 就行了。 E:\*****\Qt5.14.1\Tools\mingw730_64\lib\gcc\x86_64-w64-mingw32\7.3.0\include\c 下面的math.h 文件。 可以看到这个文件有一个…

二、C#—第一个c#程序(2)

&#x1f33b;&#x1f33b; 目录 一、编写第一个C#程序1.1 使用Visual Studio创建c#程序的步骤1.2 编写第一个程序“Hello Word”1.3 c#程序的基本结构1.3.1 c#中的命名空间1.3.2 c#中的类1.3.3 c#中的程序启动器——Main方法1.3.4 c#中的标识符1.3.5 c#中的关键字1.3.6 c#中的…

Yjs + Quill 实现文档多人协同编辑器开发(基础+实战)

前言 多人协同开发确实是比较难的知识点&#xff0c;在技术实现上有一定挑战&#xff0c;但随着各种技术库的发展&#xff0c;目前已经有了比较成熟的解决方案。今介绍 Yjs 基于CRDT算法&#xff0c;用于构建自动同步的协作应用程序&#xff0c;与Quill富文本编辑器&#xff0c…

海康机器人工业相机 Win10+Qt+Cmake 开发环境搭建

文章目录 一. Qt搭建海康机器人工业相机开发环境 一. Qt搭建海康机器人工业相机开发环境 参考这个链接安装好MVS客户端 Qt新建一个c项目 cmakeList中添加海康机器人的库&#xff0c;如下&#xff1a; cmake_minimum_required(VERSION 3.5)project(HIKRobotCameraTest LANG…

OPENCV实现暴力特征匹配

# -*- coding:utf-8 -*- """ 作者:794919561 日期:2023/9/1 """ import cv2 import numpy as np# 读

iPhone 14四款机型电池容量详细参数揭秘

苹果推出的iPhone 14系列与2021系列的设计和外形尺寸相同&#xff08;仅缩小了几分之一毫米&#xff09;&#xff0c;所以这并不奇怪&#xff0c;但电池容量也大致相同。 虽然可能不足以对电池寿命产生可衡量的影响&#xff0c;但也存在微小的差异。不同的是&#xff0c;现在有…

GreenPlum的gpfdist使用与原理流程分析

一、简介 GreenPlum 的数据导入功能作为对数据源的一种扩充&#xff0c;数据导入的方式有&#xff1a; 1、insert 该方式通过 sql 语句&#xff0c;把数据一条一条插入至表中。这种方式&#xff0c;不仅读取数据慢&#xff08;一条一条读取&#xff09;&#xff0c;且数据需要…

【局部活动轮廓】使用水平集方法实现局部活动轮廓方法研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

uni-app:允许字符间能自动换行(英文字符、数字等)

<template><view class"container"><!-- 这里是你的文本内容 -->{{ multilineText }}</view> </template><style> .container {word-break: break-all; } </style>例如&#xff1a; <template><view class"…

三、定长内存池

三、定长内存池 我们知道申请内存使用的是malloc&#xff0c;malloc其实就是一个通用的大众货&#xff0c;什么场景下都可以使用&#xff0c;而什么场景下都可以用就意味着什么场景下都不会有很高的性能&#xff0c;下面我们就先来设计一个定长内存池作为一个开胃菜&#xff0…