关于图形学:WebGPU-导入2-核心概念与重要机制解读

1. 外围概念这部分不会具体开展,当前写教程时会深刻。以下只是外围概念,是绝大多数 WebGPU 原生程序要接触的,并不是全副。 ① 适配器和设施适配器,也就是 GPUAdapter,指代真正的物理显卡,WebGPU 给了个对象来代替它: const adapter = await navigator.gpu.requestAdapter()它提供了一个最重要行为,申请设施对象 GPUDevice: const device = await adapter.requestDevice()那么什么是 Device?其实,显卡很忙。 WebGPU 程序只是三大图形 API 中某个的“下层封装”,除了 WebGPU,调用三大图形 API 的程序远不止,游戏、三维建模工具、视频编解码器,都有可能会调用,甚至会间接调取 GPU 厂商给的 SDK 或驱动程序。 显然,作为显卡“自身”,适配器为了极高效率地工作,喂给它的数据资源和指令最好就是翻译过的,尽可能专一地执行计算 —— 就像大老板不可能日理万机一样,最好给到老板的决策材料,就是通过整顿的,他要做的就是应用他多年的教训疾速决策、签字(效率高的老总 = RTX4090,超市小老板 = GT1030)。 那么,谁负责与各个部门(各个对显卡有须要的程序)负责人沟通具体业务呢? 我认为是老总的全权代理人,个别是秘书 + 副总经理。 不同封装有不同的概念,至多在 WebGPU 中,这个代理人叫做“设施”,GPUDevice,它简直就是显卡的分身,WebGPU 程序中所要调取的资源、创立的对象、要触发的行为,都交给设施对象实现。 每个 WebGPU 程序应该都有本人的 GPUDevice,不同的设施对象创立的 Buffer、Texture 等资源是不互通的,而适配器呢,个别状况下是同一个,除非你短时间内把电脑的显卡给更改过,前一会儿是独显,过一会儿可能是核显了(这段话还有待技术验证,仅为我不负责任的猜想)。 如果你写过原生的 WebGL,你可能会联想到 gl 上下文变量了,没错,设施对象大部分时候就是 gl 上下文的作用,然而是有本质区别的。② 缓冲、纹理、采样器缓冲、纹理,即 GPUBuffer、GPUTexture 均是 GPU 显存中的数据对象,能在客户端代码(如果没特地阐明,就是指浏览器端的 JavaScript)组织、创立、上载数据、互相转化、反读数据。 WebGPU 进行渲染绘图时,Canvas 是一个非凡的 GPUTexture。 ...

August 2, 2022 · 2 min · jiezi

关于图形学:GAMES101课程-作业6-源代码概览

