WebGL基础-变量控制与颜色修改

1 前言

前文已经完成了WebGL中Hello World的实现,具体参考该文章:WebGL基础概念。也就是绘制一个三角形,这篇文章我们来修改其中的一些参数,改变三角形的颜色,修改三角形的位置等操作。

WebGL探索系列目录传送门

2 修改三角形颜色

还记得我们在片段着色器中给gl_FragColor赋值了么,每个像素都将调用一次片段着色器,每次调用需要从你设置的特殊全局变量gl_FragColor中获取颜色信息。

gl_FragColor = vec4(1, 0, 0.5, 1); // 返回“红紫色”

如果想修改颜色,可以直接在这里修改,如修改为以下代码:

gl_FragColor = vec4(1, 1, 0.5, 1); // 返回黄色

在这里插入图片描述
当然,这样直接写死在片段着色器中的固定值不是我们想要的,可以通过传值的方式传入我们想要的值,一般传值的方式有三种

Uniforms :全局变量
Textures:纹理
Varyings:可变量

由于纹理的内容比较多,所以我们单独开篇讲解,来看一下其他两个。

2.1 使用Uniforms修改颜色

全局变量在一次绘制过程中传递给着色器的值都一样,在下面的一个简单的例子中, 用全局变量给片段着色器添加了颜色。修改片段着色器的定义,加一个uniform的变量u_frag,并赋值给gl_FragColor,这样我们在js代码中修改u_frag即可

const fragmentShaderSource = `
  precision mediump float;
  uniform vec4 u_frag;

  void main() {
    gl_FragColor = u_frag;
  }
`

首先使用getUniformLocation获取一个uniform的变量,注意和getAttribLocation的区别。

const uFrag = gl.getUniformLocation(program, "u_frag");

随后对该变量进行赋值的操作,这样即可通过传递把值传给gl_FragColor,可以实现在js中控制三角形的颜色。

gl.uniform4fv(uFrag, [1, 1, 0.5, 1])

要注意的是全局变量属于单个着色程序,如果多个着色程序有同名全局变量,需要找到每个全局变量并设置自己的值。 我们调用gl.uniform???的时候只是设置了当前程序的全局变量,当前程序是传递给gl.useProgram的最后一个程序。

gl.uniform1f (floatUniformLoc, v);                 // float
gl.uniform1fv(floatUniformLoc, [v]);               // float 或 float array
gl.uniform2f (vec2UniformLoc,  v0, v1);            // vec2
gl.uniform2fv(vec2UniformLoc,  [v0, v1]);          // vec2 或 vec2 array
gl.uniform3f (vec3UniformLoc,  v0, v1, v2);        // vec3
gl.uniform3fv(vec3UniformLoc,  [v0, v1, v2]);      // vec3 或 vec3 array
gl.uniform4f (vec4UniformLoc,  v0, v1, v2, v4);    // vec4
gl.uniform4fv(vec4UniformLoc,  [v0, v1, v2, v4]);  // vec4 或 vec4 array
 
gl.uniformMatrix2fv(mat2UniformLoc, false, [  4x element array ])  // mat2 或 mat2 array
gl.uniformMatrix3fv(mat3UniformLoc, false, [  9x element array ])  // mat3 或 mat3 array
gl.uniformMatrix4fv(mat4UniformLoc, false, [ 16x element array ])  // mat4 或 mat4 array
 
gl.uniform1i (intUniformLoc,   v);                 // int
gl.uniform1iv(intUniformLoc, [v]);                 // int 或 int array
gl.uniform2i (ivec2UniformLoc, v0, v1);            // ivec2
gl.uniform2iv(ivec2UniformLoc, [v0, v1]);          // ivec2 或 ivec2 array
gl.uniform3i (ivec3UniformLoc, v0, v1, v2);        // ivec3
gl.uniform3iv(ivec3UniformLoc, [v0, v1, v2]);      // ivec3 or ivec3 array
gl.uniform4i (ivec4UniformLoc, v0, v1, v2, v4);    // ivec4
gl.uniform4iv(ivec4UniformLoc, [v0, v1, v2, v4]);  // ivec4 或 ivec4 array
 
gl.uniform1i (sampler2DUniformLoc,   v);           // sampler2D (textures)
gl.uniform1iv(sampler2DUniformLoc, [v]);           // sampler2D 或 sampler2D array
 
gl.uniform1i (samplerCubeUniformLoc,   v);         // samplerCube (textures)
gl.uniform1iv(samplerCubeUniformLoc, [v]);         // samplerCube 或 samplerCube array

2.2 使用Varyings修改颜色

