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

【技术调研】三维(0)-webGL、三维基础知识、前置知识、数学知识以及简单示例

前言

​ 因业务需要了解网页端三维相关技术,故对webGL相关技术学习并记录。旨在了解网页端三维的基本原理。

什么是webGL?

​ WebGL全称叫做Web Graphics Library,它是JavaScript API。用于在任何兼容的Web浏览器中渲染交互式的3D图形,并且无需使用插件。它基于 OpenGL ES 2.0(一个用于嵌入式系统的图形库),并与其他 Web 标准完全集成,使开发者能够利用 GPU 加速图形处理直接在网页上实现复杂的图形效果。

​ WebGL可以在网页上开发高性能的3D游戏,许多现代网页游戏都利用了WebGL实现了丰富的图形效果和流畅的用户体验。

WebGL地解决了现有的Web交互式三维动画的两个问题:第一,它通过HTML脚本本身实现Web交互式三维动画的制作,无需任何浏览器插件支持;第二,它利用底层的图形硬件加速功能进行的图形渲染,是通过统一的、标准的、跨平台的OpenGL接口实现的。

​ 简单地说,webGL是一个用于在html中实现三维动画的API。

webGL坐标系

​ 在WebGL中,坐标系使用的是右手坐标系,手掌朝向自己大拇指与食指垂直,食指与中指垂直形成一个空间。大拇指方向是X轴,食指方向是Y轴,中指方向是Z轴。

​ 注意,其中X、Y、Z轴正方向最大值都为1,负方向最大值都为-1。

在这里插入图片描述

canvas画布上的坐标

Canvas画布可以支持2D,也可以支持3D。但是2D和3D坐标方向是完全不同的。

  • 2D,坐标原点是canvas画布的左顶点,水平方向向右是X轴,竖直方向向下是Y轴。如图:

在这里插入图片描述

  • 3D,坐标原点是canvas画布的中心点,水平方向向右是X轴,竖直方向向上是Y轴,屏幕朝外方向是Z轴。如图:

    在这里插入图片描述

webGL渲染管线

- webGL是个状态机,需要先提前设置所有状态,通过DrawCall命令GPU顺着渲染管线来调用设置好的所有状态,最终获得Framebuffer
- 设置所有状态的过程都是在CPU上跑,DrawCall命令下的渲染管线是GPU上跑
- 渲染管线存在可编程阶段,可配置阶段,不可配置阶段,可选阶段等
- 不同厂商实现的渲染管线部分不同

在这里插入图片描述

总结:渲染管线实质上指的是一系列的绘制过程。

其他前置知识

canvas

canvas是 HTML5 提供的一个用于绘制图形的区域,它可以通过 JavaScript 动态地渲染图形内容。canvas 可用于绘制图形、动画、图表、游戏以及实时数据可视化等。具体绘制2D或者3D图形,取决于渲染上下文对象是2D还是3D。
获取渲染上下文

HTMLCanvasElement.getContext()方法用于返回绘图上下文对象,绘图上下文对象是2D上下文还是3D上下文取决于传入的参数。

//获取一个webGLRenderingContext三维的渲染上下文对象
const gl = canvas.getContext("webgl");
//获取一个CanvasRenderingContext2D二维的渲染上下文对象
const 2d = canvas.getContext("2d");

类型化数组

​ JavaScript的类型化数组是一种用于处理和操作二进制数据的对象,类型化数组在处理WebGL等需要高性能和大数据量操作的应用中非常有用。

​ 类型化数组和普通的JavaScript数组不同,类型化数组的每一个元素都是同一类型的二进制数据,这种类型在创建数组时就已经确定了。

​ 以下是常用的一些特定类型的类型化数组:

