HarmonyOS Next开发学习手册——使用WebGL绘制图形

799 篇文章 5 订阅
349 篇文章 0 订阅

场景介绍

WebGL的全称为Web Graphic Library(网页图形库),主要用于交互式渲染2D图形。目前HarmonyOS中使用的WebGL是基于OpenGL裁剪的OpenGL ES,可以在HTML5的Canvas元素对象中使用,无需使用插件,支持跨平台。WebGL程序是由JavaScript代码组成的,其中使用的API可以利用用户设备提供的GPU硬件完成图形渲染和加速。

说明
目前该功能仅支持使用兼容JS的类Web开发范式开发。

基本概念

着色器程序

将缓冲区中的数据推送到着色器中还需涉及“着色器程序”,一个负责关联着色器和缓冲区的JavaScript对象。一个WebGLProgram对象由两个编译过后的 WebGLShader组成,即顶点着色器和片元着色器(均由GLSL语言所写)。

着色器

着色器可以理解为运行在显卡中的指令和数据。在WebGL中,着色器是用OpenGL ES着色语言(GLSL)编写的。

完整的着色器包括顶点着色器和片元着色器。顶点着色器和片元着色器的交互则涉及到图片光栅化。

  • 顶点着色器:最基本的任务是接收三维空间中点的坐标,将其处理为二维空间中的坐标并输出。

  • 片元着色器:最基本的任务是对需要处理的屏幕上的每个像素输出一个颜色值。

图片光栅化

将顶点着色器输出的二维空间中的点坐标,转化为需要处理的像素并传递给片元着色器的过程。

帧缓冲对象

帧缓冲区对象为绘图缓冲区提供替代呈现目标。它们是颜色、字母、深度和模板缓冲区的集合,通常用于渲染图像。

纹理

纹理是一种图像,可以应用到3D模型的表面上。WebGL中的纹理有许多属性,包括宽度、高度、格式和类型。在使用纹理时,需要将其加载到WebGL中,并将其绑定到一个纹理单元上。

变量与接口说明

变量类型

类型对应Web IDL类型描述
GLenumunsigned long用于枚举。
GLbooleanboolean纹理true或者false。
GLbitfieldunsigned long无符号整数,可以包含多个位标志。每个位标志都代表一个特定的选项
GLbytebyte纹理八位(一个字节),2的补码表示的有符号整数。
GLshortshort16位2的补码表示的有符号整数。
GLintlong32位2的补码表示的有符号整数。
GLsizeilong用来描述尺寸(例如:绘画缓冲drawing buffer 的宽和高)。
GLintptrlong long用来表示指针的特殊类型。
GLsizeiptrlong long用来表示指针的特殊类型。
GLubyteoctet八位(一个字节)2的补码表示的无符号整数。
GLushortunsigned short16位2的补码表示的无符号整数。
GLuintunsigned short32位2的补码表示的有符号整数。
GLfloatunrestricted float32位的IEEE标准的浮点数。
GLclampfunrestricted float限值32位IEEE浮点数。

接口说明

接口名描述
canvas.getContext获取canvas对象上下文。
webgl.createBuffer(): WebGLBuffer null创建与初始化WebGL数据缓冲区。
webgl.bindBuffer(target: GLenum, buffer: WebGLBuffer null): void将WebGL数据缓冲区与目标进行绑定。
webgl.bufferData(target: GLenum, srcData: ArrayBufferView, usage: GLenum, srcOffset: GLuint, length?: GLuint): void创建并初始化WebGL的数据存储区。
webgl.getAttribLocation(program: WebGLProgram, name: string): GLint从给定WebGL着色程序中获取着色器中attribute变量的地址。
webgl.vertexAttribPointer(index GLuint, size: GLint, type: GLenum, normalized: GLboolean, stride: GLsizei, offset: GLintptr): void将缓冲区对象分配给变量。
webgl.enableVertexAttribArray(index: GLuint): void连接变量与分配给它的缓冲区对象。
webgl.clearColor(red: GLclampf, green:GLclampf, blue: GLclampf, alpha: GLclampf): void清空指定的颜色。
webgl.clear(mask: GLbitfield): void清空。
webgl.drawArrays(mode: GLenum, first:;GLint, count: GLsizei): void执行数据绘制。
webgl.flush(): void刷新数据至GPU,清空缓冲区。
webgl.createProgram(): WebGLProgram null创建着色器程序对象。

开发步骤