varying是一种可以从顶点着色器传值到片段着色器的“可变量”,在顶点着色器中定义一个变量v_color,同样的,在片段着色器中定义同名varying变量,顶点着色器中v_color的值会被传递给片段着色器。当然这不是直接的值传递,而是发生了一系列的内插过程,暂时不讨论这些过程。

const vertexShaderSource = `
  // 一个属性变量,将会从缓冲中获取数据
  attribute vec4 a_position;
  varying vec4 v_color;

  // 所有着色器都有一个main方法
  void main() {
    // gl_Position 是一个顶点着色器主要设置的变量
    v_color = a_position;
    gl_Position = a_position;
  }
`

const fragmentShaderSource = `
  // 片段着色器没有默认精度,所以我们需要设置一个精度
  // mediump是一个不错的默认值,代表“medium precision”(中等精度)
  precision mediump float;
  varying vec4 v_color;

  void main() {
    // gl_FragColor是一个片段着色器主要设置的变量
    gl_FragColor = v_color; // 返回一个颜色
  }
`

顶点着色器中,将a_position的值赋值给v_color,在文中已经对a_position的值进行了定义,则会传给顶点着色器的v_color,同样也传给了片段着色器的v_color,三个顶点的颜色被确定后,其中点颜色通过内插得到。
在这里插入图片描述
回顾一下,我们a_position的赋值为

 0, 0,
 0, 0.5,
 0.7, 0,

顶点的颜色被赋值后,是这样的

rgba(0, 0, 0, 255)
rgba(0, 127, 0, 255)
rgba(180, 0, 0, 255)

得出的三角形是一个多彩的三角形。
在这里插入图片描述

3 顶点坐标的传递过程

下面我们来聊一聊怎么传递顶点的过程

3.1 webgl坐标系

首先我们要先聊一下坐标系,webgl的坐标系是空间坐标系,使用的是右手坐标系,面对屏幕向上为y轴的正方向,向左为正x轴的正方向,垂直于屏幕向外的为z轴的正方向。原点位于屏幕的中心处,坐标抽范围为(-1,1)
在这里插入图片描述
所以我们看下数据,该数据一个点的长度为2,所以一行的两个数据代表两个点,第一个坐标为(0,0),第二个坐标为(0,0.5),第三个坐标为(0.7,0)

const positions = [
  0, 0,
  0, 0.5,
  0.7, 0,
];

3.2 创建buffer并传入数据

那么如何让这样的一串数据传递给了顶点着色器中的变量呢,首先使用使用createBuffer函数创建一个buffer,用来存储顶点或颜色等数据。绑定完数据后,GLSL定义的变量就可以从缓冲区里面获取到想要的数据。

随后使用bindBuffer函数将创建好的buffer绑定到目标。这句代码是激活当前的buffer,因为可能会创建几个buffer,bindBuffer后,GLSL会从该buffer中取数。

使用bufferData函数可以向buffer中注入数据,这里是将positions的数据注入了创建的buffer中。

  // 创建一个缓冲区,并在其中放置三个二维剪辑空间点
  const positionBuffer = gl.createBuffer();

  // 将其绑定到ARRAY_BUFFER
  gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);

  const positions = [
    0, 0,
    0, 0.5,
    0.7, 0,
  ];
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);

3.3 将buffer的数据传入GLSL定义的变量中

数据已经准备好了,那么下面就开始取数了,首先要获取顶点着色器程序中我们定义的attribute变量,使用getAttribLocation函数可以实现。

 // 从顶点着色程序中找到a_position属性
 const positionAttributeLocation = gl.getAttribLocation(program, "a_position");

获取到了顶点的变量和buffer的数据,就可以开始给顶点变量赋值了。赋值操作主要使用vertexAttribPointer函数。

该函数共有六个参数,第一个便是需要赋值的变量,我们这里的值为positionAttributeLocation 。第二个值是每次迭代运行提取的单位数据,在我们的项目中,相当于是一次取positions 数组的数量,赋值为2时,代表一个顶点有两个值是从positions 中获取的,vec4中的其他值会自动补全。positions 数组长度为6,则一共可以生成三个顶点。

第三个参数定义了数据类型,这里使用的是浮点型,所以使用了gl.FLOAT,第四个参数是一个布尔值,是否需要归一化,我们的数据已经是[-1,-1]之间的数据,所以不做归一化。

