04webgl的实际绘图思路
知识点
webgl的绘图思路
- 找一台电脑
- 浏览器里内置的webgl渲染引擎,负责渲染webgl图形,只认GLSL ES语言
- 找一块手绘板
- 程序对象,承载GLSL ES语言,翻译GLSL ES语言和js语言,使两者相互童心
- 找一只触控笔
- 通过canvas获取的webgl类型的上下文对象,可以向手绘板传递绘图命令,并接收手绘板的状态信息
- 开始画画
- 通过webgl类型的上下文对象,用js画画
webgl的绘图步骤
- 在html中建立canvas画布
- 在js中获取画布
const canvas = document.querySelector("#canvas")
- 使用canvas获取webgl上下文
const gl = canvas.getContext(“webgl”)
- 在script中建立顶点着色器和片元着色器,用的是glsl es语言
- 顶点着色器:描述顶点的特征,如位置、颜色等。
- gl_Position = vec4(0.0, 0.0, 0.0, 1.0);表示点的位置,默认参数为0, 0, 0, 1
- 第一个参数代表x轴,负数向左,正数向右,如果-1,代表点的中心在画布最左侧,如果1,代表点的中心在画布最右侧
- 第二个参数代表y轴,负数向下,正数向上,如果-1,达标点的中心在画布最下方,如果1,代表点的中心在画布最上方
- 第三个参数代表z轴,表示远近
(后面会讲)
- gl_Position = vec4(0.0, 0.0, 0.0, 1.0);表示点的位置,默认参数为0, 0, 0, 1
- 片元着色器:进行逐片元处理,如光照。
- 顶点着色器:描述顶点的特征,如位置、颜色等。
<!-- 顶点着色器 -->
<script id="vertexShader" type="x-shader/x-vertex">
void main() {
// 点位,单词gl_Position是写死的,专门用于接收点位的,后面要写分号
gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
// 点的尺寸,单词gl_PointSize写死的,值一定是浮点,后面要写分号
gl_PointSize = 100.0;
}
<\/script>
<!-- 片元着色器 -->
<script id="fragmentShader" type="x-shader/x-fragment">
void main() {
// 片元,单词gl_FragColor写死的,
gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0); // 黄色
}
<\/script>
- 在js中获取顶点着色器和片元着色器的文本
- 目的:用于后面初始化着色器
- 方法:获取顶点着色器和片元着色器的script的两个DOM元素,然后获取innerText
- 返回值:顶点着色器和片元着色器的script中的两段viod main函数
// 获取着色器的文本,获取着色器文本的目的是用于后面初始化着色器
// 获取顶点着色器文本
const vsSource = document.querySelector("#vertexShader").innerText;
// 获取片元着色器文本
const fsSource = document.querySelector("#fragmentShader").innerText;
```
6. 初始化着色器
- 初始化着色器的功能:解析着色器文本,整合到程序对象,关联webgl上下文对象,实现两种语言的相互通信
```go
initShaders(gl, vsSource, fsSource);
// 注意:这个initShaders函数是要自己实现的,如下
function initShaders(gl,vsSource,fsSource){
//创建程序对象
const program = gl.createProgram();
//建立着色对象
const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);
const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);
//把顶点着色对象装进程序对象中
gl.attachShader(program, vertexShader);
//把片元着色对象装进程序对象中
gl.attachShader(program, fragmentShader);
//连接webgl上下文对象和程序对象
gl.linkProgram(program);
//启动程序对象
gl.useProgram(program);
//将程序对象挂到上下文对象上
gl.program = program;
return true;
}
function loadShader(gl, type, source) {
//根据着色类型,建立着色器对象
const shader = gl.createShader(type);
//将着色器源文件传入着色器对象中
gl.shaderSource(shader, source);
//编译着色器对象
gl.compileShader(shader);
//返回着色器对象
return shader;
}
- 指定将要用来清空绘图区的颜色
gl.clearColor(0, 0, 0, 1)
这里设置底色Wie黑色 - 使用之前设定的颜色,清空绘图区
gl.clear(gl.COLOR_BUFFER_BIT)
- 绘制顶点
- gl.drawArrays(mode, FIRST, COUNT)
- mode代表绘制方式,具体方式如下:
- gl.POINTS 绘制一系列点
- gl.LINE_STRIP 绘制一个线条。即绘制一系列线段,上一点链接下一点
- gl.LINE_LOOP 绘制一个线圈。即绘制一系列线段,上一个点链接下一个点,并且最后一点与第一个点相连
- gl.LINES 绘制一系列单独线段。每两个点作为端点,线段之间不连接
- gl.TRIANGLE_STRIP 绘制一个三角带
- gl.TRIANGLE_FAN 绘制一个三角扇
- gl.TRIANGLES 绘制一系列三角形。每三个点作为定点
- FIRST
- Glint类型,代表指定从哪个点开始绘制
- COUNT
- GLsizei类型,代表指定绘制需要使用到多少个点
gl.drawArrays(gl.POINTS, 0, 1)
- GLsizei类型,代表指定绘制需要使用到多少个点
- mode代表绘制方式,具体方式如下:
- gl.drawArrays(mode, FIRST, COUNT)
webgl绘图需要两种着色器:
- 顶点着色器(Vertex shader):描述定点的特征,比如位置。颜色等
- 片元着色器(Fragment shader):进行片元处理,如光照
- webgl中的片元就是像素的意思
举例说明:
两点决定一条直线,两个点就是顶点着色器的顶点,把直线画到画布上后,两个点之间构成的每个像素就是片元
代码
<!--
* @Author: 俞华
* @Date: 2021-02-28 23:06:22
* @LastEditors: 俞华
* @LastEditTime: 2021-03-01 22:06:42
* @CSDN_BLOG: https://blog.csdn.net/qq_17175013
* @wechat: 809742006
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>01-刷底色</title>
<style>
body{
margin: 0;
overflow: hidden;
}
#canvas{
background-color: red;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<!-- 顶点着色器 -->
<script id="vertexShader" type="x-shader/x-vertex">
void main() {
// 设置点位,单词gl_Position是写死的,专门用于接收点位的,后面要写分号
gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
// 点的尺寸,单词gl_PointSize写死的,值一定是浮点,后面要写分号
gl_PointSize = 50.0;
}
</script>
<!-- 片元着色器 -->
<script id="fragmentShader" type="x-shader/x-fragment">
void main() {
// 片元,单词gl_FragColor写死的,这句代码的意思是设置片元的颜色
gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0); // 黄色
}
</script>
<script type="module">
/*
webgl的绘图思路
1. 找一台电脑
- 浏览器里内置的webgl渲染引擎,负责渲染webgl图形,只认GLSL ES语言
2. 找一块手绘板
- 程序对象,承载GLSL ES语言,翻译GLSL ES语言和js语言,使两者相互童心
3. 找一只触控笔
- 通过canvas获取的webgl类型的上下文对象,可以向手绘板传递绘图命令,并接收手绘板的状态信息
4. 开始画画
- 通过webgl类型的上下文对象,用js画画
webgl的绘图步骤
1. 在html中建立canvas画布
> <canvas id="canvas"></canvas>
2. 在js中获取画布
> const canvas = document.querySelector("#canvas")
3. 使用canvas获取webgl上下文
> const gl = canvas.getContext("webgl")
4. 在script中建立顶点着色器和片元着色器,用的是glsl es语言
- 顶点着色器:描述顶点的特征,如位置、颜色等。
- gl_Position = vec4(0.0, 0.0, 0.0, 1.0);表示点的位置,默认参数为0, 0, 0, 1
- 第一个参数代表x轴,负数向左,正数向右,如果-1,代表点的中心在画布最左侧,如果1,代表点的中心在画布最右侧
- 第二个参数代表y轴,负数向下,正数向上,如果-1,达标点的中心在画布最下方,如果1,代表点的中心在画布最上方
- 第三个参数代表z轴,表示远近
(后面会讲)
- 片元着色器:进行逐片元处理,如光照。
```html
<!-- 顶点着色器 -->
<script id="vertexShader" type="x-shader/x-vertex">
void main() {
// 点位,单词gl_Position是写死的,专门用于接收点位的,后面要写分号
gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
// 点的尺寸,单词gl_PointSize写死的,值一定是浮点,后面要写分号
gl_PointSize = 100.0;
}
<\/script>
<!-- 片元着色器 -->
<script id="fragmentShader" type="x-shader/x-fragment">
void main() {
// 片元,单词gl_FragColor写死的,
gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0); // 黄色
}
<\/script>
```
5. 在js中获取顶点着色器和片元着色器的文本
- 目的:用于后面初始化着色器
- 方法:获取顶点着色器和片元着色器的script的两个DOM元素,然后获取innerText
- 返回值:顶点着色器和片元着色器的script中的两段viod main函数
```go
// 获取着色器的文本,获取着色器文本的目的是用于后面初始化着色器
// 获取顶点着色器文本
const vsSource = document.querySelector("#vertexShader").innerText;
// 获取片元着色器文本
const fsSource = document.querySelector("#fragmentShader").innerText;
```
6. 初始化着色器
- 初始化着色器的功能:解析着色器文本,整合到程序对象,关联webgl上下文对象,实现两种语言的相互通信
```go
initShaders(gl, vsSource, fsSource);
// 注意:这个initShaders函数是要自己实现的,如下
function initShaders(gl,vsSource,fsSource){
//创建程序对象
const program = gl.createProgram();
//建立着色对象
const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);
const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);
//把顶点着色对象装进程序对象中
gl.attachShader(program, vertexShader);
//把片元着色对象装进程序对象中
gl.attachShader(program, fragmentShader);
//连接webgl上下文对象和程序对象
gl.linkProgram(program);
//启动程序对象
gl.useProgram(program);
//将程序对象挂到上下文对象上
gl.program = program;
return true;
}
function loadShader(gl, type, source) {
//根据着色类型,建立着色器对象
const shader = gl.createShader(type);
//将着色器源文件传入着色器对象中
gl.shaderSource(shader, source);
//编译着色器对象
gl.compileShader(shader);
//返回着色器对象
return shader;
}
```
7. 指定将要用来清空绘图区的颜色
`gl.clearColor(0, 0, 0, 1)`这里设置底色Wie黑色
8. 使用之前设定的颜色,清空绘图区
`gl.clear(gl.COLOR_BUFFER_BIT)`
9. 绘制顶点
- gl.drawArrays(mode, FIRST, COUNT)
- mode代表绘制方式,具体方式如下:
- gl.POINTS 绘制一系列点
- gl.LINE_STRIP 绘制一个线条。即绘制一系列线段,上一点链接下一点
- gl.LINE_LOOP 绘制一个线圈。即绘制一系列线段,上一个点链接下一个点,并且最后一点与第一个点相连
- gl.LINES 绘制一系列单独线段。每两个点作为端点,线段之间不连接
- gl.TRIANGLE_STRIP 绘制一个三角带
- gl.TRIANGLE_FAN 绘制一个三角扇
- gl.TRIANGLES 绘制一系列三角形。每三个点作为定点
- FIRST
- Glint类型,代表指定从哪个点开始绘制
- COUNT
- GLsizei类型,代表指定绘制需要使用到多少个点
`gl.drawArrays(gl.POINTS, 0, 1)`
webgl绘图需要两种着色器:
- 顶点着色器(Vertex shader):描述定点的特征,比如位置。颜色等
- 片元着色器(Fragment shader):进行片元处理,如光照
- webgl中的片元就是像素的意思
举例说明:
两点决定一条直线,两个点就是顶点着色器的顶点,把直线画到画布上后,两个点之间构成的每个像素就是片元
*/
import { initShaders } from "../jsm/Utils.js"
const canvas = document.querySelector("#canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
// 获取着色器的文本,获取着色器文本的目的是用于后面初始化着色器
// 获取顶点着色器文本
const vsSource = document.querySelector("#vertexShader").innerText;
// 获取片元着色器文本
const fsSource = document.querySelector("#fragmentShader").innerText;
console.log(vsSource, fsSource);
// 三维画笔
const gl = canvas.getContext("webgl");
// 初始化着色器
// 初始化着色器的功能:解析着色器文本,整合到程序对象,关联webgl上下文对象,实现两种语言的相互通信
initShaders(gl, vsSource, fsSource);
// 声明底色颜色
gl.clearColor(0, 0, 0, 1);
// 刷底色
gl.clear(gl.COLOR_BUFFER_BIT);
// 绘制顶点
gl.drawArrays(gl.POINTS, 0, 1);// 第一个参数是绘制方式,可以用点、线或面来绘制,第二个参数是从哪里开始画,第三个参数表示画的个数
</script>
</body>
</html>
jsm文件夹下的Utils.js代码
function initShaders(gl,vsSource,fsSource){
//创建程序对象
const program = gl.createProgram();
//建立着色对象
const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);
const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);
//把顶点着色对象装进程序对象中
gl.attachShader(program, vertexShader);
//把片元着色对象装进程序对象中
gl.attachShader(program, fragmentShader);
//连接webgl上下文对象和程序对象
gl.linkProgram(program);
//启动程序对象
gl.useProgram(program);
//将程序对象挂到上下文对象上
gl.program = program;
return true;
}
function loadShader(gl, type, source) {
//根据着色类型,建立着色器对象
const shader = gl.createShader(type);
//将着色器源文件传入着色器对象中
gl.shaderSource(shader, source);
//编译着色器对象
gl.compileShader(shader);
//返回着色器对象
return shader;
}
export {
initShaders
}