如下以实现一个彩色正方形为例,来演示使用WebGL绘制2D图形的过程。

  1. 使用WebGL进行3D渲染前,首先需要一个Canvas元素。以下示例创建了一个Canvas元素并设置一个onclick事件处理程序来初始化WebGL上下文。
 <div class="container">
     <canvas ref="canvas1" style="width : 400px; height : 400px; background-color : lightyellow;"></canvas>
     <button class="btn-button" onclick="BtnColorTriangle">BtnColorTriangle</button>
 </div>
  1. 设置WebGL的上下文。
  • JavaScript 代码中的 main() 函数将会在文档加载完成之后被调用。它的任务是设置WebGL上下文并开始渲染内容。

  • 当获取到canvas之后,会调用getContext函数并向它传递 “webgl” 参数,来尝试获取WebGLRenderingContext。如果浏览器不支持WebGL, getContext将会返回null,如果WebGL上下文成功初始化,变量’gl’会用来引用该上下文。

function main() {
  const canvas = document.querySelector("#glcanvas");
  // 初始化WebGL上下文
  const gl = canvas.getContext("webgl");

  // 确认WebGL支持性
  if (!gl) {
    alert("你的浏览器、操作系统或硬件等可能不支持WebGL。");
    return;
  }
  // 使用完全不透明的黑色清除所有图像
  gl.clearColor(0.0, 0.0, 0.0, 1.0);
  // 用上面指定的颜色清除缓冲区
  gl.clear(gl.COLOR_BUFFER_BIT);
}
  1. 定义顶点着色器。

顶点着色器需要对顶点坐标进行必要的转换,在每个顶点基础上进行其他调整或计算,然后通过将其保存在由GLSL提供的特殊变量中来返回变换后的顶点。

const vsSource = `
   attribute vec4 aVertexPosition;
   uniform mat4 uModelViewMatrix;
   uniform mat4 uProjectionMatrix;
   void main() {
     gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition;
   }
 `;
  1. 定义片段着色器。

片段着色器在顶点着色器处理完图形的顶点后,会被要绘制的每个图形的每个像素点调用一次。

const fsSource = `
    void main() {
      gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
    }
 `;
  1. 将着色器传递给WebGL。

定义顶点着色器与片段着色器之后,需要将它们传递给WebGL,并将其编译连接在一起。

如下代码通过调用 loadShader(),为着色器传递类型和来源。创建了两个着色器。然后创建一个附加着色器的程序,将它们连接在一起。如果编译或链接失败,代码将弹出alert。

// 初始化着色器程序,让WebGL知道如何绘制数据
function initShaderProgram(gl, vsSource, fsSource) {
  const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);
  const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);
  // 创建着色器程序
  const shaderProgram = gl.createProgram();
  gl.attachShader(shaderProgram, vertexShader);
  gl.attachShader(shaderProgram, fragmentShader);
  gl.linkProgram(shaderProgram);
  // 如果创建失败,将会弹出alert
  if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
    alert(
      "无法初始化着色器程序: " +
     gl.getProgramInfoLog(shaderProgram),
    );
    return null;
  }
  return shaderProgram;
}
// 创建指定类型的着色器,上传source源码并编译
function loadShader(gl, type, source) {
  const shader = gl.createShader(type);
  // 将资源发送到着色器对象
  gl.shaderSource(shader, source);
  // 编译着色器程序
  gl.compileShader(shader);
  // 查看是否编译成功
  if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
    alert(
   "编译着色器时出错:" + gl.getShaderInfoLog(shader),
    );
    gl.deleteShader(shader);
    return null;
  }
  return shader;
}
  1. 查找WebGL返回分配的输入位置。
  • 在创建着色器程序之后,需要查找WebGL返回分配的输入位置。上述有一个属性和两个Uniform。
  • 属性从缓冲区接收值。顶点着色器的每次迭代都从分配给该属性的缓冲区接收下一个值。
  • Uniform类似于JavaScript全局变量。它们在着色器的所有迭代中保持相同的值。由于属性的位置是特定于单个着色器程序的,因此将它们存储在一起以易于传递。