GAMES101课程 作业6 源代码概览Written by PiscesAlpaca(双鱼座羊驼) 一、概述本篇将从main函数为出发点,依照各cpp文件中函数的调用程序和层级嵌套关系,简略剖析本次作业代码的含意。鉴于自己是初学者,局部剖析恐有偏颇,欢送读者批评指正。 二、源码剖析1 初始化1.1 场景初始化main.cppScene scene(1280, 960);Scene.cppclass Scene{public: // setting up options int width = 1280; int height = 960; Scene(int w, int h) : width(w), height(h) {} }在main函数中,首先创立了一个场景,将场景的长和宽传入Scene类的构造函数中 1.2 模型加载与三角片元生成main.cppMeshTriangle bunny("models/bunny/bunny.obj");紧接着,在main函数中调用了加载obj模型文件的语句,咱们跟进去看看里边做了什么 Triangle.hpp MeshTriangle(const std::string& filename) { objl::Loader loader; loader.LoadFile(filename); //依据文件门路加载obj文件 assert(loader.LoadedMeshes.size() == 1); auto mesh = loader.LoadedMeshes[0]; //获取mesh Vector3f min_vert = Vector3f{std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity()}; Vector3f max_vert = Vector3f{-std::numeric_limits<float>::infinity(), -std::numeric_limits<float>::infinity(), -std::numeric_limits<float>::infinity()}; //上述两个语句别离创立了bounding_box的6个面的记录,这些记录应用最小点和最大点示意 for (int i = 0; i < mesh.Vertices.size(); i += 3) { std::array<Vector3f, 3> face_vertices; //记录一个片元的三个顶点 for (int j = 0; j < 3; j++) { auto vert = Vector3f(mesh.Vertices[i + j].Position.X, mesh.Vertices[i + j].Position.Y, mesh.Vertices[i + j].Position.Z) * 60.f; //对于每一个定点,都将其后续两个定点进行遍历,造成一个片元的记录,并将其放大60倍 face_vertices[j] = vert; min_vert = Vector3f(std::min(min_vert.x, vert.x), std::min(min_vert.y, vert.y), std::min(min_vert.z, vert.z)); max_vert = Vector3f(std::max(max_vert.x, vert.x), std::max(max_vert.y, vert.y), std::max(max_vert.z, vert.z)); //在遍历中每次更新最大点和最小点 } auto new_mat = new Material(MaterialType::DIFFUSE_AND_GLOSSY, Vector3f(0.5, 0.5, 0.5), Vector3f(0, 0, 0)); new_mat->Kd = 0.6; new_mat->Ks = 0.0; new_mat->specularExponent = 0; //创立一个材质,其具体系数将在下方介绍 triangles.emplace_back(face_vertices[0], face_vertices[1], face_vertices[2], new_mat); //每个片元的三个顶点及其材质增加入triangles向量中,emplace_back与push_back有殊途同归之妙 } bounding_box = Bounds3(min_vert, max_vert);//用两个最大点和最小点示意六个面 std::vector<Object*> ptrs; for (auto& tri : triangles) ptrs.push_back(&tri); //浅拷贝一份triangels的vector bvh = new BVHAccel(ptrs); //创立BVH减速实例 }解释: ...

April 28, 2022 · 8 min · jiezi

关于图形学:Dead-Reckoning算法生成有向距离场

简介有向间隔场(signed distance field,SDF)是一张标注了每个像素到最近几何体边缘间隔的位图。因为在几何轮廓之外提供了额定的信息,SDF能为二维渲染减少很多灵活性,比方渲染文字时任意调整笔画粗细、放大形态时没有显著锯齿、通过穿插淡化两张SDF来穿插淡化几何轮廓等等。 这里介绍一种通用的有向间隔场生成办法:Dead Reckoning(原始文献),它可能从二维位图形容的几何轮廓计算SDF。不同于之前的一些近似算法会失去有“棱角”的后果,Dead Reckoning得出的后果简直是精确的,靠近于全局遍历失去的参考后果。 Dead Reckoning这个名字来源于船舶导航办法,名字中的“dead”可能来源于“deduced”简称之后的语音流变。这种导航办法通过观察一个指标之外的固定标志物来推算与导航指标之间的方位和间隔,这与算法中通过观察街坊像素来寻找最近边界有些类似,故而得名。 算法Dead Reckoning与生物信息学畛域的Needleman-Wunsch序列比对算法相似,都是一种动静布局算法。在处理过程中,它岂但记录每个像素的边界间隔,而且记录对应边界的像素地位,或者说以后的间隔是“从哪来的”。 整个计算过程会遍历两遍矩阵,第一次从上向下、从左向右逐行遍历所有像素,第二次反过来从下向上、从右向左。 数据初始化假如输出几何形态存在位图I上,外部像素值为1,内部像素值为0;位图d用来存储间隔,位图p用来存储每个像素的最近边界地位的坐标。 位图d:将位于边际的地位设为零,所有其它地位设为无穷大。 位图p:将位于边际的地位设为指向本身,所有其它地位设为某个非法值。 这里有个细节问题:如何定义边际地位。原论文认为该当既蕴含那些位于几何形态外部的像素,也蕴含位于内部的像素。也就是说,边界的宽度为2像素。这样的起因是为了数学对称性:将内外部的定义颠倒,对应的SDF也是原SDF求正数。但实际上咱们通常并不关怀这个对称性,只计入外部的那条边界就能够了。所以边际的条件是: I[x,y] == 1 and ( I[x,y]!= I[x-1,y] or I[x,y]!= I[x+1,y] or I[x,y]!= I[x,y-1] or I[x,y]!= I[x,y+1] )两次遍历遍历每个像素的时候,将它的以后距边界间隔与曾经解决过的四个街坊比拟,如果街坊的以后距边界间隔+像素间隔比它本人的要小,阐明街坊对应的边界更近,就应用街坊的边界信息,并依此更新本人的间隔。 假如左上角是(0,0),那么正向遍历的四个街坊就是它的左、左上、上、右上像素,反向遍历的四个街坊是它的右、右下、下、左下像素。 图中正在进行正向遍历的过程。绿色像素是曾经解决过的。蓝色像素是以后要解决的像素,它会从四个相邻的已解决像素(标为深绿色)中获取最近的那个边界地位。伪代码如下: // 正向遍历for y in 1 to height { for x in 1 to width { curr_d = d[x,y]; curr_p = p[x,y]; // 查看左上像素 if d[x-1,y-1] + 1.414 < curr_d { curr_p = p[x-1,y-1]; curr_d = distance((x,y), curr_p); } // 查看正上方像素 if d[x,y-1] + 1 < curr_d { curr_p = p[x,y-1]; curr_d = distance((x,y), curr_p); } // 查看右上像素 if d[x+1,y-1] + 1.414 < curr_d { curr_p = p[x+1,y-1]; curr_d = distance((x,y), curr_p); } // 查看正左方像素 if d[x-1,y] + 1 < curr_d { curr_p = p[x-1,y]; curr_d = distance((x,y), curr_p); } d[x,y] = curr_d; p[x,y] = curr_p; }}// 反向遍历for y in height to 1 { for x in width to 1 { curr_d = d[x,y]; curr_p = p[x,y]; // 查看左下像素 if d[x-1,y+1] + 1.414 < curr_d { curr_p = p[x-1,y+1]; curr_d = distance((x,y), curr_p); } // 查看正下方像素 if d[x,y+1] + 1 < curr_d { curr_p = p[x,y+1]; curr_d = distance((x,y), curr_p); } // 查看右下像素 if d[x+1,y+1] + 1.414 < curr_d { curr_p = p[x+1,y+1]; curr_d = distance((x,y), curr_p); } // 查看正右方像素 if d[x+1,y] + 1 < curr_d { curr_p = p[x+1,y]; curr_d = distance((x,y), curr_p); } d[x,y] = curr_d; p[x,y] = curr_p; }}在正反两次遍历之后,间隔d曾经填充实现,然而没有辨别几何体内外。如果须要这个辨别,只须要再遍历依此图像,将位于外部的像素的间隔变成负的。 ...

January 9, 2022 · 2 min · jiezi

关于图形学:图形学入门基础

什么是电磁波https://baike.baidu.com/item/... 首先,光是一种电磁波,因而光具备波速(光速)、波长和频率。 波长刻画了光这种电磁波的空间周期性;频率指1s内实现周期性变动的次数;光速 = 波长 x 频率光的频率是一种固有属性,不随着流传介质的扭转而扭转。光速在真空中是不变的见这里在不同介质中,光速不同,波长不同。光的能量是不间断的,咱们应用光子这一概念来刻画这种不连续性。对于每一个光子携带的能量咱们有\( Q=hv \),其中\(h\)是普朗克常数,单位焦秒。而v为光子的振动频率,频率的单位是赫兹。 什么是色彩https://www.zhihu.com/questio... 什么是光照强度 光通量 光照度 辐射(亮度)https://zhuanlan.zhihu.com/p/...https://zhuanlan.zhihu.com/p/... BRDFhttps://zhuanlan.zhihu.com/p/...https://zhuanlan.zhihu.com/p/...BRDF其实是一个(对于某点而言)定义在半球面上的四维函数,两个维度由入射光指定,两个维度由出射光指定,它本质上指定了某入射方向的光线奉献的光通量与某出射方向上提供了通量的比值。顺次构建出了反射方程和渲染方程:https://zhuanlan.zhihu.com/p/...渲染方程:能量守恒->光通量守恒 + 立体角微分

December 18, 2021 · 1 min · jiezi

关于图形学:计算机图形学入门光栅化

作者:心动前端工程师 山楂 山楂最近入坑计算机图形学,在心动外部做了一次分享,分享内容次要基于闫令琪的课程。上面是这次外部分享的笔记,请配此 slide 食用。 计算机图形学在游戏、电影、设计、VR & AR、可视化、模仿、GUI、字体等畛域失去广泛应用,包含光栅化(rasterization)、几何(curves & meshes)、光线追踪(ray tracing)、动画模仿(animation/simulation)等内容。其中,光栅化能够说是计算机图形学中最为根底的概念。简略来说,光栅化是将三维场景映射成立体图形,再将图形分解成多边形,多边形打碎成像素,显示到屏幕上的过程。 光栅化波及的数学知识次要是线性代数,包含向量(求和、点积、叉积)和矩阵(乘积、转置、单位矩阵)等。光栅化波及的大量变换都能够表白为向量和矩阵的运算。缩放、切变、翻转、旋转这些线性变换能够用矩阵乘法示意,引入齐次坐标后,平移也同样能够像线性变换一样用矩阵乘法解决。蕴含俯仰、偏航、滚转的三维简单旋转,能够用罗德里格斯旋转方程形容。 缩放、旋转、平移等根本的变换操作产生在模型变换(modeling tranformation)阶段,相似拍照过程中的找景、模特就位。模型变换之后是相机变换(view tranformation)阶段,在这一阶段咱们确定相机和物体的绝对地位,相似拍照过程中的找角度、放相机。具体来说,咱们通过相机的地位、看向的方向、往上的方向来示意相机,而后为了简化计算,将相机和物体一起挪动,在放弃两者绝对地位不变的前提下将相机挪动至坐标系原点。下一阶段是投影变换(projection tranformation),相似拍照过程中的按快门。投影次要分为正交投影和透视投影两种。正交投影绝对简略,光线平行,各点的绝对地位不变,将场景平移缩放至 [-1, 1]^3 的规范立方体上,再去除 Z 值压到立体上。这里,缩放至规范立方体是为了简化计算。透视投影,近大远小,相似人眼观看物体的形式。使用近立体通过挤压不会发生变化、远立体通过挤压 Z 值不会发生变化、中心点通过挤压也不会发生变化三点性质,能够实现透视投影。这三个阶段组成了视图变换。最初还有一个视口变换(viewport transformation),将之前缩放至规范大小的场景依据屏幕的长宽再进行一次变换,投射到屏幕上。 光栅化合成图形为多边形,其中使用最宽泛的是三角形,因为三角形外部是立体,内外定义很清晰,外部任意一个点都能够插值突变。三角形输入到屏幕时,会遍历屏幕上的每个像素,通过向量的叉乘判断像素点是否在三角形内。当然,理论计算时会应用突围盒简化计算,突围盒外的像素点就不必再进行向量叉乘运算了。为了应答锯齿、摩尔纹等采样瑕疵,能够先含糊再采样。尽管对每个像素进行卷积操作能够实现含糊,但计算量比拟大,所以个别应用超采样,每个像素外部减少采样点再进行均匀。 利用 Z 值能够解决遮挡的问题,保护一个 Z-Buffer 记录像素点的深度,如果三角形面上的像素点 Z 值小于 Z-Buffer 中的值,那就更新 Z-Buffer 中的值为以后 Z 值,同时更新该像素点的色彩为以后三角形面上的像素点的色彩。 再接下来要解决的是着色(shading)问题,因为物体的色彩会受光照影响,更简单的是,不同的材质和光线的相互作用不同。最根底的着色模型是Blinn-Phong反射模型,它从高光、漫反射、环境光三个维度去综合思考着色。漫反射次要思考材质的漫反射系数、光线强度、光源远近、入射方向和材质外表的夹角大小。不同的着色频率会产生不同的显示成果,有逐立体法线(flat shading)、逐顶点法线(gouraud shading)、逐像素法线(phong shading)三种。逐立体法线以三角形面为着色单位,计算很快,但成果较差。将共享一个顶点的所有三角形面的法线向量相加求均值,能够失去顶点的法线向量,据此能够对每个顶点进行着色,而后间接插值计算三角形面内每个点的色彩,这就是 gouraud shading。如果不间接插值计算三角形内每个点的色彩,而是间接光栅化后造成像素点,再据此对每一个点着色,就是 phong shading。 计算机图形中经常提到的渲染管线通常可分为顶点解决、三角形解决、光栅化、片元解决、帧缓冲解决,其实具体来说大抵就是下面提到的这些内容。顶点解决就是对所有顶点数据进行视图变换,三角形解决就是这些顶点组合成各三角形面(三角面剖分),而后是光栅化判断像素点是否在三角形内,再接下来是片元解决,对每个片元进行着色,最初则是整合所有信息输入至屏幕。其中,片元解决除了之前提到的着色外,也能够进行纹理映射,用纹理贴图代替色彩。 最初举荐两个超棒的视频教程: 3Blue1Brown 的 线性代数的实质,以可视化的形式来了解线性代数(总时长:2h40m)。闫令琪的 古代计算机图形学入门,全程无一句废话,通俗易懂,滑稽风趣(总时长:28h+)。

October 21, 2021 · 1 min · jiezi