webGL学习-程序员宅基地

技术标签: 学习  webgl  javascript  

1 初试webGL

const canvas = document.getElementById('canvas')
//获取webgl上下文对象 相当于设置画笔
const gl = canvas.getContext('webgl')
//声明颜色
gl.clearColor(0,0,0,1)

gl.clear(gl.COLOR_BUFFER_BIT)

2 将rbga颜色设置为webgl颜色

使用three.js的color

const color = new Color('rgba(255,1,2,1)')

3 webgl坐标系

坐标中心位于原点,y轴方向朝上,其余和正常坐标系一致

4 webgl绘图步骤

  1. 建立canvas画图
  2. 获取canvas画布
  3. 使用canvas获取wegbl绘图上下文
  4. 在script中建立顶点着色器和片元着色器
<script id="vertexShader" type="x-shader/x-vertex">
<script id="fragmentShader" type="x-shader/x-fragment">
  1. 初始化着色器

      //获取着色器文本
      const vsSource = document.querySelector("#vertexShader").innerHTML;
      const fsSource = document.querySelector("#fragmentShader").innerHTML;
      //初始化着色器
      initShaders(gl, vsSource, fsSource);

      function initShaders(gl, vsSource, fsSource) {
    
        //创建程序对象
        const program = gl.createProgram();
        //建立着色对象
        const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);
        const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);
        //把顶点着色对象装进程序对象中
        gl.attachShader(program,vertexShader)
        gl.attachShader(program,fragmentShader)
        //连接webgl上下文对象和程序对象
        gl.linkProgram(program)
        //启动程序对象
        gl.useProgram(program)
        //将程序对象挂载到上下文对象中
        gl.program = program
        return true
      }

      function loadShader(gl,type,source){
    
        //根据着色类型,建立着色器对象
        const shader = gl.createShader(type)
        //将着色器源文件传入着色器对象中
        gl.shaderSource(shader,source)
        //编译着色器对象
        gl.compileShader(shader)
        return shader
      }

5 着色器

着色器语言是GLSL ES语言

  • 顶点着色器:描述顶点的特征,如位置、颜色
  • 片元着色器:进行逐片元处理,如光照

着色器编程

void main(){
    
	gl_Position = vec4(x,y,z,1.0);
	gl_PointSize = 100.0;
	gl_FragColor = vec4(r,g,b,a)
}

着色器初始化

//建立程序对象
const shader = gl.createProgram()

//建立着色对象
const vertexShader = loadShader(gl,gl.VERTEX_SHADER,vsSource)
const fragShader = loadShader(gl,gl.FRAGMENT_SHADER,fsSource)

//将着色器对象装入程序对象中
gl.attachShader(program,vertexShader)
gl.attachShader(program,fragmentShader)

//连接webgl上下文对象和程序对象
gl.linkProgram(program)

//启动程序对象
gl.useProgram(program)

gl.program = program


function loadShader(gl,type,source){
    
	//根据着色器类型,建立着色器对象
	const shader = gl.createShader(type)
	//将着色器对象放入着色器源文件中
	gl.shaderSource(shader,source)
	//编译着色器对象
	gl.compileShader(shader)
	return shader
}

attribute变量及设置:

const position = gl.getAttribLocation(gl.program,'z_position')

//设置前3各值
gl.vertexAttrib3f(position,0,0,0)

6 获取鼠标点在webgl坐标系中的位置

webgl是同步绘图是由颜色缓冲区导致的,颜色缓冲区中存储的图像只在当前线程有效;在执行异步线程时,颜色缓冲区会被重置

canvas.addEventListener('click',(e)=>{
    
	const {
     clientX,clientY } = e
	const {
    left,top,width,height} = gl.getBoundingClientRect()
	const [ cssX,cssY ] = [clientX-left,clientY-top]
	const [halfWidth,halfHeight] = [width/2,height/2]
	const [ x,y ] =  [(cssX-halfWidth)/halfWidth,(halfHeight-cssY)/halfHeight]
	a.points.push({
    x,y})
	render()
})

