万丈高楼平地起。


01基础知识

一、相关术语

  • 图元 :WebGL 能够绘制的基本图形元素,包含三种:线段三角形
  • 片元:可以理解为像素,像素着色阶段是在片元着色器中。
  • 裁剪坐标系:裁剪坐标系是顶点着色器中的 gl_Position 内置变量接收到的坐标所在的坐标系。
  • 设备坐标系:又名 NDC 坐标系,是裁剪坐标系各个分量对 w 分量相除得到的坐标系,特点是 x、y、z 坐标分量的取值范围都在 【-1,1】之间,可以将它理解为边长为 2 的正方体,坐标系原点在正方体中心。

二、GLSL


  • gl_Position:内置变量,用来设置顶点的裁剪坐标系坐标,包含 X, Y, Z,W 四个坐标分量。顶点着色器接收到这个坐标之后,对它进行透视除法,即将各个分量同时除以 W,转换成 NDC 坐标,NDC 坐标每个分量的取值范围都在【-1, 1】之间,GPU 获取这个属性值作为顶点的最终位置进行绘制。
  • gl_PointSize:内置变量,用来设置顶点大小。只有在绘制图元是的时候才会生效。
  • gl_FragColor:片元(像素)颜色,包含 R, G, B, A 四个颜色分量,且每个分量的取值范围在【0,1】之间,GPU 获取这个值作为像素的最终颜色进行着色。
  • gl_FragColor:内置变量,用来设置像素颜色。
  • attribue 变量:只能在顶点着色器中定义。
  • uniform 变量:既可以在顶点着色器中定义,也可以在片元着色器中定义。
  • 最后一种变量类型 varing 变量:它用来从顶点着色器中往片元着色器传递数据。使用它我们可以在顶点着色器中声明一个变量并对其赋值,经过插值处理后,在片元着色器中取出插值后的值来使用。
  • vec4:4 维向量,包含四个浮点元素的容器类型,vec 是 vector(向量)的单词简写,vec4 代表包含 4 个浮点数的向量。此外,还有 vec2vec3 等类型,代表包含2个或者3个浮点数的容器。
  • precision:精度设置限定符,使用此限定符设置完精度后,之后所有该数据类型都将沿用该精度,除非单独设置。
  • 运算符:向量的对应位置进行运算,得到一个新的向量。
    • vec * 浮点数:vec2(x, y) * 2.0 = vec(x * 2.0, y * 2.0)。
    • vec2 * vec2:vec2(x1, y1) * vec2(x2, y2) = vec2(x1 * x2, y1 * y2)。
    • 加减乘除规则基本一致。但是要注意一点,如果参与运算的是两个 vec 向量,那么这两个 vec 的维数必须相同。

GLSL 中 gl_Position 所接收的坐标所在坐标系是裁剪坐标系 ,不同于我们的浏览器窗口坐标系。所以当我们赋予 gl_Position 位置信息的时候,需要对其进行转换才能正确显示。

三、JAVASCRIPT程序如何向连接着色器程序


  • createShader:创建着色器对象
  • shaderSource:提供着色器源码
  • compileShader:编译着色器对象
  • createProgram:创建着色器程序
  • attachShader:绑定着色器对象
  • linkProgram:链接着色器程序
  • useProgram:启用着色器程序

四、JAVASCRIPT如何往着色器中传递数据


  • getAttribLocation:找到着色器中的 attribute 变量地址。
  • getUniformLocation:找到着色器中的 uniform 变量地址。
  • vertexAttrib2f:给 attribute 变量传递两个浮点数。
  • uniform4f:给uniform变量传递四个浮点数。

五、WebGL 绘制函数


  • drawArrays: 用指定的图元进行绘制。

gl.drawArrays 是执行绘制的 API,上面示例中的第一个参数 gl.POINTS 代表我们要绘制的是点图元,第二个参数代表要绘制的顶点的起始位置,第三个参数代表顶点绘制个数。

六、WebGL 图元


  • gl.POINTS: 将绘制图元类型设置成点图元