const programInfo = {
  program: shaderProgram,
  attribLocations: {
    vertexPosition: gl.getAttribLocation(shaderProgram, "aVertexPosition"),
  },
  uniformLocations: {
    projectionMatrix: gl.getUniformLocation(shaderProgram, "uProjectionMatrix"),
    modelViewMatrix: gl.getUniformLocation(shaderProgram, "uModelViewMatrix"),
  },
};
  1. 创建缓冲器对象。
  • 在画正方形前,需要创建一个缓冲器来存储它的顶点。
  • 首先调用gl的成员函数createBuffer()得到缓冲对象并存储在顶点缓冲器。然后调用 bindBuffer() 函数绑定上下文。
  • 创建一个Javascript数组去记录每一个正方体的每一个顶点。然后将其转化为WebGL浮点型类型的数组,并将其传到gl对象的bufferData()方法来建立对象的顶点。
function initBuffers(gl) {
  const positionBuffer = initPositionBuffer(gl);
  return {
    position: positionBuffer,
  };
}
function initPositionBuffer(gl) {
  // 为正方形的位置创建一个缓冲区。
  const positionBuffer = gl.createBuffer();
  // 选择positionBuffer作为应用缓冲区的位置。
  gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
  // 创建一个正方形的位置数组。
  const positions = [1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, -1.0];
  //将位置列表传递给WebGL以构建形状。
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
  return positionBuffer;
}
export { initBuffers };
  1. 渲染场景。
  • 用背景色擦除画布,然后建立摄像机透视矩阵。设置45度的视图角度,并且设置一个适合实际图像的宽高比。指定在摄像机距离0.1到100单位长度的范围内的物体可见。
  • 加载特定位置,并把正方形放在距离摄像机6个单位的位置。然后,绑定正方形的顶点缓冲到上下文,并配置好,再通过调用drawArrays()方法来画出对象。
function drawScene(gl, programInfo, buffers) {
  gl.clearColor(0.0, 0.0, 0.0, 1.0); 
  gl.clearDepth(1.0); // 清除所有内容。
  gl.depthFunc(gl.LEQUAL); 
  // 清除画布。
   gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
  //创建透视矩阵用于模拟相机中的透视变形。
  const fieldOfView = (45 * Math.PI) / 180; 
  const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
  const zNear = 0.1;
  const zFar = 100.0;
  const projectionMatrix = mat4.create();
  mat4.perspective(projectionMatrix, fieldOfView, aspect, zNear, zFar);
  // 将绘制位置设置为标识点,即场景的中心。
  const modelViewMatrix = mat4.create();
  // 开始绘制正方形。
  mat4.translate(
    modelViewMatrix, // 目标矩阵
    modelViewMatrix, // 要转换的矩阵
    [-0.0, 0.0, -6.0],
  ); 
  {
    const numComponents = 2; 
    const type = gl.FLOAT; 
    const normalize = false; 
    const stride = 0; // 从一组值到下一组值需要多少字节
    const offset = 0; 
    gl.bindBuffer(gl.ARRAY_BUFFER, buffers.position);
    gl.vertexAttribPointer(
      programInfo.attribLocations.vertexPosition,
      numComponents,
      type,
      normalize,
      stride,
      offset,
    );
    gl.enableVertexAttribArray(programInfo.attribLocations.vertexPosition);
  }
  gl.useProgram(programInfo.program);
  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);
  }
}
// 告诉WebGL如何从位置中拉出位置缓冲到vertexPosition属性中。
function setPositionAttribute(gl, buffers, programInfo) {
  const numComponents = 2; 
  const type = gl.FLOAT; 
  const normalize = false;  
  const stride = 0; // 从一组值到下一组值需要多少字节
  const offset = 0;
  gl.bindBuffer(gl.ARRAY_BUFFER, buffers.position);
  gl.vertexAttribPointer(
    programInfo.attribLocations.vertexPosition,
    numComponents,
    type,
    normalize,
    stride,
    offset,
  );
  gl.enableVertexAttribArray(programInfo.attribLocations.vertexPosition);
}
export { drawScene };

最终实现效果示意如下:

鸿蒙全栈开发全新学习指南

有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以要有一份实用的鸿蒙(HarmonyOS NEXT)学习路线与学习文档用来跟着学习是非常有必要的。

针对一些列因素,整理了一套纯血版鸿蒙(HarmonyOS Next)全栈开发技术的学习路线,包含了鸿蒙开发必掌握的核心知识要点,内容有(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、WebGL、元服务、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、OpenHarmony驱动开发、系统定制移植等等)鸿蒙(HarmonyOS NEXT)技术知识点。

本路线共分为四个阶段

第一阶段:鸿蒙初中级开发必备技能

在这里插入图片描述