视图名称 元素大小(字节) 描述 等价的C语言类型
Int8Array 1 8位二进制补码有符号整数 signed char
Uint8Array 1 8位无符号整数 unsigned char
Uint8ClampedArray 1 8位无符号整数(对溢出做特殊处理) unsigned char
Int16Array 2 16位二进制补码有符号整数 short
Uint16Array 2 16位无符号整数 unsigned short
Int32Array 4 32位二进制补码有符号整数 int
Uint32Array 4 32位无符号整数 unsigned int
Float32Array 4 32位IEEE浮点数 float
Float64Array 8 64位IEEE浮点数 double

​ 关于类型化数组本文不展开介绍,要详细了解请点击

着色器

​ GLSL(OpenGL Shading Language)是一种用于编写图形着色器的编程语言。着色器是用于在图形处理单元(GPU)上执行特定图形处理任务的程序。通俗讲,着色器是画点的工具,一个图形是由无数个点组成的,每个点都有其自己的颜色。

着色器的类型

一个着色器就是一个绘制东西到屏幕上的函数,着色器有顶点着色器和片元着色器。

  • 顶点着色器:处理每个顶点的属性,如位置、法线、纹理坐标等。它的主要任务是将顶点从对象坐标系转换到屏幕坐标系,并传递其他顶点属性给片段着色器。
  • 片元着色器:处理每个像素的颜色。它接收来自顶点着色器插值后的数据,并最终决定每个像素的颜色。
着色器语法

在HTML中,如果你想把着色器代码直接写在

		<!--  顶点着色器  -->
		<script id="vertex-shader" type="x-shader/x-vertex">
			attribute vec2 position;
			void main(){
   
				gl_PointSize = 5.0;
				gl_Position = vec4(position,0.0,1.0);
			}
		</script>
		
		<!--  片元着色器  -->
		<script id="fragment-shader" type="x-shader/x-fragment">
			void main(){
   
				gl_FragColor = vec4(1.0,0.0,0.0,1.0);
			}
		</script>
着色器中的变量修饰符
  • atrribute:用于顶点着色器,定义从顶点缓冲区传入的变量(只能在顶点缓冲区使用,可理解为用于传递顶点数据)
  • uniform:定义在整个渲染过程中保持不变的变量,常用于传递变换矩阵、光照参数。
  • varying:用于在点点着色器和片元着色器之间传递插值数据
着色器中的内部变量
  • 顶点着色器:
    • gl_Position 顶点的位置
    • gl_PointSize 顶点的大小
  • 片元着色器:
    • gl_FragColor 片元的最终颜色

webGL API

​ 见webGL API

线性代数、矩阵知识

​ 略。复习可参考以下:矩阵知识复习

第一个webGL程序

​ 绘制一个点。具体步骤见代码中注释:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>firstwebGLDemo</title>
		<style type="text/css">
			#myCanvas{
     
				background-color: aqua;
			}
		</style>
		<script>
			
			
		</script>
	</head>
	<body>
		<canvas id='myCanvas' width="700" height='600'></canvas>
		
		<!--  顶点着色器  -->
		<script id="vertex-shader" type="x-shader/x-vertex">
			void main(){
     
				gl_PointSize = 50.0;
				gl_Position = vec4(0.5,0.5,0.0,1.0);
			}
		</script>
		
		<!--  片元着色器  -->
		<script id="fragment-shader" type="x-shader/x-fragment">
			void main(){
     
				gl_FragColor = vec4(1.0,0.0,0.0,1.0);
			}
		</script>
		
		<script>
			/** 
			 * 	第一步 创建画布、获取画布、创建三维上下文对象	
			**/
			const canvas = document.getElementById("myCanvas");
			//获取一个webGLRenderingContext三维的渲染上下文对象
			const gl = canvas.getContext("webgl");	

			/** 
			 * 	第二步 创建着色器、与webGL渲染对象绑定、编译
			**/ 
			//通过element获取着色器源码
			const vertexSource = document.getElementById("vertex-shader").innerText;
			const fragmentSource = document.getElementById("fragment-shader").innerText;
			//创建顶点着色器对象,并绑定源码,编译;
			const vertexShader = gl.createShader(gl.VERTEX_SHADER);
			gl.shaderSource(vertexShader,vertexSource)
			gl.compileShader(vertexShader);
			//创建片元着色器对象,并绑定源码,编译
			const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
			gl.shaderSource(fragmentShader,fragmentSource);
			gl.compileShader(fragmentShader);
			
			
			/**
			 * 	第三步 创建着色器程序对象,并将着色器附着在程序上。
			**/
			//创建程序对象
			const program = gl.createProgram();
			//将着色器附着到程序对象
			gl.attachShader(program,vertexShader);
			gl.attachShader(program,fragmentShader);
			//webgl对象链接程序对象,将顶点着色器和片元着色器链接成一个完成的可执行程序
			gl.linkProgram(program);
			//webgl对象使用这个program作为渲染程序
			gl.useProgram(program);
			
			
			/**
			 *  第四步 绘制---点
			 */
			gl.drawArrays(gl.POINTS,0,1);
		</script>
	</body>