02代码

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>WebGL 绘制点</title>
<script type="x-shader/x-vertex" id="vertexShader">
//设置浮点数精度为中等精度
precision mediump float;
// 接收点在canvas坐标系上的坐标(x,y)
attribute vec2 a_Position;
// 接受canvas 的宽高尺寸
attribute vec2 a_Screen_Size;
void main(){
//start 将屏幕坐标系转化为裁剪坐标(裁剪坐标系)
vec2 position = (a_Position / a_Screen_Size) * 2.0 - 1.0;
position = position * vec2(1.0, -1.0);
gl_Position = vec4(position, 0.0, 1.0);
//end 将屏幕坐标系转化为裁剪坐标(裁剪坐标系)
//声明要绘制的点的大小。
gl_PointSize = 10.0;
}
</script>
<script type="x-shader/x-fragment" id="fragmentShader">
//设置浮点数精度为中等精度
precision mediump float;
//接收 JavaScript 传过来的颜色值(RGBA)。
uniform vec4 u_Color;
void main(){
//将普通的颜色表示转化为 WebGL 需要的表示方式,即将【0-255】转化到【0,1】之间。
vec4 color = u_Color / vec4(255, 255, 255, 1);
gl_FragColor = color;
}
</script>
</head>
<body>
<canvas id="canvas"></canvas>
</body>
</html>
<script>
function createShaderFromScript(gl, mode, id) {
// 获取着色器源码
var shaderSource = document.getElementById(id).innerHTML;
// 创建着色器对象
var shader = gl.createShader(mode);
// 将源码分配给着色器对象
gl.shaderSource(shader,shaderSource);
// 编译着色器
gl.compileShader(shader);

return shader;
}
function createProgram(gl, vertexShader, fragmentShader) {
var program = gl.createProgram();
// 将顶点着色器挂载在着色器程序上。
gl.attachShader(program, vertexShader);
//将片元着色器挂载在着色器程序上。
gl.attachShader(program, fragmentShader);
//链接着色器程序
gl.linkProgram(program);

return program;
}

var canvas = document.getElementById('canvas');
var gl = canvas.getContext('webgl') || canvas.getContext("experimental-webgl");

<!--region 创建着色器对象-->
var vertexShader = createShaderFromScript(gl, gl.VERTEX_SHADER, 'vertexShader');
var fragmentShader = createShaderFromScript(gl, gl.FRAGMENT_SHADER, 'fragmentShader')
<!--endregion-->

<!--region 创建着色器程序-->
//创建着色器程序
let program = createProgram(gl, vertexShader, fragmentShader);

// 使用刚刚创建好的着色器程序
gl.useProgram(program);
<!--endregion-->

//找到顶点着色器中的变量a_Position
var a_Position = gl.getAttribLocation(program, 'a_Position');
//找到顶点着色器中的变量a_Screen_Size
var a_Screen_Size = gl.getAttribLocation(program, 'a_Screen_Size');
//找到片元着色器中的变量u_Color
var u_Color = gl.getUniformLocation(program, 'u_Color');
//为顶点着色器中的 a_Screen_Size 传递 canvas 的宽高信息
gl.vertexAttrib2f(a_Screen_Size, canvas.width, canvas.height);
//存储点击位置的数组。
var points = [];
function randomColor(){
return {
r: Math.ceil(Math.random() * 255),
g: Math.ceil(Math.random() * 255),
b: Math.ceil(Math.random() * 255),
a: Math.ceil(Math.random()),
};
}
canvas.addEventListener('click',e=>{
var x = e.pageX;
var y = e.pageY;

var color = randomColor();

points.push({x,y,color});
gl.clearColor(0, 0, 0, 1.0);
//用上一步设置的清空画布颜色清空画布。
gl.clear(gl.COLOR_BUFFER_BIT);

for (let i = 0; i < points.length; i++) {
let color = points[i].color;
gl.uniform4f(u_Color, color.r, color.g, color.b, color.a);
//为顶点着色器中的 a_Position 传递顶点坐标。
gl.vertexAttrib2f(a_Position, points[i].x, points[i].y);

// 绘制点
gl.drawArrays(gl.POINTS, 0, 1);
}
})

//设置清空画布颜色为黑色。
gl.clearColor(0.0,0.0,0.0,1.0);
//用上一步设置的清空画布颜色清空画布。
gl.clear(gl.COLOR_BUFFER_BIT);

</script>

vec2 position = (a_Position / a_Screen_Size) * 2.0 - 1.0

上面这句代码用来将浏览器窗口坐标转换成裁剪坐标,之后通过透视除法,除以 w 值(此处为 1 )转变成设备坐标(NDC坐标系)。这个算法首先将(x,y) 转化到【0, 1】区间,再将 【0, 1】之间的值乘以 2 转化到 【0, 2】区间,之后再减去 1 ,转化到 【-1, 1】之间的值,即 NDC 坐标

