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

WebGL2初识

WebGL渲染步骤WebGL渲染过程具体代码片段
CPU端1.准备顶点坐标(位置、颜色、法线)塞进GPU缓冲区
2.把“顶点/片元着色器源码”变成可执行文件
GPU启动GPU按固定管线顺序执行后续所有阶段gl.drawArrays(gl.TRIANGLES,0,3);
顶点着色器执行顶点着色器文件,对每个顶点跑一遍:坐标变换-裁剪空间gl_Position=vec4(a_pos,0,1);代码只存在js内存里面
图元装配顶点连起来后的“几何形状”(点线面)硬件自动,无代码
光栅化在屏幕格子内部插值,生成一堆候选“片元”,还未写进屏幕硬件自动,无代码
片元着色器执行片元着色器文件,给每个片元上色、贴图、光照→输出颜色+深度fragColor=vec4(v_color,1);代码只存在js内存里面
测试与混合深度测试/模板测试/混合→幸存下来的片元正式成为像素默认开启深度测试
帧缓冲→显示控制器写进帧缓存的真实屏幕点浏览器+OS自动完成,无需代码

图形学是“先做再看”效率最高的学科,所以直接看效果和代码:


<script type="module">
/*** @fileoverview WebGL2 配置开关 - JSDoc 全参详解版* 每一行 gl.* 都带「参数含义 + 中文一句话 + 常见坑」* 执行顺序:① → ⑪ 保持原标记*//* ================= ① 获取 WebGL2 上下文 ================= */
/** @type {WebGL2RenderingContext} */
const gl = c.getContext('webgl2');        // 拿到 GPU 遥控器
if (!gl) throw '浏览器不支持 WebGL2';      // 保险:旧浏览器直接抛错/* ================= ② 玩家配置 ================= */
const CFG = {rotate: true,      // 60 fps 旋转move: true,        // 左右摆动rainbow: false,    // 每帧换色texture: false,    // 棋盘格纹理wireframe: true,   // 线框模式cullFace: true,    // 背面剔除depthTest: true,   // 深度缓冲clearColor: [0, 0, 0, 1] // RGBA 0-1,黑色背景
};/* ================= ③ 实时绑定面板 ================= */
['rotate','move','rainbow','texture','wireframe','cullFace','depthTest'].forEach(k => document.getElementById(k).addEventListener('change', () => rebuild()));/* ================= ④ 动态生成着色器 ================= */
/*** 根据 CFG 返回 VS/FS 源码字符串* @returns {{vs:string, fs:string}}*/
function buildShader() {const vs = `#version 300 esin vec2 a_pos;in vec3 a_color;in vec2 a_uv;out vec3 v_color;out vec2 v_uv;uniform float u_time;uniform vec2 u_offset;void main(){vec2 p = a_pos;${CFG.rotate ? `float s = sin(u_time), c = cos(u_time); p = vec2(p.x*c - p.y*s, p.x*s + p.y*c);` : ''}${CFG.move ? `p += u_offset;` : ''}gl_Position = vec4(p, 0, 1);v_color = a_color;v_uv = a_uv;}`;const fs = `#version 300 esprecision highp float;in vec3 v_color;in vec2 v_uv;out vec4 fragColor;uniform float u_time;uniform sampler2D u_tex;void main(){${CFG.rainbow ? `fragColor = vec4(0.5 + 0.5*sin(u_time + vec3(0,2,4)), 1);` :CFG.texture ? `fragColor = texture(u_tex, v_uv);` :`fragColor = vec4(v_color, 1);`}}`;return {vs, fs};
}/* ================= ⑤ 生成棋盘格纹理 ================= */
/*** 创建 64×64 棋盘格纹理* @returns {WebGLTexture} 纹理句柄*/
function makeCheckerTexture() {const size = 64;const data = new Uint8Array(size * size * 4);for (let i = 0; i < size; ++i)for (let j = 0; j < size; ++j) {const c = ((i >> 3) + (j >> 3)) & 1 ? 255 : 0; // 8×8 黑白格const idx = (i * size + j) * 4;data[idx] = data[idx + 1] = data[idx + 2] = c; // RGBdata[idx + 3] = 255; // A}const tex = gl.createTexture(); // 新建纹理对象gl.bindTexture(gl.TEXTURE_2D, tex); // 绑定到纹理单元 0/*** 上传像素数据到 GPU* @param {GLenum} target - 固定写 gl.TEXTURE_2D* @param {GLint} level - mipmap 级别,0=基础图* @param {GLint} internalFormat - GPU 内部格式,如 gl.RGBA* @param {GLsizei} width - 图像宽(像素)* @param {GLsizei} height - 图像高(像素)* @param {GLint} border - 必须为 0(WebGL 限制)* @param {GLenum} format - 像素格式,如 gl.RGBA* @param {GLenum} type - 像素类型,如 gl.UNSIGNED_BYTE* @param {ArrayBufferView} pixels - 像素数据,null=空图*/gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);gl.generateMipmap(gl.TEXTURE_2D); // 自动生成各级 mipmap// 纹理环绕模式:REPEAT = 重复平铺gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);// 纹理过滤:LINEAR_MIPMAP_LINEAR = 三线性过滤,最平滑gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);return tex;
}/* ================= ⑥ 顶点数据(含 UV) ================= */
/*** 顶点布局:x, y, r, g, b, u, v* UV 范围 0→1:左下 (0,0)  右上 (1,1)* @type {Float32Array}*/
const vertices = new Float32Array([0.0,  0.5,  1,0,0,  0.5, 1, // 上中-0.5, -0.5,  0,1,0,  0,   0, // 左下0.5, -0.5,  0,0,1,  1,   0  // 右下
]);
const buf = gl.createBuffer(); // 创建 GPU 缓冲对象
gl.bindBuffer(gl.ARRAY_BUFFER, buf); // 绑定到“数组缓冲”目标
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW); // 拷进显存/* ================= ⑦ 重建管线(编译+链接+状态) ================= */
let program, tex, u_time, u_offset;
function rebuild() {const {vs, fs} = buildShader();const vsShader = gl.createShader(gl.VERTEX_SHADER);gl.shaderSource(vsShader, vs);gl.compileShader(vsShader);const fsShader = gl.createShader(gl.FRAGMENT_SHADER);gl.shaderSource(fsShader, fs);gl.compileShader(fsShader);program = gl.createProgram();gl.attachShader(program, vsShader);gl.attachShader(program, fsShader);gl.linkProgram(program);gl.useProgram(program); // 设为“当前要用的程序”// 获取 uniform 槽位u_time = gl.getUniformLocation(program, 'u_time');u_offset = gl.getUniformLocation(program, 'u_offset');// 属性绑定const locPos = gl.getAttribLocation(program, 'a_pos');const locColor = gl.getAttribLocation(program, 'a_color');const locUV = gl.getAttribLocation(program, 'a_uv');gl.enableVertexAttribArray(locPos);/*** 告诉 GPU 如何拆“快递包裹”里的顶点数据* @param {GLuint} index - 属性 location(槽位号)* @param {GLint} size - 每个顶点读几个分量(1-4)* @param {GLenum} type - 数据类型,gl.FLOAT 最常用* @param {GLboolean} normalized - 是否把整数归一化到 [-1,1] 或 [0,1]* @param {GLsizei} stride - **字节步长**,0=紧密排列* @param {GLintptr} offset - **字节偏移**,从缓冲区哪里开始读*/gl.vertexAttribPointer(locPos, 2, gl.FLOAT, false, 7*4, 0);gl.enableVertexAttribArray(locColor);gl.vertexAttribPointer(locColor, 3, gl.FLOAT, false, 7*4, 2*4);gl.enableVertexAttribArray(locUV);gl.vertexAttribPointer(locUV, 2, gl.FLOAT, false, 7*4, 5*4);// 纹理开关if (CFG.texture && !tex) tex = makeCheckerTexture();/*** 激活纹理单元(0-31 可用)* @param {GLenum} unit - gl.TEXTURE0 ~ gl.TEXTURE31*/gl.activeTexture(gl.TEXTURE0); // 激活纹理单元 0gl.bindTexture(gl.TEXTURE_2D, CFG.texture ? tex : null);/*** 把采样器绑定到指定纹理单元* @param {WebGLUniformLocation} location - uniform 槽位* @param {GLint} unit - 纹理单元号(0 对应 TEXTURE0)*/gl.uniform1i(gl.getUniformLocation(program, 'u_tex'), 0); // 采样器绑定到 0// 状态实时切换CFG.depthTest ? gl.enable(gl.DEPTH_TEST) : gl.disable(gl.DEPTH_TEST);CFG.cullFace  ? gl.enable(gl.CULL_FACE)  : gl.disable(gl.CULL_FACE);gl.cullFace(gl.BACK);gl.depthFunc(gl.LEQUAL);
}
rebuild(); // ⑧ 首次构建/* ================= ⑨ 动画循环 ================= */
let then = 0;
function frame(t) {const dt = (t - then) * 0.001; then = t;/*** 设置清屏颜色(RGBA 0-1)* @param {number} r - 红* @param {number} g - 绿* @param {number} b - 蓝* @param {number} a - 透明*/gl.clearColor(...CFG.clearColor);/*** 真正执行“清屏”操作* @param {GLbitfield} mask - 位掩码:gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT*/gl.clear(gl.COLOR_BUFFER_BIT | (CFG.depthTest ? gl.DEPTH_BUFFER_BIT : 0));// 更新动画 uniformgl.uniform1f(u_time, t * 0.001);/*** 设置 vec2 类型 uniform(摆动偏移)* @param {WebGLUniformLocation} location - uniform 槽位* @param {number} x - x 分量* @param {number} y - y 分量*/if (CFG.move) gl.uniform2f(u_offset, Math.sin(t * 0.001) * 0.3, 0);// 实时切换图元模式const mode = CFG.wireframe ? gl.LINE_LOOP : gl.TRIANGLES;/*** 核心 DrawCall:GPU 开始跑整条管线* @param {GLenum} mode - 图元类型*        gl.POINTS         点*        gl.LINES          每 2 顶点一线段*        gl.LINE_STRIP     连续折线*        gl.LINE_LOOP      闭合折线(本例线框用)*        gl.TRIANGLES      每 3 顶点一三角形(默认填充)*        gl.TRIANGLE_STRIP 共享边的三角带*        gl.TRIANGLE_FAN   共享第一个顶点的扇形* @param {GLint} first - 从第几个顶点开始(索引)* @param {GLsizei} count - 共用多少个顶点*/gl.drawArrays(mode, 0, 3); // 画 1 个三角形(3 顶点)requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
</script>
</body>
</html>


文章转载自:

http://O2o8BdaW.wLddq.cn
http://TmYSK0x0.wLddq.cn
http://nIxmnzqH.wLddq.cn
http://ucXZbcwY.wLddq.cn
http://4tRtZiwd.wLddq.cn
http://JPmLM8TL.wLddq.cn
http://hjwtb8zM.wLddq.cn
http://aM8ubfj6.wLddq.cn
http://HRX5SnEK.wLddq.cn
http://ghY3jYCC.wLddq.cn
http://gEDad6qx.wLddq.cn
http://m3cdhezt.wLddq.cn
http://PvvbFDBk.wLddq.cn
http://aBtrXrLB.wLddq.cn
http://OuvNf9Mi.wLddq.cn
http://TMBSA2Mi.wLddq.cn
http://GWhSPyNb.wLddq.cn
http://n7yyNMYV.wLddq.cn
http://TAzXgX8f.wLddq.cn
http://bBI5FuY4.wLddq.cn
http://d2LDZ5oP.wLddq.cn
http://tTTvRv1j.wLddq.cn
http://5EVJfa4g.wLddq.cn
http://11S1H2Gs.wLddq.cn
http://8RqoNKWS.wLddq.cn
http://sBdvpdZC.wLddq.cn
http://R6yoFhLq.wLddq.cn
http://9kwez0Ve.wLddq.cn
http://wVH2Q9vL.wLddq.cn
http://sK3ZngNb.wLddq.cn
http://www.dtcms.com/a/372171.html

相关文章:

  • 浏览器兼容性问题全解:CSS 前缀、Grid/Flex 布局兼容方案与跨浏览器调试技巧
  • TI例程demo-ADC电压、电流采样的学习研究及硬件验证调试
  • AOP常见面试题
  • Suricata 8阿里云编译安装保姆教程
  • 【112】基于51单片机大棚鸡舍远程数据检测系统【Keil程序+报告+原理图】
  • 深入理解OpenHarmony中的BUILD.gn:从语法到模块化构建
  • 阴阳学:从入门到精通
  • vulhub通关笔记1—docker unauthorized-rce
  • ZYNQ PS XADC读取芯片内部温度值,电压值。
  • 每日一题(3)
  • 泛型编程(简单介绍,通俗易懂)
  • 扩散模型揭秘:生成式AI的核心与应用
  • 【Flink】Flink Runtime 架构设计
  • MySQL数据库同步
  • 使用 Spring Security 实现 OAuth2:一步一步的操作指南
  • Axure: 分组柱状图1
  • CEEMDAN-PSO-CNN-GRU 锂电池健康状态预测matlab
  • Spring Cloud Gateway 作为一个独立的服务进行部署吗
  • webrtc弱网-LossBasedBweV2类源码分析与算法原理
  • leetcode hot100 二叉搜索树
  • 杂学项目1、S32K144与上位机通信
  • GitHub自动化利器:Probot框架实战指南
  • 一款没有任何限制的免费远程手机控制手机的软件简介
  • 企云网多应用授权系统源码 正版查询系统源码
  • Windows netstat 命令使用说明
  • 软件工程:DO-178中的适航要求核心要素
  • Caffeine Count-Min Sketch TinyLFU实现:FrequencySketch
  • 【系统分析师】第7章-基础知识:软件工程(核心总结)
  • 【拍摄学习记录】00-总结记录
  • 探索 CSS 过渡:打造流畅网页交互体验