function render(){
    
	gl.clear(gl.COLOR_BUFFER_BIT)
	a.points.forEach(({
     x,y})=>{
    
		gl.vertexAttrib2f(a_position,x,y)
		gl.drawArrays(gl.POINTS,0,1)
	})
}

7 修改顶点颜色

使用uniform限定符

const u_fragColor= gl.getUniformLocation(gl.program,'u_fragColor')
gl.uniform4f(u_fragColor,0,0,0,0)
const arr = new Float32Array([r,g,b,a])
gl.uniform4fv(u_fragColor,arr)

8 鼠标绘制星空

设置切片范围

precision mediump float;
uniform rec4 u_fragcolor;
void main(){
    
	float dist = distance(gl_PointCoord,rec2(0.5,0.5));
	if(dist<0.5){
    
		gl_FragColor = u_fragcolor;	
	}else {
    
		discard;
	}
}

9 设置颜色透明度

需要开启片元的颜色合成功能

gl.enable(gl.BLEND)
//设置片元的合成方式
gl.blendFunc(gl.SRC_ALPHA,gl.ONE_MINUS_SRC_ALPHA)

10 绘制多个点

//设置顶点坐标
const vertices = new Float32Array([0,0,0.1,0.1,0.2,0.2])
//建立顶点缓冲区
const vertexBuffer = gl.createBuffer()
//绑定缓冲区对象
gl.bindBuffer(gl.ARRAY_BUFFER,vertexBuffer)
//写入顶点数据
gl.bufferData(gl.ARRAY_BUFFER,vertices,gl.STATIC_DRAW)
//获取attribute变量
const a_position = gl.getAttribLocation(gl.program,'a_position')
//设置attribute变量
gl.vertexAttribPointer(a_position,2,gl.FLOAT,false,0,0)
gl.clearColor(0,0,1,1)
gl.clear(gl.COLOR_BUFFER_BIT)
gl.drawArrays(gl.POINTS,0,3)

11 绘制线

  • LINES:每两点连线
  • LINE_STRIP:连接所有点成线
  • LINE_LOOP:形成闭环

12 判断三角形的第三个顶点是否处于正半边

有A(x1,y1)、B(x2,y2)、C(x3,y3)

const abX = x2-x1
const abY = y2-y1
const acX = x3-x1
const acY = y3-y1

const dist = abX*acY - abY*acX

if(dist>0){
    
	return true
} 

13 旋转

无论绕那个轴,从正半轴向正半轴逆时针旋转都是正

(1)先移动后旋转
移动到相应位置后,按原来的中心点进行旋转

(2)先旋转后移动
先按中心点旋转,然后再位移

绕z轴逆时针旋转角度:[[cosθ,-sinθ],[sinθ,cosθ]]

14 视图矩阵

  • 视点:相机的位置
  • 视线方向:相机所看的方向
  • 上方向:相机绕视线转动的方向

三维向量叉乘

x={
    ax,ay,az}
y = {
    bx,by,bz}

cross(x,y)=(ay*bz-az*by,)

生成视图矩阵

function getViewMatrix(e, t, u){
    
	const c = new Vector3().subVectors(e, t).normalize()
	const a = new Vector3().corssVectors(u, c).normalize()
	const b = new Vector3().crossVectors(c, a).normalize()
	const mr = new Matrix4().set(
		...a,0,
		...b,0,
		-c.x,-c.y,-c.z,0,
		0,0,0,1
	)
	const mt = new Matrix4().set(
		1,0,0,-e.x,
		0,1,0,-e.y,
		0,0,1,-e.z,
		0,0,0,1	
	)
	return mr.multiple(mt).elements
}

15 多attribute数据合一

