文章目录

  • 前言
  • 绘制一个点
    • 初始化着色器
    • 存储限定符
    • 向 webgl 系统传递变量

前言

接前面文章,我们实现了一个最简单的 webgl 程序,但是只是程序运行起来只是漆黑一片,我们想要通过 webgl 绘制一些图形。这篇文章让我们来使用 webgl 绘制一个点,并使用着色器来给他点颜色看看。

绘制一个点

还是先上代码:

import React, { useRef, useEffect } from 'react'
import { VSHADERR_SOURCE, FSHADER_SOURCE } from './glsl'const HelloPoint = () => {const canvasDom = useRef<HTMLCanvasElement | null>(null)// 创建程序const createProgram = (gl: WebGLRenderingContext, vshader: string, fshader: string) => {const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vshader)const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fshader)if (!vertexShader || !fragmentShader) {return null}// 创建程序对象const program = gl.createProgram()if (!program) {return null}// 为程序对象分配着色器gl.attachShader(program, vertexShader)gl.attachShader(program, fragmentShader)// 连接程序对象gl.linkProgram(program)// Check the result of linkingconst linked = gl.getProgramParameter(program, gl.LINK_STATUS)if (!linked) {const error = gl.getProgramInfoLog(program)console.log(`Failed to link program: ${error}`)gl.deleteProgram(program)gl.deleteShader(fragmentShader)gl.deleteShader(vertexShader)return null}return program}const loadShader = (gl: WebGLRenderingContext, type: number, source: string) => {// 创建 shader 对象const shader = gl.createShader(type)if (shader === null) {console.log('unable to create shader')return null}// 向着色器对象中填充着色器程序的源代码gl.shaderSource(shader, source)// 编译着色器gl.compileShader(shader)// Check the result of compilationconst compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS)if(!compiled) {const error = gl.getShaderInfoLog(shader)console.log(`Failed to compile shader: ${error}`)gl.deleteShader(shader)return null}return shader}// 初始化着色器const initShader = (gl: WebGLRenderingContext, vshader: string, fshader: string) => {const program = createProgram(gl, vshader, fshader)if (!program) {console.log('Failed to create program')return false}// 使用程序对象gl.useProgram(program);(gl as any).program = programreturn true}const main = () => {if (!canvasDom.current) returnconst gl = canvasDom.current.getContext('webgl')if (!gl) {console.log('Failed to get the rendering context for WebGL')return}// 初始化着色器if (!initShader(gl, VSHADERR_SOURCE, FSHADER_SOURCE)) {console.log('Failed to intialize shaders.')return}// 获取 attribute 变量的存储位置const a_Position = gl.getAttribLocation((gl as any).program, 'a_Position')// 获取存储位置其实是从 0 开始根据定义的位置依次计数的结果if (a_Position < 0) {console.log('Failed to get the storage location of a_Position')return}// 将顶点位置传输给 attribute 变量gl.vertexAttrib3f(a_Position, 0.0, 0.0, 0.0)// 指定清空 canavs 的颜色gl.clearColor(0.0, 0.0, 0.0, 1.0)// 清空 canvasgl.clear(gl.COLOR_BUFFER_BIT)// 绘制一个点gl.drawArrays(gl.POINTS, 0, 1)}useEffect(() => {main()// eslint-disable-next-line react-hooks/exhaustive-deps}, [])return (<canvas ref={canvasDom} style={{width: '500px',height: '500px'}}></canvas>)
}export default HelloPoint

代码有点多,我们慢慢来看,首先看初始化着色器部分;

初始化着色器

在三维场景中,仅仅用线条和颜色将图层绘制出来是远远不够的,比如我们需要模拟光照打在物体上,高光部门以及阴影部分的展示等等;着色器可以高度灵活地完成对于图形的这些各种渲染效果。

创建和初始化着色器需要以下几个步骤:

  1. 创建着色器对象:gl.createShader();
  2. 向着色器对象中填充着色器程序的源代码:gl.shaderSource();
  3. 编译着色器:gl.compileShader();
  4. 创建程序对象:gl.createProgram();
  5. 为程序对象分配着色器: gl.attachShader();
  6. 连接程序对象:gl.linkProgram();
  7. 使用程序对象:gl.useProgram();

