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

搭建WebGL开发环境

前言

本篇文章介绍如何搭建WebGL开发环境

WebGL

WebGL的技术规范继承自免费和开源的OpenGL ES标准,从某种意义上说,WebGL就是Web版的OpenGL ES,而OpenGL ES是从OpenGL中派生出来的。他们的应用环境有区别,一般来说:

  • OpenGL:一般应用于桌面级别的三维图形渲染,同类的还有微软的DirectX和苹果公司的Metal技术
  • OpenGL ES:OpenGL的子集,删除了很多用处不大的接口和特性,但仍然能进行三维渲染,应用于智能手机、嵌入式计算机、家用游戏机等
  • WebGL:从OpenGL ES派生出来的。需要浏览器内核的支持。WebGL广泛应用于所有的网页渲染。因为需要运行在浏览器上,所以浏览器在背后做了很多工作,包括跨平台的特性。

版本

既然OpenGL、OpenGL ES和WebGL存在继承关系,那必然涉及到版本信息
先看一下OpenGL的版本信息:

  • OpenGL 1.5:这个版本的OpenGL不支持着色器编程,采用固定渲染管线
  • OpenGL 2.0:这个版本加入GLSL着色器编程语言
  • OpenGL 3.3:2010年发布
  • OpenGL 4.3:2013年发布

看一下OpenGL ES的版本信息:

  • OpenGL ES 1.1:OpenGL 1.5的子集,应用范围有限
  • OpenGL ES 2.0:OpenGL 2.0的子集,应用最广泛的版本
  • OpenGL ES 3.0:OpenGL 3.3的子集,增加了很多新功能,包括:
    • 遮挡查询
    • 变缓反馈(Transform Feedback)
    • 实例渲染(Instanced Rendering)
    • 四个或更多渲染目标支持
    • 着色语言全面支持整数和32位浮点操作
    • 纹理功能大幅增强,支持浮点纹理、3D纹理、深度纹理、顶点纹理、NPOT纹理、R/RG单双通道纹理、不可变纹理、2D阵列纹理、无二次幂限制纹理、阴影对比、调配(swizzle)、LOD与mip level clamps、无缝立方体贴图、采样对象、纹理MSAA抗锯齿渲染器
    • 一系列广泛的精确尺寸纹理和渲染缓冲格式

看一下WebGL的版本信息:

  • WebGL 1.0:基于OpenGL ES 2.0,并提供了3D图形的API,它使用HTML5Canvas并允许利用文档对象模型接口。
  • WebGL 2.0:WebGL 2.0基于OpenGL ES 3.0,确保了提供许多选择性的WebGL 1.0扩展,并引入新的API。可利用部分Javascript实现自动存储器管理

WebGL程序组成

一个最简单的WebGL程序之需要一个html文件和几个js文件就可以了,下面详细介绍

html部分

html主要是为了放置canvas元素,因为WebGL的渲染都是在canvas进行的。
下面是一个html部分:

<!DOCTYPE html>
<html lang="cn">
<head><meta charset="utf-8"><title>wgl render ins</title>
</head>
<body onload="main()"><canvas id="wglCanvas" width="960" height="540">当前浏览器不支持canvas</canvas><script src="sk_init.js"></script><script src="sk_shader.js"></script><script src="sk_utils.js"></script>
</body>
</html>

这个简单的不能再简单的html就已经够用了。

上面的html我们命名为main.html。从上面的html中,可以发现我们需要一个main函数,这个函数一般来说在js中实现,这也是我们WebGL程序正式开始的入口函数,我们添加一个js文件sk_init.js,并实现该函数,当然我们也需要在html中加入引用js的代码,为了保持代码的简洁,已经在上面的html中加入了该代码。

js部分

下面是sk_init.js的代码:

var gl;
function main()
{var canvas = document.getElementById("wglCanvas");gl = create3DContext(canvas);if(!gl){console.log("获取webgl渲染上下文失败");return;}gl.clearColor(0.0,0.0,0.0,1.0);gl.clear(gl.COLOR_BUFFER_BIT);
}var create3DContext = function(canvas) {var names = ["webgl", "experimental-webgl", "webkit-3d", "moz-webgl"];var context = null;for (var ii = 0; ii < names.length; ++ii) {try {context = canvas.getContext(names[ii]);} catch(e) {}if (context) {break;}}return context;
}

上面这个代码分为几部分:

  • 获取canvas对象
  • 获取webgl上下文
  • 设置canvas画布背景色
  • 使用背景色清空绘图区

虽然代码很简单,但是这几步是所有webgl程序都需要做的事情,当前main.html已经可以运行了。不过只会显示一个黑色背景。下面我们开始加入些东西

shader

想编写一个真正可以使用的webgl程序,首先需要写shader,由于本篇文章我们着重介绍WebGL框架,所以我们只是简单说明一下,关于shader语法,会有专门文章介绍。

  • WebGL程序的shader一般有两个,顶点着色器片元着色器
  • 着色器是以字符串的形式嵌入到js文件中的

下面是两个简单的着色器代码,我们创建一个sk_shader.js存放这部分代码:
顶点着色器:

var VERTEX_SHADER=`
attribute vec4 a_Position;
uniform float u_PointSize;
void main() {gl_Position = a_Position;gl_PointSize = u_PointSize;
}`;

片元着色器:

var FRAG_SHADER=`
void main() {gl_FragColor = vec4(1.0,0.0,0.0,1.0);
}`;

初始化着色器

创建好了着色器以后,下一步就要初始化着色器了

加载着色器代码

我们新建一个sk_util.js文件,里面封装一些公共的方法,首先我们要添加的方法就是加载着色器代码的方法:

// gl: webgl上下文
// type: 着色器类型
// source: 着色器代码
function loadShader(gl, type, source) {var shader = gl.createShader(type);if (shader == null) {console.log('unable to create shader');return null;}gl.shaderSource(shader, source);gl.compileShader(shader);var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);if (!compiled) {var error = gl.getShaderInfoLog(shader);console.log('Failed to compile shader: ' + error);gl.deleteShader(shader);return null;}return shader;
}

加载一个着色器需要以下步骤:

  • 创建着色器对象:使用gl.createShader接口,参数为着色器类型,着色器类型一般有两类:
    • gl.VERTEX_SHADER:顶点着色器
    • gl.FRAGMENT_SHADER:片元着色器
  • 加载着色器代码:使用gl.shaderSource接口,第一个参数为第一步创建的着色器对象,第二个参数为着色器的字符串表示
  • 编译着色器代码:使用gl.compileShader接口,参数为第一步创建的着色器对象
  • 获取着色器编译状态,如果编译失败,获取错误信息

创建着色器程序

下面是创建着色器程序的代码:

function createProgram(gl, vshader, fshader) {var vertexShader = loadShader(gl, gl.VERTEX_SHADER, vshader);var fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fshader);if (!vertexShader || !fragmentShader) {return null;}var program = gl.createProgram();if (!program) {return null;}gl.attachShader(program, vertexShader);gl.attachShader(program, fragmentShader);gl.linkProgram(program);var linked = gl.getProgramParameter(program, gl.LINK_STATUS);if (!linked) {var error = gl.getProgramInfoLog(program);console.log('Failed to link program: ' + error);gl.deleteProgram(program);gl.deleteShader(fragmentShader);gl.deleteShader(vertexShader);return null;}return program;
}

创建着色器程序的步骤如下:

  • 创建着色器程序:使用gl.createProgram接口,返回着色器程序对象
  • 关联着色器对象:使用gl.attachShader接口,第一个参数是第一步创建的着色器程序对象,第二个参数是关联的着色器对象
  • 链接着色器程序:使用gl.linkProgram接口链接程序,参数是第一步创建的着色器程序对象
  • 获取着色器程序链接状态,如果链接失败,获取错误信息

使用着色器对象

  • 使用gl.useProgram接口使用我们上一步创建的着色器程序对象。
  • 将着色器程序对象赋给gl.program,方便我们后面传递数据的时候使用