</html>

绘制线(使用attribute)

​ 根据第一个程序可知,绘制两个点后连接即可成为线。那么如何绘制多个点以及连接呢?这时候就要用到attribute(用于顶点着色器,定义从顶点缓冲区传入的变量,只能在顶点缓冲区使用,可理解为用于传递顶点数据)。

​ 代码如下:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>firstwebGLDemo</title>
		<style type="text/css">
			#myCanvas{
     
				background-color: aqua;
			}
		</style>
		<script>
			
			
		</script>
	</head>
	<body>
		<canvas id='myCanvas' width="700" height='600'></canvas>
		
		<!--  顶点着色器  -->
		<script id="vertex-shader" type="x-shader/x-vertex">
			attribute vec2 position;
			void main(){
     
				gl_PointSize = 5.0;
				gl_Position = vec4(position,0.0,1.0);
			}
		</script>
		
		<!--  片元着色器  -->
		<script id="fragment-shader" type="x-shader/x-fragment">
			void main(){
     
				gl_FragColor = vec4(1.0,0.0,0.0,1.0);
			}
		</script>
		
		<script>
			/** 第一步 创建画布、获取画布、创建三维上下文对象  **/
			const canvas = document.getElementById("myCanvas");
			//获取一个webGLRenderingContext三维的渲染上下文对象
			const gl = canvas.getContext("webgl");
			//获取一个CanvasRenderingContext2D二维的渲染上下文对象
			// const 2d = canvas.getContext("2d");
			
			/** 第一步 创建顶点并将顶点数据存到当前绑定的webGL缓冲区  **/
			const vertices = new Float32Array([
				0.0,0.5,
				-0.5,-0.5,
				0.5,-0.5,
				0.0,0.7,
				 -0.7,-0.7,
				0.7,-0.7
			])
			//创建了一个新的缓冲区对象,存储顶点数据、颜色数据等信息。
			const buffer = gl.createBuffer();
			//将之前创建的缓冲区对象绑定到当前的 WebGL 上下文。
			//gl.ARRAY_BUFFER表示我们绑定的是一个顶点属性的缓冲区,例如顶点位置、纹理坐标等。绑定后,所有针对 gl.ARRAY_BUFFER 的操作都会影响到这个缓冲区对象。			//
			gl.bindBuffer(gl.ARRAY_BUFFER,buffer);
			//将数据传递到刚才绑定的缓冲区中
			//gl.STATIC_DRAW 是一个使用提示,告诉 WebGL 该数据将不会频繁更改,通常用于静态绘图。它帮助 WebGL 对数据进行优化
			gl.bufferData(gl.ARRAY_BUFFER,vertices,gl.STATIC_DRAW)
			
			
			/** 
			 * 	第三步 定义顶点着色器、片元着色器源码
			 * 
			 * 	attribute 用于顶点着色器,定义从顶点缓冲区传入的变量
			 * 	attribute vec2 position 声明一个名为position的顶点属性,它是一个二维向量
			 * 
			 * 	void main() {}:顶点着色器的主函数,计算每个顶点的最终位置。
			 *  vec4(positoin,0.0,1.0) 是一个四维向量,表示顶点的最终位置
			 * 	gl_FragColor = vec4(1.0,0.0,0.0,1.0); 将片元着色器设置为红色,使用vec4表示颜色,RGBA分别为(1.0,0.0,0.0,1.0)
			 *
			**/
			
			//模板引擎方式
			// const vertexShaderSource =`
			// 	attribute vec2 position;
			// 	void main(){
     
			// 		gl_Position = vec4(position,0.0,1.0);
					
			// 	}
			// `;
			
			// const fragmentShaderSource = `
			// 	void main(){
     
			// 		gl_FragColor = vec4(1.0,0.0,0.0,1.0);
			// 	}
			// `;
			
			//通过element获取
			const vertexSource = document.getElementById("vertex-shader").innerText;
			const fragmentSource = document.getElementById("fragment-shader").innerText;
			
			/**
			 * 	第四步 创建顶点着色器对象,并绑定源码,编译;创建片元着色器对象,并绑定源码,,编译
			 *  createShader(gl.VERTEX_SHADER) 创建一个顶点着色器
			 *  createShader(gl.FRAGMENT_SHADER) 创建一个片元着色器
			 *  gl.shaderSource(vertexShader,vertexSource) 将对应的着色器源码绑定到对应的着色器对象
			 *  gl.compileShader(vertexShader) 编译对应的着色器源码
			**/
			const vertexShader = gl.createShader(gl.VERTEX_SHADER);
			gl.shaderSource(vertexShader,vertexSource)
			gl.compileShader(vertexShader);
			const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
			gl.shaderSource(fragmentShader,fragmentSource);
			gl.compileShader(fragmentShader);
			
			
			/**
			 * 	第五步 创建着色器程序对象,并将着色器附着在程序上。
			 * 
			**/
			//创建程序对象
			const program = gl.createProgram();
			//将着色器附着到程序对象
			gl.attachShader(program,vertexShader);
			gl.attachShader(program,fragmentShader);
			//webgl对象链接程序对象,将顶点着色器和片元着色器链接成一个完成的可执行程序
			gl.linkProgram(program);
			//webgl对象使用这个program作为渲染程序
			gl.useProgram(program);
			
			
			/**
			 *  第六步 设置顶点属性
			 */
			//获取顶点属性position在着色器中的程序位置
			const positionLocation = gl.getAttribLocation(program,"position");
			//启用顶点属性数组
			gl.enableVertexAttribArray(positionLocation);
			/**
			 *  gl.vertexAttribPointer(index, size, type, normalized, stride, offset);
			 *  指定顶点数据组的解析方式。
			 *  index:positionLocation 顶点属性position的位置,可以理解为需要将缓冲区数据解析到程序中的哪个位置。通过前面getAttribLocation返回的结果可以看出这是一个整数,指定要修改的顶点属性的索引。它通常是通过调用 
			 *  size:2 每个顶点属性的元素数量,可以理解为从缓冲区取数据时几个数据表示一个点。通过gl_Position = vec4(position,0.0,1.0)可以看出是二维数组,即两个浮点数表示一个点,所以是2.
			 *  type:gl.FlOAT 指定数组中每个组件的数据类型。在这个例子中,gl.FLOAT 表示每个顶点属性数据的类型为 32 位浮点数 (float)
			 *  normalized:false 数据是否应该被标准化处理。这里设置false表示不进行标准化处理,按原值传递。
			 *  stride:0 跨度:在缓冲区获取数据时的跨度,以字节为单位。如果数据连续则跨度为0。WebGL 会根据 size 和 type 自动计算跨度。例如,如果每个顶点都有 (x, y) 坐标,且每个坐标为 32 位浮点数,则步幅为 2 * 4 = 8 字节。
			 *  offset:0  指定缓冲区中的起始位置偏移量,以字节为单位。可以理解为从缓冲区的哪个字节位置开始读取第一个顶点属性。
			 */
			gl.vertexAttribPointer(positionLocation,2,gl.FLOAT,false,0,0);
			
			/**
			 *  第七步 绘制
			 * 
			 * gl.clearColor(0.0,0.0,0.0,1.0) 设置 WebGL 的清屏颜色,也就是背景颜色;
			 * gl.clear(gl.COLOR_BUFFER_BIT) 清除颜色缓冲区,也就是将整个绘图区域用前面指定的清屏颜色(黑色)填充;
			 * 以上与绘制内容无关,可以注释掉查看效果
			 * gl.drawArrays(gl.TRIANGLES,0,3) 绘制三角形,
			 *   gl.TRIANGLES 表示每三个顶点组成一个三角形。如果你有 6 个顶点,则 WebGL 会绘制两个三角形,依此类推。
			 * 	 0: 从顶点数组的第 0 个位置开始绘制。
			 *   3: 表示要绘制的顶点数量。可以理解为有效顶点数据 这里设置5表示5个点有效,即只能绘制出一个三角形
			 * 
			 * gl.POINTS: 绘制一系列点。
			 * gl.LINE_STRIP: 绘制一个线条。即,绘制一系列线段,上一点连接下一点。
			 * gl.LINE_LOOP: 绘制一个线圈。即,绘制一系列线段,上一点连接下一点,并且最后一点与第一个点相连。
			 * gl.LINES: 绘制一系列单独线段。每两个点作为端点,线段之间不连接。
			 * gl.TRIANGLE_STRIP:绘制一个三角带。
			 * gl.TRIANGLE_FAN:绘制一个三角扇。
			 * gl.TRIANGLES: 绘制一系列三角形。每三个点作为顶点。
			 * 
			 */
			// gl.clearColor(0.0,0.0,0.0,1.0);
			// gl.clear(gl.COLOR_BUFFER_BIT);
			// gl.drawArrays(gl.POINTS,0,6);
			// gl.drawArrays(gl.TRIANGLES,0,6);
			gl.drawArrays(gl.LINE_LOOP,0,6);
			gl.drawArrays(gl.LINE_LOOP,4,3);
		</script>
	</body>
	

	