初级入门 --- web GL绘制点的更多相关文章

  1. 响应式Web初级入门

    本文来自我的前端博客,原文地址:http://www.hacke2.cn/about-responsive/ 跨终端时代的到来 当你乘坐各种交通工具(公交.地铁.轻轨.火车)时你会发现,人们都个个低下 ...

  2. 零基础快速入门web学习路线(含视频教程)

    下面小编专门为广大web学习爱好者汇总了一条完整的自学线路:零基础快速入门web学习路线(含视频教程)(绝对纯干货)适合初学者的最新WEB前端学习路线汇总! 在当下来说web前端开发工程师可谓是高福利 ...

  3. hadoop入门手册5:Hadoop【2.7.1】初级入门之命令:文件系统shell2

    问题导读 1.改变hdfs文件的权限,需要修改哪个配置文件?2.获取一个文件的或则目录的权限,哪个命令可以实现?3.哪个命令可以实现设置访问控制列表(ACL)的文件和目录? 接上篇:Hadoop[2. ...

  4. hadoop入门手册4:Hadoop【2.7.1】初级入门之命令:文件系统shell1

    问题导读1.Hadoop文件系统shell与Linux shell有哪些相似之处?2.如何改变文件所属组?3.如何改变hdfs的文件权限?4.如何查找hdfs文件,并且不区分大小写? 概述文件系统 ( ...

  5. hadoop入门手册3:Hadoop【2.7.1】初级入门之命令指南

    问题导读1.hadoop daemonlog管理员命令的作用是什么?2.hadoop如何运行一个类,如何运行一个jar包?3.hadoop archive的作用是什么? 概述 hadoop命令被bin ...

  6. Spring Cloud实战之初级入门(五)— 配置中心服务化与配置实时刷新

    目录 1.环境介绍 2.配置中心服务化 2.1 改造mirco-service-spring-config 2.2 改造mirco-service-provider.mirco-service-con ...

  7. SpringCloud实战之初级入门(二)— 服务注册与服务调用

    目录 1.环境介绍 2.服务提供 2.1 创建工程 2.2 修改配置文件 2.3 修改启动文件 2.5 亲测注意事项 3.服务调用 3.1 创建工程 3.2 修改配置文件 3.3 修改启动文件 3.4 ...

  8. mui初级入门教程(六)— 模板页面实现原理及多端适配指南

    文章来源:小青年原创发布时间:2016-07-26关键词:mui,webview,template,os,多端适配转载需标注本文原始地址: http://zhaomenghuan.github.io. ...

  9. mui初级入门教程(四)— 再谈webview,从小白变“大神”!

    文章来源:小青年原创发布时间:2016-06-05关键词:mui,html5+,webview转载需标注本文原始地址: http://zhaomenghuan.github.io/#!/blog/20 ...

随机推荐

  1. yp寒假训练一

    19年东北四省省赛 做了J G C 补了E H J签到题 G 题意: 给n个正方形的两个斜对角点坐标,问最小的移动可以重叠(移动上下左右一格) 思路: 一开始想的是中心pos移动,但是可能有小数,而且 ...

  2. Pako.js压缩解压,vue压缩解压,前后端之间高效数据传输

    项目开发中常常会遇到前后端之间有大量数据传输占用带宽导致页面响应慢的问题,这时候我们可以考虑使用Pako.js对信息进行压缩之后传输. 我在前端使用的是vue-element-admin前端框架.框架 ...

  3. 二十二、mysql 执行计划与存储引擎

    1.explain(执行计划)中涉及的各字段理解1.1) select_type列的取值及含义:    SIMPLE                 :简单的SELECT语句(不包括UNION操作或子 ...

  4. scp 远程文件拷贝命令

    Linux scp命令用于Linux之间复制文件和目录. scp是 secure copy的缩写, scp是linux系统下基于ssh登陆进行安全的远程文件拷贝命令. 1.从本地复制到远程 命令格式: ...

  5. 「JSOI2015」最大公约数

    「JSOI2015」最大公约数 传送门 考虑先枚举区间左端点, 然后我们会发现所有可能的区间虽然有 \(O(n)\) 个,但是本质不同的区间 \(\gcd\) 只有 \(\log n\) 级别,而且是 ...

  6. 「luogu3402」【模板】可持久化并查集

    「luogu3402」[模板]可持久化并查集 传送门 我们可以用一个可持久化数组来存每个节点的父亲. 单点信息更新和查询就用主席树多花 一个 \(\log\) 的代价来搞. 然后考虑如何合并两个点. ...

  7. java基础课程笔记 static 主函数 静态工具类 classpath java文档注释 静态代码块 对象初始化过程 设计模式 继承 子父类中的函数 继承中的构造函数 对象转型 多态 封装 抽象类 final 接口 包 jar包

    Static那些事儿 Static关键字 被static修饰的变量成为静态变量(类变量) 作用:是一个修饰符,用于修饰成员(成员变量,成员方法) 1.被static修饰后的成员变量只有一份 2.当成员 ...

  8. kali安装vm tools正确操作

    参考博文:https://blog.csdn.net/qq_39536876/article/details/79501471 前言:每次在执行完 ./vmware-install.pl 重启后,总是 ...

  9. spring boot ApplicationRunner使用

    spring boot ApplicationRunner使用 它的使用比较简单,实现ApplicationRunner的run方法 package com.hikvision.pbg.jc.conf ...

  10. keil条件断点

    http://www.keil.com/support/man/docs/uv4/uv4_db_dbg_breakpnts.htm Target Device does not support con ...