步骤也很简单也就是创建着色器,然后通过 program 将顶点着色器和片元着色器连接起来;program 对象进行着色器连接操作,目的是保证:

  1. 顶点着色器和片元着色器的 varying 变量同名同类型,且一一对应;
  2. 顶点着色器对每个 varying 变量赋了值;
  3. 顶点着色器和片元着色器中的同名 uniform 变量也是同类型的,无需一一对应,即某些 uniform 变量可以出现在一个着色器中而不出现在另一个中。
  4. 着色器中的 attribute 变量、uniform 变量和 varying 变量的个数没有超过着色器的上限。

如果程序已经成功连接,我们得到了一个二进制的可执行模块供 webgl 系统使用。如果连接失败了,也可以通过调用 gl.getProgramInfiLog(program) 从信息日志中获取连接出错信息。

最后我们通过 gl.useProgram(program) 告知 webgl 系统绘制时使用哪个程序对象,该函数接收一个指定待使用的程序对象做为参数。

我们可以在绘制前初始化多个程序对象,然后在绘制的时候根据需要切换程序对象。

存储限定符

我们发现;在 JavaScript 中我们通过 gl.getAttribLocation() 函数获取 webgl 程序变量的存储地址。到现在我们也没看到着色器代码;如下:

export const VSHADERR_SOURCE = `attribute vec4 a_Position;void main() {// 设置坐标gl_Position = a_Position;// 设置尺寸gl_PointSize = 10.0;}
`export const FSHADER_SOURCE = `void main() {// 设置点的颜色gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);}
`

这是 GLSL 着色器语言,很简单相信大家可以看懂。主要需要注意的是,attribute 数据类型。对于着色器语言,具有三种数据类型:

  • attribute:只能在顶点着色器中使用的变量,一般用于传递顶点数据(顶点、索引、颜色、法向量等);
  • uniform:常量,不能被 shader 修改,uniform 变量在顶点着色器和片元着色器两者之间声明方式完全一致,则他可以在顶点着色器和片元着色器共享使用,相当于一个被顶点着色器和片元着色器共享的全局变量。通常是一个全局的变量(如颜色、光照参数等),或者全局的矩阵(如世界矩阵、观察矩阵等等)
  • varying:varying 变量是顶点着色器和片元着色器之间做数据传递用的。

我们上面代码通过 attribute 类型的变量传递我们绘制点的坐标。

向 webgl 系统传递变量

接下来就是需要向 webgl 系统中传递绘制点的坐标;传递值我们首先得获取该值的位置,如下代码:

    // 获取 attribute 变量的存储位置const a_Position = gl.getAttribLocation((gl as any).program, 'a_Position')// 获取存储位置其实是从 0 开始根据定义的位置依次计数的结果if (a_Position < 0) {console.log('Failed to get the storage location of a_Position')return}

对于 attribute 定义的变量通过 getAttribLocation() 方法进行获取,当然通过 uniform 定义的变量通过 getUniformLocation() 方法进行获取。获取存储位置其实是从 0 开始根据定义的位置依次计数的结果;

然后获取到位置,我们需要将值传输给变量:

    // 将顶点位置传输给 attribute 变量gl.vertexAttrib3f(a_Position, 0.0, 0.0, 0.0)

需要注意的是,webgl 使用的是颜色缓冲区,webgl 系统中的绘制操作实际上是在颜色缓冲区中进行绘制的,绘制结束后系统将缓冲区中的内容显示在屏幕上,然后颜色缓冲区就会被重置,其中的内容会丢失;如果我们需要实时绘制点,比如鼠标点击之后绘制点,需要将鼠标点击的点进行记录,每次点击完成之后通过循环,渲染之前的点。

至此,我们的着色器使用已经完成。