代码如下:

function initShaders(gl, vshader, fshader) {var program = createProgram(gl, vshader, fshader);if (!program) {console.log('Failed to create program');return false;}gl.useProgram(program);gl.program = program;return true;
}

经过这三步以后,着色器程序已经初始化完成了,接下来就是向着色器传递数据

传递数据

所谓的传递数据就是将内存的数据传递给显存
一般情况下shader中使用的数据有三种:

  • 使用attribute标记的数据,这个也叫做顶点数据,就是每个顶点都会有自己的数值
  • 使用uniform标记的数据,这个也叫做统一数据,就是所有顶点共用的数据
  • 使用varying标记的数据,这个是在着色器之间传递的数据

获取shader的数据标记

  • 使用gl.getAttribLocation接口获取attribute数据的标记,第一个参数是着色器程序对象,第二个参数是数据在shader中的名称的字符串表示
  • 使用gl.getUniformLocation接口获取uniform数据的标记,第一个参数是着色器程序对象,第二个参数是数据在shader中的名称的字符串表示

下面我们获取前面着色器程序的a_Position和u_PointSize的标记:

var u_PointSize = gl.getUniformLocation(gl.program, "u_PointSize");
if (u_PointSize < 0) {console.log('Failed to get the storage location of u_PointSize');return -1;
}
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
if (a_Position < 0) {console.log('Failed to get the storage location of a_Position');return -1;
}

从内存传递attribute数据到显存

  • 创建缓冲区,使用gl.createBuffer()创建缓冲区
  • 绑定缓冲区,使用gl.bindBuffer接口绑定缓冲区,第一个参数是缓冲区类型,这里我们使用gl.ARRAY_BUFFER,第二个参数是上一步创建的缓冲区
  • 传递数据,使用gl.bufferData接口传递数据,第一参数是缓冲区类型,这里我们使用gl.ARRAY_BUFFER,第二个参数是内存数据指针,第三个参数是数据的使用方式,这里我们使用gl.STATIC_DRAW
    代码如下:
var verticesTexCoords = new Float32Array([-0.5, 0.5, 0.0, 1.0,-0.5, -0.5, 0.0, 1.0,0.5, 0.5, 0.0, 1.0,0.5, -0.5, 0.0, 1.0,    ]);
var FSIZE = verticesTexCoords.BYTES_PER_ELEMENT;
var vertexTexCoordBuffer = gl.createBuffer();
if (!vertexTexCoordBuffer) {console.log('Failed to create the buffer object');return -1;
}
gl.bindBuffer(gl.ARRAY_BUFFER, vertexTexCoordBuffer);
gl.bufferData(gl.ARRAY_BUFFER, verticesTexCoords, gl.STATIC_DRAW);

传递uniform数据到显存

使用gl.uniform1f接口传递单个float数值到显存,在当前程序中用来传递u_PointSize的值
代码如下:

gl.uniform1f(u_PointSize, 10);

绑定缓冲区与attribute顶点属性

  • 使用gl.vertexAttribPointer接口绑定缓冲区与attribute顶点属性
  • 使用gl.enableVertexAttribArray接口开启顶点属性数组,如果不开启的话,默认会使用静态属性,就是所有顶点数据都使用一个默认的值
    代码如下:
gl.vertexAttribPointer(a_Position, 4, gl.FLOAT, false, FSIZE * 4, 0);
gl.enableVertexAttribArray(a_Position);

绘制

当前程序使用gl.drawArrays来开始绘制操作
gl.drawArrays的第一个参数是绘制的类型,我们当前程序就使用gl.POINTS方式
gl.drawArrays的第二个参数是绘制顶点的偏移,当前为0
gl.drawArrays的第三个参数是绘制顶点的数量,当前为4
代码如下:

gl.clearColor(0.0,0.0,0.0,1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.POINTS, 0, 4);

代码结构调整

  • 我们把创建WebGL上下文和初始化着色器的方法放进sk_utils.js
  • 我们把shader字符串放进sk_shader.js
  • 我们把传递数据的部分放进sk_init.js
  • main.html中需要添加对这3个js的引用,我们已经添加好了