第二阶段:鸿蒙南北双向高工技能基础:gitee.com/MNxiaona/733GH

第三阶段:应用开发中高级就业技术

第四阶段:全网首发-工业级南向设备开发就业技术:gitee.com/MNxiaona/733GH

《鸿蒙 (Harmony OS)开发学习手册》(共计892页)

如何快速入门?

1.基本概念
2.构建第一个ArkTS应用
3.……

开发基础知识:gitee.com/MNxiaona/733GH

1.应用基础知识
2.配置文件
3.应用数据管理
4.应用安全管理
5.应用隐私保护
6.三方应用调用管控机制
7.资源分类与访问
8.学习ArkTS语言
9.……

基于ArkTS 开发

1.Ability开发
2.UI开发
3.公共事件与通知
4.窗口管理
5.媒体
6.安全
7.网络与链接
8.电话服务
9.数据管理
10.后台任务(Background Task)管理
11.设备管理
12.设备使用信息统计
13.DFX
14.国际化开发
15.折叠屏系列
16.……

鸿蒙开发面试真题(含参考答案):gitee.com/MNxiaona/733GH

鸿蒙入门教学视频:

美团APP实战开发教学:gitee.com/MNxiaona/733GH

写在最后

  • 如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:
  • 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
  • 关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识。
  • 想要获取更多完整鸿蒙最新学习资源,请移步前往小编:gitee.com/MNxiaona/733GH

  • 20
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用 WebGL 绘制正方形需要进行以下步骤: 1. 获取 WebGL 上下文对象 ```javascript const canvas = document.querySelector('canvas'); const gl = canvas.getContext('webgl'); ``` 2. 设置顶点着色器和片元着色器 ```javascript const vertexShaderSource = ` attribute vec2 a_position; void main() { gl_Position = vec4(a_position, 0, 1); } `; const fragmentShaderSource = ` precision mediump float; void main() { gl_FragColor = vec4(1, 0, 0, 1); } `; const vertexShader = gl.createShader(gl.VERTEX_SHADER); gl.shaderSource(vertexShader, vertexShaderSource); gl.compileShader(vertexShader); const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); gl.shaderSource(fragmentShader, fragmentShaderSource); gl.compileShader(fragmentShader); ``` 3. 创建着色器程序并链接顶点着色器和片元着色器 ```javascript const program = gl.createProgram(); gl.attachShader(program, vertexShader); gl.attachShader(program, fragmentShader); gl.linkProgram(program); gl.useProgram(program); ``` 4. 创建缓冲区并绑定数据 ```javascript const positionBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); const positions = [ -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5, ]; gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW); ``` 5. 设置顶点属性指针并启用 ```javascript const positionAttributeLocation = gl.getAttribLocation(program, 'a_position'); gl.enableVertexAttribArray(positionAttributeLocation); gl.vertexAttribPointer(positionAttributeLocation, 2, gl.FLOAT, false, 0, 0); ``` 6. 清空画布并绘制正方形 ```javascript gl.clearColor(0, 0, 0, 0); gl.clear(gl.COLOR_BUFFER_BIT); gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); ``` 完整的 WebGL 绘制正方形的代码如下: ```javascript const canvas = document.querySelector('canvas'); const gl = canvas.getContext('webgl'); const vertexShaderSource = ` attribute vec2 a_position; void main() { gl_Position = vec4(a_position, 0, 1); } `; const fragmentShaderSource = ` precision mediump float; void main() { gl_FragColor = vec4(1, 0, 0, 1); } `; const vertexShader = gl.createShader(gl.VERTEX_SHADER); gl.shaderSource(vertexShader, vertexShaderSource); gl.compileShader(vertexShader); const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); gl.shaderSource(fragmentShader, fragmentShaderSource); gl.compileShader(fragmentShader); const program = gl.createProgram(); gl.attachShader(program, vertexShader); gl.attachShader(program, fragmentShader); gl.linkProgram(program); gl.useProgram(program); const positionBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); const positions = [ -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5, ]; gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW); const positionAttributeLocation = gl.getAttribLocation(program, 'a_position'); gl.enableVertexAttribArray(positionAttributeLocation); gl.vertexAttribPointer(positionAttributeLocation, 2, gl.FLOAT, false, 0, 0); gl.clearColor(0, 0, 0, 0); gl.clear(gl.COLOR_BUFFER_BIT); gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); ``` 这样就可以在 canvas 中绘制一个红色的正方形了。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值