webgl——使用着色器给图形给点颜色看看(二)相关推荐

  1. webgl入门(2)-初识webgl和着色器

    前言 原书中第2章非常长,如果整理成一个文档的话,得看好多天.为了浏览方便,我将其拆分成若干小节,方便大家学习. webgl采用HTML5中引入的canvas元素来定义页面的绘图区域.如果没有WegG ...

  2. VTK 学习----3D基础知识-着色器和图形管道

    2.5 着色器和图形管道 2.5.1 图形管道 在三维绘图引擎中,一切物体都在三维空间,但屏幕和窗口是2D像素阵列,因此三维引擎的大部分工作是将所有3D坐标转换为合适屏幕的2D像素.将3D坐标转换为2 ...

  3. OpenGL ES着色器语言之变量和数据类型(二)(官方文档第四章)

    OpenGL ES着色器语言之变量和数据类型(二)(官方文档第四章) 4.5精度和精度修饰符 4.5.1范围和精度 用于存储和展示浮点数.整数变量的范围和精度依赖于数值的源(varying,unifo ...

  4. Opengl入门基础-shader着色器画方形并且填颜色

    文章目录 一.目的 二.结果 三.详细过程 下载 一.目的 opengl shader画方形并且填颜色 二.结果 成功画方形并用shader填充彩色 三.详细过程 https://blog.csdn. ...

  5. WebGL切换着色器方法与错误

    WebGL一种着色器,是无法满足渲染需求的,需要使用不同的渲染器,这次测试了 一下渲染器的切换.切换渲染器的时候,上一个着色器的东西肯定是要清除的. gl.deleteShader(FSShader) ...

  6. 网页高性能图形编程(四)-WebGL颜色-使用着色器绘制多顶点颜色的三角图形 操作部骤-顶点着色器和片段着色器 着色器编译羽图像绘制-vertexAttribPointer 方法

    第5章-WebGL颜色 01-操作步骤介绍 颜色添加步骤 在顶点着色器中定义一个接收外部传入颜色值的属性变量a_Color和用于传输获取到的颜色值变量v_Color 在片段着色器中定义一个同一类型和名 ...

  7. “着色器”是什么意思? 如何使用HTML5和WebGL创建它们

    本文是Microsoft的Web开发技术系列的一部分. 感谢您支持使SitePoint成为可能的合作伙伴. 您可能已经注意到,去年我们第一次谈论了babylon.js ,最近发布了带有3D声音定位(使 ...

  8. WebGL基础:着色器基础知识

    今天由字节跳动的"yancy"童鞋给大家重磅推出一篇WebGL的干货接下来让我们开启奇幻旅程,进入 3D 的世界. 本文作者:yancy 1. 认识3D 首先我们要介绍的是几个概念 ...

  9. webgl 着色器_“着色器”是什么意思? 如何使用HTML5和WebGL创建它们

    webgl 着色器 本文是Microsoft的Web开发技术系列的一部分. 感谢您支持使SitePoint成为可能的合作伙伴. 您可能已经注意到,去年我们第一次谈论了babylon.js ,最近我们发 ...

最新文章

  1. [收藏] 王永民先生:自我白描
  2. 西南科技大学智能车竞赛 线上比赛
  3. android核心机制之Zygote启动流程
  4. java 回调(callback)函数简介.
  5. Android JNI_OnLoad()函数
  6. Spring Boot和Spring Data REST –通过REST公开存储库
  7. C/C++打造《百万级人脸识别系统》
  8. vue 设置全局变量、指定请求的 baseurl
  9. 「雕爷学编程」Arduino动手做(38)——joystick双轴摇杆模块
  10. 有奖投票丨HC2019开发者关注的TOP10问题你最想听哪个?
  11. 解决service iptables save出错please try to use systemctl.
  12. JSpider(3):JSpider的结构
  13. 一台电脑如何同开两个或多个飞信?
  14. ESP32利用百度智能云实现图像识别 文字识别
  15. lisp全部文本改宋体字型_如何将CAD里面的文字一下全改成宋体 CAD2014中如何将图...
  16. 移动硬盘在Mac上无法拷贝或删除文件的解决办法
  17. FlashFXP连接ftp服务器上传下载
  18. C++ 制作FlappyBird
  19. Python之NumPy(axis=0/1/2...)的透彻理解——通过np.sum(axis=?)实例进行说明
  20. 制造并批量生产现实版“储物戒指”

热门文章

  1. 电脑屏幕录像软件 OBS Studio
  2. java酷跑_不敢相信,居然用Java写了个“天天酷跑”!
  3. 软件项目管理系统-外包管理-外包验收申请
  4. 2021年起重机械指挥考试及起重机械指挥考试试卷
  5. 公务员主要的工作内容有哪些呢?
  6. 使用roslaunch启动Gazebo、world文件和URDF模型
  7. 【论文解读 ICDM 2019 | MVNN】Exploiting Multi-domain Visual Information for Fake News Detection
  8. 基于Aspose.Words 生成Word文件
  9. 龙芯可以运行linux吗,开源的龙芯主板可顺利启动Linux系统
  10. 模拟电路设计入门系列 --- 巧学系列