//按列拼接
const source = new Float32Array([])
//元素字节数
const elementBytes = source.BYTES_PRE_ELEMENT
//变量长度
const verticeSize = 3
const colorSize = 4
//总长度
const category = verticeSize + colorSize
//总字节数
const categoryBytes = catefory*elementBtyes
//变量索引
const verticeIndex = 0
const colorIndex = verticeSize * elementBytes
//顶点总数
const sourceSize = source.length/categorySize

//设置某个attribute变量
//gl.vertexArrtibPointer(index,size,type,normalized,stride,offset)
const a_color = gl.getAttribLocation(gl.program,'a_color')
gl.vertexAttribPointer(
	a_color,
	colorSize,
	gl.FLOAT,
	false,
	categoryBytes,
	colorIndex
)

16 纹理

//将图片上下对称翻转坐标轴
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL)

//激活纹理单元
gl.activeTexture(gl.TEXTURE0)
//创建纹理对象
const texture = gl.createTexture()
//将纹理对象装进纹理单元中
gl.bindTexture(gl.TEXTURE_2D,texture)
//创建图像
const image = new Image()
img.src = ''
img.onlaod = function(){
    
gl.texImage2D(gl.TEXTURE_2D,0,gl.RGB,gl.RGB,gl.UNSIGNED_BYTE,image)
gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.LINEAR)
//防止非2的n次幂图像无法显示
gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_S,gl.CLAMP_TO_EDGE)

gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_T,gl.CLAMP_TO_EDGE)

}

纹理混合:mix(m,n,a):m+(n-m)*a

跨域贴图:设置image.setAttribute(‘crossOrigin’,‘Anonymous’)

17 GLSL ES语言

  1. 结构体:struct
struct Light{
    
	vec4 color;
	vec3 pos;
};

void main(){
    
	Light l1 = Light(
		vec4(255,255,0,255),
		vec3(1,2,3)
	)
	gl_FragColor = l1.color/255.0;
}
  1. 数组
vec4 vs[2];
vs[0]=vec4();


const int n=2;
vec4 vs[n];
  1. for循环
    for循环的循环变量必须是int或float
for(int i=0;i<3;i++){
    }

for(float i=0.0;i<4.0;i++){
    }
  1. 函数
//不会影响原始数据,如果想修改原始数据要使用out
void setLum(in vec3 color){
    
	color.y = 255.0
}
  1. 设置精度
    精度有:highp、mediump、lowp,float是没有默认精度的
//设置某个变量的精度
mediump float size;

//设置某种数据类型的精度
precision mediump float;
  1. 设置颜色渐变
//获取片元的投影长度
//以投影长度比例乘以颜色差值获得该点的颜色

18 四元数

在这里插入图片描述
例如有一点p需要绕OC2轴旋转ang度,那么可以让c2旋转到z轴对齐,然后点p绕z轴旋转ang度,然后再旋转回来

在这里插入图片描述
如何旋转到Z轴?C2旋转B2OB1度到C3,然后C3旋转C3OB1度到Z轴

//three.js中采用四元数旋转
const quaternion = new Quaternion()
quaternion.setFromAxisAngle(oc2,ang)
const m = new Matrix4()
m.makeRotationFromQuaternion(quaternion)
p1.clone().applyMatrix4(m)

19 正交投影矩阵

顶点在空间中的位置投影矩阵\*视图矩阵\*模型矩阵*顶点的初始位置

正交投影矩阵=缩放矩阵*位移矩阵

const projectMatrix = new Matrix4()
//定义相机世界高度的一半
const halfH = 2
//计算画布的宽高比
const ratio = canvas.width/canvas.height
//计算相机的宽度
const halfW = halfH*ratio
//定义相机的6个边界
const [left,right,top,bottom,near,far]=[
	-halfW,halfW,halfH,-halfH,0,4
]

//获取正交投影矩阵
projectionMatrix.makeOrthographic(left,right,top,bottom,near,far)
 