完整的代码已经上传gitlab:
https://gitlab.com/lingyanTools/sk_webgl.git
该例子绘制了四个顶点
在这里插入图片描述

相关文章:

搭建WebGL开发环境

前言 本篇文章介绍如何搭建WebGL开发环境 WebGL WebGL的技术规范继承自免费和开源的OpenGL ES标准&#xff0c;从某种意义上说&#xff0c;WebGL就是Web版的OpenGL ES&#xff0c;而OpenGL ES是从OpenGL中派生出来的。他们的应用环境有区别&#xff0c;一般来说&#xff1a;…...

学习嵌入式第十五天之结构体

用变量a给出下面的定义 a) 一个整型数&#xff08;An integer&#xff09; //int a;b) 一个指向整型数的指针&#xff08;A pointer to an integer&#xff09; //int *a;c) 一个指向指针的的指针&#xff0c;它指向的指针是指向一个整型数&#xff08;A pointer to a poin…...

【HDFS】一天一个RPC系列--updateBlockForPipeline

本文目标是: 弄清updateBlockForPipeline这个RPC的作用。弄清updateBlockForPipeline RPC的使用场景,代码里的调用点。一、updateBlockForPipeline的作用 其定义在ClientProtocol接口里,是Client与NameNode之间的接口。 看其代码注释描述: 为一个under construction状态下…...

测试面试题(0101设计测试用例关键)

1. 测试计划 测试范围&#xff0c;本次改动的模块&#xff0c;新增了哪些功能测试策略&#xff0c;包含测试依据&#xff0c;测试准入标准&#xff0c;准出标准&#xff0c;测试重点及方法&#xff08;确认功能的优先级&#xff09;&#xff0c;测试工具的选择测试管理&#x…...

C++ 数论相关题目:高斯消元解异或线性方程组

输入一个包含 n 个方程 n 个未知数的异或线性方程组。 方程组中的系数和常数为 0 或 1 &#xff0c;每个未知数的取值也为 0 或 1 。 求解这个方程组。 异或线性方程组示例如下&#xff1a; M[1][1]x[1] ^ M[1][2]x[2] ^ … ^ M[1][n]x[n] B[1] M[2][1]x[1] ^ M[2][2]x[2]…...

嵌入式学习第十四天

1.结构体&#xff08;2&#xff09;: &#xff08;1&#xff09;结构体类型定义 &#xff08;2&#xff09;结构体变量的定义 &#xff08;3&#xff09;结构体元素的访问 &#xff08;4&#xff09;结构体的存储: 内存对齐: char 按照1字节对齐 …...

氢气泄漏检测仪使用方法:守护安全,从细节开始

随着科技的发展&#xff0c;我们的生活和工作环境中充满了各种潜在的危险。其中&#xff0c;氢气作为一种清洁能源&#xff0c;其使用日益广泛&#xff0c;但同时也带来了泄漏的风险。为了确保我们的安全&#xff0c;了解并正确使用氢气泄漏检测仪至关重要。下面将详细介绍氢气…...

【前端web入门第二天】01 html语法实现列表与表格_合并单元格

html语法实现列表与表格 文章目录: 1.列表 1.1 无序列表1.2 有序列表1.3 定义列表 2.表格 2.1 表格基本结构2.2 表格结构标签2.3 合并单元格 写在最前,第二天学习目标: 列表 表格 表单 元素为嵌套关系 1.列表 作用:布局内容排列整齐的区域。 列表分类:无序列表、有序列表…...

推荐系统|排序_MMOE

MMOE MMOE是指Multi-gate Mixture-of-Experts 注意看Expert后面加了s&#xff0c;说明了有多个专家。 而在MMOE中专家是指用来对输入特征计算的神经网络&#xff0c;每个神经网络根据输入计算出来的向量都会有所不同。 MMOE的低层 MMOE的上一层 通过MMOE的低层算出的向量和权…...

Redis拒绝连接的原因与解决方式