</html>

绘制不同颜色的图形(使用varying)

​ 顶点着色器与片元着色器通过varying定义参数后传递参数。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>firstwebGLDemo</title>
		<style type

http://www.kler.cn/a/295171.html

相关文章:

  • Day 63 || 拓扑排序、dijkstra
  • 设备接入到NVR管理平台EasyNVR多品牌NVR管理工具/设备的音视频配置参考
  • 从0开始学PHP面向对象内容之(常用魔术方法续一)
  • 如何使用IDEA创建Maven/SSM工程?
  • 模型结构及对比
  • 面试:TCP、UDP如何解决丢包问题
  • 【Linux】服务器上在VSCode中运行JupyterNotebook
  • Exchange 服务器地址列表的配置方法与注意事项
  • 物联网之MQTT
  • 计算机视觉中,如何理解自适应和注意力机制的关系?
  • 云手机怎样简化海外社媒平台运营
  • 网关功能介绍
  • ffmpeg命令(详解)
  • 什么是GPT-3的自回归架构?为什么GPT-3无需梯度更新和微调
  • 数学基础 -- 统计学之零均值化
  • 小米Vela:端侧AI推理框架
  • 域名证书,泛域名证书,sni
  • 测试一些概念
  • Flutter集成Firebase框架
  • unity 实现吸血鬼幸存者的随机奖励
  • 基于stm32的河流检测系统-单片机毕业设计
  • u盘显示需要格式化才能用预警下的数据拯救恢复指南
  • CNC数控加工如何开启个性化制造新时代?
  • C++数据结构重要知识点(5)(哈希表、unordered_map和unordered_set封装)
  • 封装触底加载组件
  • ✨机器学习笔记(一)—— 监督学习和无监督学习