20 视图位移

const camera = new OrthographicCamera(left,right,top,bottom,near,far)

camera.position.set(0,0,3)
camera.updateWorldMatrix(true)

const pvMatrix = new Matrix4().multiplyMatrices(
	camera.projectionMatrix,
	camera.matrixWorldInverse
)

21 视图旋转

const eye = new Vector3(1,2,3)
const target = new Vector3(0,0,0)
const up = new Vector3(1,1,1)

const camera = new OrthographicCamera(left,right,top,bottom,near,far)
camera.position.set(eye)

camera.lookat(target)
camera.updateWorldMatrix(true)

//计算投影矩阵
const pvMatrix = new Matrix4().multiplyMatrices(
	camera.projectionMatrix,
	camera.matrixWorldInverse
)

原理:

//位移矩阵
const positionMatrix = new Matrix4().setPosition(eye)

//旋转矩阵
const rotationMatrix = new Matrix4().lookAt(eye,target,up)

//计算相机的视图矩阵
const viewMatrix = new Matrix4().multiplyMatrices(
	positionMatrix,rotationMatrix
)

//投影视图矩阵
const pvMatrix = new Matrix4().multiplyMatrices(
	camera.projectionMatrix,viewMatrix
)

22 透视投影矩阵

在这里插入图片描述
两种数据间的转换关系为y=k*x+b
其中k=(maxM-minM)/(maxN-minN)以及b=minM-k*minN
在这里插入图片描述

在这里插入图片描述

  • fov:相机视锥体垂直视野角度
  • aspect:摄像机视锥体宽高比
  • near:近裁剪面到视点的距离
  • far:远裁剪面到视点的距离

在这里插入图片描述

//在three.js中使用透视投影矩阵
//建立透视相机
const [fov,aspect,near,far] = [45,canvas.width/canvas.height,1,20]

const camera = new PerspectiveCamera(fov,aspect,near,far)

23 对投影矩阵、视图矩阵、模型矩阵的理解

  • 模型矩阵:相当于更改物体的位置
  • 视图矩阵:相当于改变相机位置
  • 投影矩阵:将顶点坐标变换到裁剪坐标

24 相机轨道控制器

(1)设置相机位移轨道

//鼠标事件
const mouseButtons = new Map([
	[2, 'pan']
])

//轨道控制器状态,'pan'代表位移
let state = 'none'

//鼠标拖拽的起始和结束位置
const dragStart = new Vector2()
const dragEnd = new Vector2()

//鼠标移动的位移量
const panoffset = new Vector3()

//鼠标垂直拖拽,是基于y轴还是z轴
// true:y false:z
const screenSpacePanning = true

//取消右击菜单显示
canvas.addEventListener('contextmenu',event=>{
    
	event.preventDefault()
})

//指针按下时,设置拖拽起始位,获取轨道控制器状态
canvas.addEventListener('pointerdown',({
     clientX,clientY,button})=>{
    
	dragStart.set(clientX,clientY)
	state = mouseButtons.get(button)
})

//指针平移时,如果控制器处于移动状态,平移相机
canvas.addEventListener('pointermove',(event)=>{
    
	switch(case){
    
		case 'pan':
			handleMouseMovePan(event)	
	}
})

//指针抬起,清楚控制器状态
canvas.addEventListener('pointerup',(event)=>{
    
	state = 'none'
})

const handleMouseMovePan = ({
     clientX,clientY,button})=>{
    
	dragEnd.set(clientX,clientY)
	//基于拖拽距离拖拽相机
	pan(dragEnd.clone().sub(dragStart))
	//重置起始点位置
	dragStart.clone(dragEnd)
}	