Redis拒绝连接的原因与解决方式 在某些情况下&#xff0c;当尝试从外部计算机连接到运行在保护模式下的Redis服务器时&#xff0c;您可能会遇到如下的错误信息&#xff1a; Caused by: org.redisson.client.RedisException: DENIED Redis is running in protected mode becau…...

Neo4j在java中的使用

1.Neo4j访问的两种方式 嵌入式数据库服务器模式(通过REST的访问) 它是由应用程序的性质&#xff08;neo4j是独立服务器 还是和程序在一起),性能&#xff0c;监控和数据安全性来决定架构选择。 An embedded database&#xff08;嵌入式数据库&#xff09; 嵌入式Neo4j数据库…...

故障诊断 | 一文解决,CNN卷积神经网络故障诊断(Matlab)

文章目录 效果一览文章概述专栏介绍源码设计参考资料效果一览 文章概述 故障诊断 | 一文解决,CNN卷积神经网络故障诊断(Matlab) 专栏介绍 订阅【故障诊断】专栏,不定期更新机器学习和深度学习在故障诊断中的应用;订阅...

uniapp-app使用富文本编辑器editor

使用的是uniapp内置组件的表单组件editor&#xff1a;editor 组件 | uni-app官网 (dcloud.net.cn) editor 组件对应的 editorContext 实例&#xff1a;editorContext | uni-app官网 (dcloud.net.cn) 文档上写的也不是特别详细&#xff0c;还以为得npm&#xff0c;但没npm也能用…...

20240131 大模型快讯

//社区生态// 国内首个音视频多媒体大模型万兴“天幕”正式发布。万兴科技发布国内首个音视频多媒体大模型万兴“天幕”&#xff0c;支持多种语言&#xff0c;实现音视频创作闭环。 //行业落地// 全球首款搭载AI大模型的MPV智能座舱发布。江淮全新MPV瑞风RF8上市发布&#xf…...

MySQL原理(二)存储引擎(2)MyISAM

一、MyISAM介绍 1、介绍&#xff1a; MyISAM引擎是MySQL5.5版本之前的数据库所默认的数据表引擎。每一个采用MyISAM引擎的数据表在实际存储中都是由三个文件组成&#xff0c;分别是frm文件保存表的结构&#xff0c;MYD文件保存表的数据、MYI文件保存表的索引&#xff0c;文件…...

P1088 [NOIP2004 普及组] 火星人题解

题目 人类终于登上了火星的土地并且见到了神秘的火星人。人类和火星人都无法理解对方的语言&#xff0c;但是我们的科学家发明了一种用数字交流的方法。这种交流方法是这样的&#xff0c;首先&#xff0c;火星人把一个非常大的数字告诉人类科学家&#xff0c;科学家破解这个数…...

Python面向对象编程:探索代码的结构之美

文章目录 一、引言二、为什么学习面向对象编程2.1 提高代码的可维护性&#xff1a;通过封装、继承和多态实现模块化设计2.2 提升代码的复用性&#xff1a;通过类和对象的创建实现代码的重用 三、类和对象的基本概念3.1 类和对象的定义和关系&#xff1a;类是对象的模板&#xf…...

Java基于SpringBoot+Vue的电影影城管理系统,附源码,文档

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…...

【学网攻】 第(14)节 -- 动态路由(EIGRP)

系列文章目录 目录 系列文章目录 文章目录 前言 一、动态路由EIGRP是什么&#xff1f; 二、实验 1.引入 实验步骤 实验拓扑图 实验配置 看到D开头是便是我们的EIGRP动态路由 总结 文章目录 【学网攻】 第(1)节 -- 认识网络【学网攻】 第(2)节 -- 交换机认识及使用【学…...

【Linux】多线程(线程概念+线程控制)

&#x1f307;个人主页&#xff1a;平凡的小苏 &#x1f4da;学习格言&#xff1a;命运给你一个低的起点&#xff0c;是想看你精彩的翻盘&#xff0c;而不是让你自甘堕落&#xff0c;脚下的路虽然难走&#xff0c;但我还能走&#xff0c;比起向阳而生&#xff0c;我更想尝试逆风…...

