WebGL之使用着色器将颜色应用于 WebGL

在之前的展示中我们已经创建好了一个正方形,接下来我们要做的就是给它添加一抹色彩。添加颜色可以通过修改着色器来实现。

给顶点着色

在 WebGL 中,物体是由一系列顶点组成的,每一个顶点都有位置和颜色信息。在默认情况下,所有像素的颜色(以及它所有的属性,包括位置)都由线性插值计算得来,自动形成平滑的渐变。我们以前的顶点着色器没有给顶点添加任何特定的颜色——在顶点着色器与片段着色器之间给每个像素着白色,于是整个正方形被渲染成纯白。

现在我们假设正方形的每个顶点使用不同的颜色:红,黄,绿,白,以此渲染一个渐变的色彩。第一步,要给这些顶点建立相应的颜色。首先我们要创建一个顶点颜色数组,然后将它们存在 WebGL 的缓冲区中。为实现这一功能,我们在 initBuffers() 函数中加入如下代码:

function initColorBuffer(gl) {const colors = [1.0,1.0,1.0,1.0, // 白1.0,0.0,0.0,1.0, // 红0.0,1.0,0.0,1.0, // 绿0.0,0.0,1.0,1.0, // 蓝];const colorBuffer = gl.createBuffer();gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);return colorBuffer;
}

这段代码首先建立了一个 JavaScript 的数组,此数组中包含四组四值向量,每一组向量代表一个顶点的颜色。然后,创建一个 WebGL 缓冲区用来存储这些颜色——将数组中的值转换成 WebGL 所规定的浮点型后,存储在该缓冲区中。

当然,我们也需要从 initBuffers() 中调用这个新函数,并返回它创建的新缓冲区。
为了实际使用这些颜色,我们继续修改顶点着色器,使得着色器可以从颜色缓冲区中正确取出颜色:

// Vertex shader programconst vsSource = `attribute vec4 aVertexPosition;attribute vec4 aVertexColor;uniform mat4 uModelViewMatrix;uniform mat4 uProjectionMatrix;varying lowp vec4 vColor;void main(void) {gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition;vColor = aVertexColor;}`;

与之前相比,这段代码的关键不同点在于:每个顶点都与一个颜色数组中的数值相连接。

给片段着色

为使每个像素都得到插值后的颜色,我们只需要在此从 vColor 变量中获取这个颜色的值:

// Fragment shader programconst fsSource = `varying lowp vec4 vColor;void main(void) {gl_FragColor = vColor;}`;

带颜色的绘制

接下来,我们要初始化颜色属性,以便着色器程序使用

// Collect all the info needed to use the shader program.
// Look up which attributes our shader program is using
// for aVertexPosition, aVertexColor and also
// look up uniform locations.
const programInfo = {program: shaderProgram,attribLocations: {vertexPosition: gl.getAttribLocation(shaderProgram, "aVertexPosition"),vertexColor: gl.getAttribLocation(shaderProgram, "aVertexColor"),},uniformLocations: {projectionMatrix: gl.getUniformLocation(shaderProgram, "uProjectionMatrix"),modelViewMatrix: gl.getUniformLocation(shaderProgram, "uModelViewMatrix"),},
};

然后,我们便可以修改 drawScene() 使之在绘制正方形时使用这些颜色:

// draw-scene.js
function setColorAttribute(gl, buffers, programInfo) {const numComponents = 4;const type = gl.FLOAT;const normalize = false;const stride = 0;const offset = 0;gl.bindBuffer(gl.ARRAY_BUFFER, buffers.color);gl.vertexAttribPointer(programInfo.attribLocations.vertexColor,numComponents,type,normalize,stride,offset,);gl.enableVertexAttribArray(programInfo.attribLocations.vertexColor);
}

完整代码如下:

<!DOCTYPE html>
<html lang="en"><head><meta charset="utf-8" /><title>WebGL Demo</title><scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/gl-matrix/2.8.1/gl-matrix-min.js"integrity="sha512-zhHQR0/H5SEBL3Wn6yYSaTTZej12z0hVZKOv3TwCUXT1z5qeqGcXJLLrbERYRScEDDpYIJhPC1fk31gqR783iQ=="crossorigin="anonymous"defer></script><script src="webgl-demo.js" type="module"></script></head><body><canvas id="glcanvas" width="640" height="480"></canvas></body>
</html>
// webgl-demo.js
import { initBuffers } from "./init-buffers.js";
import { drawScene } from "./draw-scene.js";main();function main() {const canvas = document.querySelector("#glcanvas");// Initialize the GL contextconst gl = canvas.getContext("webgl");// Only continue if WebGL is available and workingif (gl === null) {alert("Unable to initialize WebGL. Your browser or machine may not support it.");return;}// Set clear color to black, fully opaquegl.clearColor(0.0, 0.0, 0.0, 1.0);// Clear the color buffer with specified clear colorgl.clear(gl.COLOR_BUFFER_BIT);// Vertex shader programconst vsSource = `attribute vec4 aVertexPosition;attribute vec4 aVertexColor;uniform mat4 uModelViewMatrix;uniform mat4 uProjectionMatrix;varying lowp vec4 vColor;void main(void) {gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition;vColor = aVertexColor;}`;// Fragment shader programconst fsSource = `varying lowp vec4 vColor;void main(void) {gl_FragColor = vColor;}`;// Initialize a shader program; this is where all the lighting// for the vertices and so forth is established.const shaderProgram = initShaderProgram(gl, vsSource, fsSource);// 收集shader program.// 查找使用到了哪些shader program// 获取aVertexColor和aVertexPosition变量// 查找uniform locations.const programInfo = {program: shaderProgram,attribLocations: {vertexPosition: gl.getAttribLocation(shaderProgram, "aVertexPosition"),vertexColor: gl.getAttribLocation(shaderProgram, "aVertexColor"),},uniformLocations: {projectionMatrix: gl.getUniformLocation(shaderProgram,"uProjectionMatrix"),modelViewMatrix: gl.getUniformLocation(shaderProgram, "uModelViewMatrix"),},};// Here's where we call the routine that builds all the// objects we'll be drawing.const buffers = initBuffers(gl);// Draw the scenedrawScene(gl, programInfo, buffers);
}// 初始化顶点着色器和片着色器
function initShaderProgram(gl, vsSource, fsSource) {const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);// Create the shader programconst shaderProgram = gl.createProgram();gl.attachShader(shaderProgram, vertexShader);gl.attachShader(shaderProgram, fragmentShader);gl.linkProgram(shaderProgram);// If creating the shader program failed, alertif (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {alert(`Unable to initialize the shader program: ${gl.getProgramInfoLog(shaderProgram)}`);return null;}return shaderProgram;
}// 加载和编译着色器
function loadShader(gl, type, source) {const shader = gl.createShader(type);// Send the source to the shader objectgl.shaderSource(shader, source);// Compile the shader programgl.compileShader(shader);// See if it compiled successfullyif (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {alert(`An error occurred compiling the shaders: ${gl.getShaderInfoLog(shader)}`);gl.deleteShader(shader);return null;}return shader;
}
// init-buffers.js
function initBuffers(gl) {const positionBuffer = initPositionBuffer(gl);const colorBuffer = initColorBuffer(gl);return {position: positionBuffer,color: colorBuffer,};
}
// 设置顶点缓存
function initPositionBuffer(gl) {// Create a buffer for the square's positions.const positionBuffer = gl.createBuffer();// Select the positionBuffer as the one to apply buffer// operations to from here out.gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);// Now create an array of positions for the square.const positions = [1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, -1.0];// Now pass the list of positions into WebGL to build the// shape. We do this by creating a Float32Array from the// JavaScript array, then use it to fill the current buffer.gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);return positionBuffer;
}
// 将顶点颜色写入缓冲区
function initColorBuffer(gl) {const colors = [1.0,1.0,1.0,1.0, // white1.0,0.0,0.0,1.0, // red0.0,1.0,0.0,1.0, // green0.0,0.0,1.0,1.0, // blue];const colorBuffer = gl.createBuffer();gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);return colorBuffer;
}export { initBuffers };
// draw-scene.js
function drawScene(gl, programInfo, buffers) {gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear to black, fully opaquegl.clearDepth(1.0); // Clear everythinggl.enable(gl.DEPTH_TEST); // Enable depth testinggl.depthFunc(gl.LEQUAL); // Near things obscure far thingsgl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);const fieldOfView = (45 * Math.PI) / 180; // in radiansconst aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;const zNear = 0.1;const zFar = 100.0;const projectionMatrix = mat4.create();// 创建一个透视投影矩阵,该矩阵定义了观察者视角下的透视效果,用于将 3D 场景投影到 2D 屏幕上,实现透视效果mat4.perspective(projectionMatrix, fieldOfView, aspect, zNear, zFar);// Set the drawing position to the "identity" point, which is// the center of the scene.const modelViewMatrix = mat4.create();// 将模型视图矩阵modelViewMatrix 沿着世界坐标系的z轴负方向移动6个单位mat4.translate(modelViewMatrix, // 表示结果存储的目标矩阵,即进行平移操作后的矩阵将存储在这里。modelViewMatrix, // 表示要进行平移操作的原始矩阵,即待平移的矩阵。[-0.0, 0.0, -6.0] // 表示一个包含 x、y 和 z 坐标的数组,指定了平移的距离和方向);// Tell WebGL how to pull out the positions from the position// buffer into the vertexPosition attribute.setPositionAttribute(gl, buffers, programInfo);setColorAttribute(gl, buffers, programInfo);// 绘制调用将使用该着色器程序中定义的顶点着色器和片元着色器来处理顶点和片元数据gl.useProgram(programInfo.program);// 设置shader中 uniforms值gl.uniformMatrix4fv(programInfo.uniformLocations.projectionMatrix,false,projectionMatrix);gl.uniformMatrix4fv(programInfo.uniformLocations.modelViewMatrix,false,modelViewMatrix);{const offset = 0;// 绘制的顶点数量,即条带中顶点的个数const vertexCount = 4;gl.drawArrays(gl.TRIANGLE_STRIP, offset, vertexCount);}
}// positionBuffer中读取值并赋值给vertexPosition属性.
function setPositionAttribute(gl, buffers, programInfo) {const numComponents = 2; // pull out 2 values per iterationconst type = gl.FLOAT; // the data in the buffer is 32bit floatsconst normalize = false; // don't normalizeconst stride = 0; // how many bytes to get from one set of values to the next// 0 = use type and numComponents aboveconst offset = 0; // how many bytes inside the buffer to start fromgl.bindBuffer(gl.ARRAY_BUFFER, buffers.position);gl.vertexAttribPointer(programInfo.attribLocations.vertexPosition,numComponents,type,normalize,stride,offset);gl.enableVertexAttribArray(programInfo.attribLocations.vertexPosition);
}// 从colorBuffer中读取颜色属性并传递给vertexColor属性并指定步长
function setColorAttribute(gl, buffers, programInfo) {// 当 numComponents 被设置为 4 时,表示每个顶点的颜色数据由四个分量组成,分别对应 RGBA 中的红、绿、蓝和透明度。这样的设置可以确保在顶点着色器中正确地解析和处理颜色数据,以便在渲染过程中正确显示顶点的颜色const numComponents = 4;const type = gl.FLOAT;const normalize = false;const stride = 0;const offset = 0;gl.bindBuffer(gl.ARRAY_BUFFER, buffers.color);// 指定如何从缓冲区中读取数据并将其传递给颜色属性gl.vertexAttribPointer(programInfo.attribLocations.vertexColor,numComponents,type,normalize,stride,offset);gl.enableVertexAttribArray(programInfo.attribLocations.vertexColor);
}export { drawScene };

gl.uniformMatrix4fv 函数

将矩阵数据传递给顶点着色器中的 uniform 变量。这个函数用于传递 4x4 的矩阵数据给着色器程序。

下面是这两个函数调用的详细解释:

  1. gl.uniformMatrix4fv(programInfo.uniformLocations.projectionMatrix, false, projectionMatrix);

    • programInfo.uniformLocations.projectionMatrix 是一个 uniform 变量的位置,它指定了顶点着色器中投影矩阵的 uniform 变量的位置。
    • false 表示是否需要转置矩阵。在 WebGL 中,通常使用列主序(column-major)的矩阵表示,因此这里设置为 false
    • projectionMatrix 是一个 4x4 投影矩阵,它包含了将顶点从世界坐标系变换到裁剪空间的变换信息。通过这个函数调用,将投影矩阵数据传递给顶点着色器中的 projectionMatrix uniform 变量。
  2. gl.uniformMatrix4fv(programInfo.uniformLocations.modelViewMatrix, false, modelViewMatrix);

    • programInfo.uniformLocations.modelViewMatrix 是另一个 uniform 变量的位置,它指定了顶点着色器中模型视图矩阵的 uniform 变量的位置。
    • false 同样表示不需要转置矩阵。
    • modelViewMatrix 是一个 4x4 模型视图矩阵,它包含了将顶点从模型空间变换到观察者空间的变换信息。通过这个函数调用,将模型视图矩阵数据传递给顶点着色器中的 modelViewMatrix uniform 变量。

这样,通过 gl.uniformMatrix4fv 函数,可以将投影矩阵和模型视图矩阵等矩阵数据传递给顶点着色器中的相应 uniform 变量,以便在渲染过程中正确地对顶点进行变换和投影操作。
在 WebGL 中,顶点数据是通过顶点缓冲区对象传递给顶点着色器的。当设置顶点属性时,需要指定顶点属性变量从缓冲区中获取数据的方式。这包括数据的组件数量、数据类型、是否归一化、步长(stride)和偏移量(offset)等信息。

gl.vertexAttribPointer 函数

用于指定顶点属性变量如何从缓冲区中读取数据。下面是一些参数的含义:

  • index:指定要修改的顶点属性的索引。
  • size:指定每个顶点属性的分量数量,比如 2 表示二维向量,3 表示三维向量,4 表示四维向量。
  • type:指定数据的类型,比如 gl.FLOAT 表示 32 位浮点数。
  • normalized:指定是否应该将非浮点数型的数据归一化到特定范围。
  • stride:指定相邻两个顶点属性开始之间的偏移量,以字节为单位。
  • offset:指定顶点属性在缓冲区中的起始偏移量,以字节为单位。

通过这些参数的设置,顶点着色器就能够正确地从缓冲区中读取顶点数据,并将其应用于渲染过程中。在绘制过程中,WebGL 会按照顶点的顺序从缓冲区中读取数据,并将其传递给顶点着色器,确保每个顶点都对应着正确的顶点数据。

gl.drawArrays函数

用于根据顶点数组绘制图形。下面是这个函数调用的详细解释:

  • gl.drawArrays(mode, first, count)
    • mode 参数指定了绘制的图元类型,比如 gl.TRIANGLES 表示绘制三角形,gl.POINTS 表示绘制点,gl.LINES 表示绘制线段等。
    • offset 参数指定了从顶点数组中的哪个位置开始绘制,即起始索引。
    • vertexCount 参数指定了要绘制的顶点数量。

gl.drawArrays(gl.TRIANGLE_STRIP, offset, vertexCount) 的含义是以三角形条带(triangle strip)的方式绘制图形。具体解释如下:

  • gl.TRIANGLE_STRIP 表示使用三角形条带的方式绘制图形。在三角形条带中,每个顶点都会与前两个顶点组成一个三角形,因此顶点的顺序非常重要。
  • offset 参数指定从顶点数组中的哪个位置开始绘制,即起始顶点的索引。
  • vertexCount 参数指定了要绘制的顶点数量,即条带中顶点的个数。

通过这个函数调用,WebGL 将根据指定的顶点数组数据以三角形条带的方式绘制图形,根据顶点的顺序依次连接顶点来形成三角形条带。

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

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

相关文章

异常-Exception

文章目录 异常-Exception常见的运行时异常NullPointerException&#xff08;空指针异常&#xff09;ArithmeticException&#xff08;数学运算异常&#xff09;ArrayIndexOutOfBoundsException&#xff08;数组下标越界异常&#xff09;ClassCastException&#xff08;类型转换…

Basis运维日常检查清单- Checklist

检查SYSTEM 是否正常GUI登入登入到系统检查所有应用服务器是否活动正常SM51检查所有SAP Instance服务器运行是否正常.检查工作进程进行SM50检查是否有运行时间很长Local ProcessSM66检查是否有运行时间很长Global Process检查陈旧锁定条目SM12在User ID栏输入*. 检查前期的锁列…

网络编程聊天室

客户端 #include <myhead.h> //创建结构体存储用户信息 struct User {char tape;char username[32];char msg[1024]; };int main(int argc, const char *argv[]) {//创建套接字与服务器进行通信int sfdsocket(AF_INET,SOCK_STREAM,0);if(sfd-1){perror("socket err…

鸿蒙实战开发Camera组件:【相机】

相机组件支持相机业务的开发&#xff0c;开发者可以通过已开放的接口实现相机硬件的访问、操作和新功能开发&#xff0c;最常见的操作如&#xff1a;预览、拍照和录像等。 基本概念 拍照 此功能用于拍摄采集照片。 预览 此功能用于在开启相机后&#xff0c;在缓冲区内重复采集…

django默认后台管理显示内容深化设置

1、设置models字段展示为只读模式 如某个字段在展示时不允许修改&#xff0c;可在admin.py的注册类下重写函数get_readonly_fields&#xff0c;例&#xff1a; def get_readonly_fields(self, request, objNone): return (dwdm,dwmc,"zjs","yyj"…

ARC-Challenge数据集分享

来源: AINLPer公众号&#xff08;每日干货分享&#xff01;&#xff01;&#xff09; 编辑: ShuYini 校稿: ShuYini 时间: 2024-2-28 该数据集由Allen Institute for Artificial Intelligence&#xff08;AI2&#xff09;发布&#xff0c;旨在推动高级问答的研究。该数据集包含…

#微信小程序(按键控制)

1.IDE&#xff1a;微信开发者工具 2.实验&#xff1a;微信小程序设计两个按钮&#xff0c;对onenet平台数据流&#xff08;旧版&#xff09;来进行http post上传&#xff0c;下位机再http get得到控制信息 3.记录 &#xff08;1&#xff09;bind-tap&#xff08;绑定函数&…

3D数字孪生运行不起来?该检查你的电脑配置了

运行3D数字孪生项目通常需要一定的计算资源和图形处理能力。以下是一些常见的电脑配置要求&#xff0c;可以作为参考&#xff1a;1处理器&#xff08;CPU&#xff09;&#xff1a;推荐使用多核心处理器&#xff0c;如Intel Core i7或更高级别的处理器。较高的时钟频率和较大的缓…

Linux shell 网络掩码地址转CIDR

例子&#xff1a; ./1.sh 255.255.255.0 ./1.sh 255.255.255.128 ./1.sh 255.255.0.0 源实现&#xff1a; #!/bin/bashnetmask_to_cidr() {local IFSlocal -a octetslocal i0local cidr0IFS. read -r -a octets <<< "$1"for octet in "${octets[]}…

Sora关于视频分镜的提示词技巧

视频分镜是视频制作中至关重要的一环&#xff0c;它决定了视频内容的结构、节奏和视觉效果。在Sora文生视频模型中&#xff0c;通过巧妙地运用提示词&#xff0c;你可以更加高效地进行视频分镜设计&#xff0c;提升视频的质量和观众体验。以下是10个关于视频分镜的提示词技巧&a…

kafka报文模拟工具的使用

日常项目中经常会碰到消费kafka某个topic的数据&#xff0c;如果知道报文格式&#xff0c;即可使用工具去模拟发送报文&#xff0c;以此测试代码中是否能正常消费到这个数据。 工具资源已上传&#xff0c;可直接访问连接下载&#xff1a;https://download.csdn.net/download/w…

CSS补充(下),弹性布局(上)

高级选择器 1.兄弟选择器 2.同时满足 div.bg{background-color: red;}p.bg{background-color: green;}spam.bg{background-color: blue;}注&#xff1a;选择器中间没有空格&#xff0c;有明确标识的选择器写在后面 3.各种伪类的应用 3.1作为第几个子元素 选择器:nth-child…

React-父传子

1.概念 说明&#xff1a;父组件传递数据子组件标签身上绑定属性&#xff1b;子组件接受数据props的参数。props是一个对象&#xff0c;包含父组件传递的所有数据。例如数字、字符串、布尔值、数组、对象、函数、JSX。不允许直接修改父组件传递的数据。 2.例子 // 父传子 // …

uniapp踩坑之项目:uni.previewImage简易版预览单图片

主要使用uni.previewImage //html <view class"box-card" v-for"(item,index) in DataList" :key"index"><view>图片&#xff1a;</view><image :src"item.Path" tap.stop"clickImg(item.Path)">&l…

有点NB的免费wordpress主题模板

一个不错的黄色模板&#xff0c;用WP免费主题模板搭建家政服务公司网站。 https://www.wpniu.com/themes/15.html

【性能】JDK和Jmeter的安装与配置

一、JDK环境配置 1. 下载JDK 官网下载地址&#xff1a;http://www.oracle.com/technetwork/java/javase/downloads/java-archive-downloads-javase7-521261.html 选择对应系统的安装包&#xff0c;下载后安装&#xff0c;安装中记录JDK安装的地址&#xff0c;之后一直点击下一…

继深圳后,重庆与鸿蒙展开原生应用开发合作

截至2023年底&#xff0c;开源鸿蒙开源社区已有250多家生态伙伴加入&#xff0c;开源鸿蒙项目捐赠人达35家&#xff0c;通过开源鸿蒙兼容性测评的伙伴达173个&#xff0c;累计落地230余款商用设备&#xff0c;涵盖金融、教育、智能家居、交通、数字政府、工业、医疗等各领域。 …

【Python】科研代码学习:三 PreTrainedModel, PretrainedConfig, PreTrainedTokenizer

【Python】科研代码学习&#xff1a;三 PreTrainedModel, PretrainedConfig, PreTrainedTokenizer 前言Models : PreTrainedModelPreTrainedModel 中重要的方法 tensorflow & pytorch 简单对比Configuration : PretrainedConfigPretrainedConfig 中重要的方法 Tokenizer : …

Java基础面试题(day 01)

&#x1f4d1;前言 本文主要是【Java】——Java基础面试题的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是听风与他&#x1f947; ☁️博客首页&#xff1a;CSDN主页听风与他 &#x1f304;每日一句&am…

C++ 篇 数组

数组是含有多个数据项的数据结构&#xff0c;并且这些数据项都具有相同的数据类型。这些数据项称为数组的元素&#xff0c;我们可以根据元素在数组中的位置来选取元素。 最简单的数组就是一维数组。数组元素在内存中是依次排列的&#xff0c;如下图所示&#xff1a; 声明一个…