//相机移动是基于鼠标在近裁剪面上的位移量来移动的
const pan = (delta)=>{
    
	//相机近裁剪面尺寸
	const cameraWidth = camera.right - camera.left
	const cameraHeight = camera.top - camera.bottom
	//指针拖拽量在画布中的比值
	const ratioX = delta.x / canvas.clientWidth
	const ratioY = delta.y / canvas.clientHeight
	//将像素单位的位移量转换为近裁剪面上的位移量
	const distanceLeft = ratioX * cameraWidth
	const distanceUp = ratioY * cameraHeight
	//相机本地坐标系的x轴 取相机本地坐标系第一列作为x轴
	const mx = new Vector3().setFromMatrixColumn(camera.matrix,0)
	//相机x轴位移量
	const vx = mx.clone().multiplyScalar(-distanceLeft)
	//相机z/y轴平移量
	const vy = new Vector3()
	if (screenSpacePanning){
    
		vy.setFromMatrixColumn(camera.matrix,1)
	} else {
    
	//-z向
	//相机的上方向叉乘x轴会得到-z轴 x轴叉乘上方向得到z轴
		vy.crossVectors(camera.up,mx)
	}
	vy.multiplyScalar(distanceUp)
	//整合平移量
	panoffset.copy(vx.add(vy))
	update()
}

const update = ()=>{
    
	//移动相机的目标点
	target.add(panoffset)
	//移动相机视点
	camera.position.add(panoffset)
	//看向目标点
	camera.lookAt(target)
	//更新相机世界坐标系
	camera.updateWorldMatrix(true)
	//计算投影视图矩阵
	pvMatrix.multiplyMatrix(
		camera.projectionMatrix,
		camera.matrixWorldInverse,
	)
	render()	
}

(2)设置相机旋转轨道


(3)设置相机缩放轨道
主要是让在同一深度上的东西更多或者更少

//定义缩放系数
const zoomScale = 0.95

//添加滚动事件
canvas.addEventListener('wheel',handleMouseWheel)

const handleMouseWheel = ({
     deltaY})=>{
    
	if(deltaY<0){
    
		dolly(1/zoomScale)	
	} else if (deltaY>0) {
    
		dolly(zoomScale)
	}
	update()
}




25 BufferGeometry和Geometry的区别

  • BufferGeometry的数据以连续的方式存储,能够节省传递数据到gpu的时间,在处理大规模数据或复杂模型时更具优势,能减少向gpu传输数据所需的开销
  • Geometry的数据存储方式是非缓冲的,即每个顶点的属性都会保存在一个单独的数组中,这种存储方式使Geometry更容易读写,但是运行效果不如BufferGeometry
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_44208404/article/details/127829525

智能推荐

ring3下的注入dll_ring3注入dll-程序员宅基地

文章浏览阅读437次。注入DLL是个古老的技术,但是应用很广泛,特别在ring3下注入的方法通常是3种一.通过注册表键去写,这种方法的缺点是要等到系统重启后才能加载,优点就是能方便注入多个,某些恶意软件通过这个方式,注入大量的DLL有时候导致Explorer.exe的线程等待很长时间才能进入桌面二.通过消息钩子,消息钩子的原理是这样的,我从看雪上得知的,如果你设置一个消息钩子,每当某个进程处理消息的时候会检查是否存在钩子,如果存在,将试图把DLL加载进来处理钩子,这样,DLL就轻松进入的进程例子就是中的一个HOOK MESSAG_ring3注入dll

CSS 颜色代码大全 CSS颜色对照表-程序员宅基地

文章浏览阅读4.6w次,点赞42次,收藏384次。HTML及CSS常用颜色英文词汇 黑色 银色 灰色 白色 茶色 红色 紫色 紫红 black silver gray white maroon red purple fuchsia #000000 #C0C0C0 _css颜色

安卓在使用上下文菜单时遇到的问题_context-menu问题-程序员宅基地