【昕宝爸爸小模块】深入浅出详解之常见的语法糖

深入浅出详解之常见的语法糖 一、&#x1f7e2;关于语法糖的典型解析二、&#x1f7e2;如何解语法糖&#xff1f;2.1&#x1f7e2;糖块一、switch 支持 String 与枚举2.2&#x1f4d9;糖块二、泛型2.3&#x1f4dd;糖块三、自动装箱与拆箱2.4&#x1f341;糖块四、方法变长参数…...

低代码

腾讯云微搭低代码 WeDa _低代码开发平台_可视化开发平台-腾讯云 首页 - 钉钉宜搭 快速上手多维表格 爱速搭 - 企业应用智能设计平台 | 低代码平台 - 百度智能云 Astro轻应用 Astro Zero_低代码开发平台_软件开发工具_应用开发工具_华为云 低代码是一种软件开发方法&#x…...

2024/1/30 备战蓝桥杯 3-1 栈

目录 小鱼的数字游戏 P1427 小鱼的数字游戏 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 表达式括号匹配 P1739 表达式括号匹配 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 【模板】栈 B3614 【模板】栈 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 小鱼的数字…...

qt setStyleSheet 设置多个属性{}之间用空格间隔

setStyleSheet 设置多个属性时&#xff0c;大属性之间不能用分号&#xff0c;用 空格进行间隔 pbtn1->setStyleSheet("QPushButton {background-color: rgb(4,138,224);font: bold 12pt;color: rgb(255,255,255);} QPushButton:hover,QPushButton:pushed {background-…...

【Node.js基础】Node.js的介绍与安装

文章目录 前言一、什么是Node.js&#xff1f;二、安装Node.js2.1 Windows系统2.2 macOS系统2.3 Linux系统 三、运行js代码总结 前言 随着互联网技术的不断发展&#xff0c;构建高性能、实时应用的需求日益增长。Node.js作为一种服务器端运行时环境&#xff0c;以其事件驱动、非…...

树和二叉树基础

树和二叉树基础 1.1树的概念 树是在数据结构中第一次接触到的非线性结构。 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。把它 叫做树是因为它看起来像一棵倒挂的树&#xff0c;也就是说它是根朝上&am…...

第十四届蓝桥杯大赛软件赛省赛(C/C++ 大学B组)题解

尝试再做一次&#xff0c;我记得还是有点难&#xff0c;我会尽量多写一点解析&#xff0c;尽量让基础比较弱的友友也能看懂&#xff0c;希望能给你带来帮助 目录 1. 日期统计 题目描述 解题思路 具体代码 2. 01 串的熵 题目描述 解题思路 具体代码 3. 冶炼金属 题目…...

【计算机网络】网络的网络

网络的网络 客户 customer 接入ISP提供商 provider 全球承载ISP多个ISP的层级结构 第一层ISP &#xff08;tier-1 ISP &#xff09; 位于顶部 区域ISP &#xff08;reginal ISP&#xff09;Level 3通信 &#xff0c;AT&T&#xff0c;Sprint &#xff0c;NTT存在点&#x…...

SQL Server 函数参考手册

目录 SQL Server 字符串函数 SQL Server 数值函数 SQL Server 日期函数 SQL Server 高级函数 SQL Server 字符串函数 函数描述ASCII返回特定字符的 ASCII 值CHAR根据ASCII码返回字符CHARINDEX返回子字符串在字符串中的位置CONCAT将两个或多个字符串加在一起Concat with 将…...

NTP时间同步服务器@客户端时钟同步设置

NTP时间同步服务器客户端时钟同步设置 时间同步服务器支持NTP和SNTP网络同步协议&#xff0c;是一款高精度、大容量、高品质的时钟产品。设备采用冗余架构设计&#xff0c;高精度时钟直接来源于北斗、GPS系统中各个卫星的原子钟&#xff0c;通过信号解析驯服本地时钟源&#x…...