第五个参数是相邻两个顶点间的字节数,在我们的项目中,该值为0,因为所有的数据都是顶点的数据,没有在buffer中传入颜色的数据,所以顶点是紧挨着的,该值为0。第六个参数是指定缓冲对象的偏移量,我们这里是从数组的第一个值开始的,所以也是0。

 // 告诉属性怎么从positionBuffer中读取数据 (ARRAY_BUFFER)
 const size = 2;          // 每次迭代运行提取两个单位数据
 const type = gl.FLOAT;   // 每个单位的数据类型是32位浮点型
 const normalize = false; // 不需要归一化数据
 const stride = 0;        // 0 = 移动单位数量 * 每个单位占用内存(sizeof(type))
                       // 每次迭代运行运动多少内存到下一个数据开始点
 const offset1 = 0;        // 从缓冲起始位置开始读取
 gl.vertexAttribPointer(
     positionAttributeLocation, size, type, normalize, stride, offset1)

3.4 修改三角形的位置与形状

让我们修改当前三角形的位置与形状。直接修改positions即可

const positions = [
  -1, -1,
  0.4, 1,
  0.7, 0,
];

.

4 使用offset在positions中取值

我们已经知道了如何在定义的数据中取值,但是目前顶点位置与颜色的值是一样的,我们来修改一下positions的值,使顶点位置与颜色值分开。

将positions添加几个参数。

const positions = [
// 顶点		 颜色
  0, 0, 	1.0, 0, 1.0,
  0, 0.5, 	0, 1.0, 0,
  0.7, 0, 	1.0, 1.0, 0
];
const positionFloat = new Float32Array(positions)

前两个参数控制顶点的坐标,后三个参数控制片元的颜色。首先,在定义着色器时新增一个变量a_color,用于控制颜色。

const vertexShaderSource = `
  // 一个属性变量,将会从缓冲中获取数据
  attribute vec4 a_position;
  attribute vec4 a_color;
  varying vec4 v_color;

  // 所有着色器都有一个main方法
  void main() {
    // gl_Position 是一个顶点着色器主要设置的变量
    v_color = a_color;
    gl_Position = a_position;
  }
`

const fragmentShaderSource = `
  // 片段着色器没有默认精度,所以我们需要设置一个精度
  // mediump是一个不错的默认值,代表“medium precision”(中等精度)
  precision mediump float;
  varying vec4 v_color;

  void main() {
    // gl_FragColor是一个片段着色器主要设置的变量
    gl_FragColor = v_color; // 返回一个颜色
  }
`

随后在获取属性时,获取a_color的属性,并开启该属性。

const aColor = gl.getAttribLocation(program, "a_color");
gl.enableVertexAttribArray(aColor);  

计算每个单位占用的内存,并分配数据。

// 计算这种数据类型占据的字节数
const FSIZE = positionFloat.BYTES_PER_ELEMENT

// 分配数据
gl.vertexAttribPointer(positionAttributeLocation, 2, gl.FLOAT, false, FSIZE * 5, 0)
gl.vertexAttribPointer(aColor, 3, gl.FLOAT, false, FSIZE * 5, FSIZE * 2)

运行后的展示为:
在这里插入图片描述
这样就利用vertexAttribPointerstrideoffset对同一块buffer数据进行了存取。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
webgl-fingerprint-defende.crx 是一个浏览器扩展文件,它的作用是提供WebGL指纹防御功能。WebGL是一种用于在网页浏览器中渲染3D图形的技术,而指纹则是通过收集浏览器和计算机的信息来识别用户身份的一种方法。 通常,浏览器会从操作系统和硬件中收集一些信息来创建一个独特的指纹识别码。这个识别码可以随着浏览器的使用而变化,因此可以用作用户识别。然而,一些网站可能会滥用这种技术来跟踪用户的在线行为,侵犯用户隐私。 webgl-fingerprint-defende.crx 文件可以帮助用户保护自己的隐私,防止被WebGL指纹识别出来。它通过修改浏览器的WebGL指纹数据,使之变得随机或无法识别。这样,即使网站尝试使用WebGL指纹进行用户跟踪,也无法准确识别用户的真实身份。 使用 webgl-fingerprint-defende.crx 文件可以有效地防止被WebGL指纹追踪,保护用户的个人隐私。它的安装和使用也非常简单,只需将文件添加到浏览器的扩展管理页面即可。然后,在用户浏览网页时,该扩展将自动激活并对WebGL指纹进行保护。 需要注意的是,虽然这个扩展可以有效防止WebGL指纹追踪,但在使用时仍需注意个人隐私的其他方面。同时,由于浏览器和WebGL技术的不断更新和演变,扩展的效果可能会有所变化。因此,保持扩展的更新和关注相关的隐私保护措施是很重要的。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值