文章浏览阅读259次。1、在使用contextMemu时最基本的实现就是长按listView的一个item然后弹出一个选项菜单,但是在contextMenu都配置完以后发现长按不会出现菜单。问题:由于在listView适配器中设置了关于item的点击事件,覆盖掉了长按事件。解决办法:将在adpter定义的onclick事件取消改为在main.activity中使用setOnItemClickListener来配置listView的点击方法。 @Override public v_context-menu问题

CSS3新增特性(二)

接上一篇,CSS3新增特性,包括 2D 转换(位移、缩放、旋转、倾斜)和 3D 转换,以及动画。

CSS中的圆角和阴影

在 CSS3 中,新增了圆角边框样式,这样我们的盒子就可以变圆角了。(必需值)水平阴影(horizontal shadow),可以为负值。(必需值)水平阴影(horizontal shadow),可以为负值。(必需值)垂直阴影(vertical shadow),可以为负值。(必需值)垂直阴影(vertical shadow),可以为负值。(可选值)将外(盒子的背面)阴影改为内(盒子之上)阴影。CSS3 中新增了盒子阴影,可以使用。属性为盒子添加阴影。(可选值)阴影模糊程度。(可选值)阴影模糊程度。

springcloud第4季 springcloud-alibaba之sentinel2

多语言异构化服务架构的流量治理组件,主要以流量为切入点,从。等多个维度来帮助开发者保障服务的稳定性。sentinel是面向。

随便推点

STM32F103——GPIO八种工作模式_stm32f103微控制器gpio工作模式的各自特点-程序员宅基地

文章浏览阅读2.7k次,点赞7次,收藏17次。STM32F103GPIO八种工作模式解析。_stm32f103微控制器gpio工作模式的各自特点

[filemgmt 56-313] Exception caught in getCurrentGraph(): bad allocation_vivado bad allocation-程序员宅基地

文章浏览阅读594次。在使用vivado进行开发的过程中,遇到系统报错如下[filemgmt 56-313] Exception caught in getCurrentGraph(): bad allocatio在address editor中发现有IP的地址并没有分配,点击右键也不会出现assign address的选项,所以推测是时钟域的问题,后来经过查看block designs,发现该IP连接AXI的时钟使用错了。更改连线之后解决。..._vivado bad allocation

面经Java开发-程序员宅基地

文章浏览阅读804次,点赞17次,收藏19次。1、这段代码的输出结果是多少?

java分割PDF文件——itextpdf_itextpdf.text.document 两个隔开-程序员宅基地

文章浏览阅读997次。动机:使用Java将PDF论文分割成一个个4页大小的PDF,便于使用有道翻译免费翻译PDF文档(因为每次只免费翻译4页,使用了不少翻译软件,还是有道翻译好用,翻译质量好,就是收费);顺便练习下写代码。使用的idea平台,导出了可执行的jar包。import com.itextpdf.text.Document;import com.itextpdf.text.DocumentExcepti..._itextpdf.text.document 两个隔开

WSL2编译内核并更改替换内核版本_linux-msft-wsl-5.15.123.1+linux-msft-wsl-6.1.21.2-程序员宅基地

文章浏览阅读4.1k次,点赞5次,收藏20次。WSL2支持完整的,并且支持微软官方优化的内核,因此可以使用提供的内核代码进行自主编译。本次教程,以在Ubuntu 22.04.1 LTS为例展现如果更换WSL的内核。_linux-msft-wsl-5.15.123.1+linux-msft-wsl-6.1.21.2

前端table组件封装_大型项目表格封装前端-程序员宅基地

文章浏览阅读277次。前端表格组件是现代Web应用程序中常见的UI控件之一,也是前端开发人员最常用的控件之一。在实际项目中,一个好的前端表格组件必须具备稳定性、易用性和扩展性等特点。因此,对于前端表格的封装技术非常重要。最后,在项目中使用前端表格组件时,需要谨慎选择。一个好的前端表格组件应该是稳定、高效和易用的,并且需要与项目架构和UI风格相匹配。_大型项目表格封装前端

推荐文章

热门文章

相关标签