WebGL 基础:一个点 & 往着色器传递数据
源码
定点着色器
html
<script type="shader-source" id="vertexShader">
void main(){
// 声明定点位置
gl_Position = vec4(0.0,0.0,0.0,1.0);
// 声明待绘制的点的大小
gl_PointSize = 10.0;
}
</script>
片元着色器
html
<script type="shader-source" id="fragmentShader">
void main(){
// 设置像素颜色位红色
gl_FragColor = vec4(1.0,0.0,0.0,1.0);
}
</script>
TypeScript
js
// 获取canvas元素
const canvas: HTMLCanvasElement = document.querySelector('#canvas')
// 获取 WebGL 绘图环境
const gl: WebGLRenderingContext = canvas.getContext('webgl') || canvas.getContext('experimental-webgl')
/**
* 创建定点着色器对象
* 绘制点位位置
*/
// 获取定点着色器源码
const vertexShaderSource: string = document.querySelector('#vertexShader').innerHTML
// 创建定点着色器对象
const vertexShader: WebGLShader = gl.createShader(gl.VERTEX_SHADER)
// 将源码分配给定点着色器对象
gl.shaderSource(vertexShader, vertexShaderSource)
// 编译顶点着色器程序
gl.compileShader(vertexShader)
/**
* 创建片元着色器对象
* 像素着色
*/
// 获取片元着色器源码
const fragmentShaderSource: string = document.querySelector('#fragmentShader').innerHTML
// 创建片元着色器对象
const fragmentShader: WebGLShader = gl.createShader(gl.FRAGMENT_SHADER)
// 将源码分配给片元着色器对象
gl.shaderSource(fragmentShader, fragmentShaderSource)
// 片元着色器编译
gl.compileShader(fragmentShader)
/**
* 创建着色器程序
*/
// 创建着色器程序
const program: WebGLProgram = gl.createProgram()
// 将顶点着色器挂载在着色器程序上
gl.attachShader(program, vertexShader)
// 将片元着色器挂载在着色器程序锁
gl.attachShader(program, fragmentShader)
// 链接着色器程序
gl.linkProgram(program)
// 使用刚创建好的着色器程序
gl.useProgram(program)
/**
* 开始绘制
*/
// 设置清空画布颜色为黑色
gl.clearColor(0.0, 0.0, 0.0, 1.0)
// 用上一步设置的清空画布颜色清空画布。
gl.clear(gl.COLOR_BUFFER_BIT)
// 绘制点
gl.drawArrays(gl.POINTS, 0, 1)
学习记录
HTMLCanvasElement.getContext('webgl')
获取 WebGL 绘图环境WebGLRenderingContext
(简写gl
)- 创建着色器对象
gl.createShader(type)
创建着色器对象(WebGLShader
)- type:
gl.VERTEX_SHADER
创建定点着色器 - type:
gl.FRAGMENT_SHADER
创建片元着色器
- type:
gl.shaderSource(WebGLShader,source)
设置着色器对象的 GLSL 程序代码gl.compileShader(WebGLShader)
编译一个 GLSL 着色器,使其成为二进制数据
- 创建着色器程序
gl.createProgram()
创建和初始化着色器程序(WebGLProgram
)。它由两个WebGLShader
(webgl 着色器)组成,分别为顶点着色器和片元着色器。gl.attachShader(WebGLProgram,WebGLShader)
往着色器程序中添加片段/定点着色器gl.linkProgram(WebGLProgram)
链接着色器程序,从而完成为程序的片元和顶点着色器准备 GPU 代码的过程。gl.useProgram(WebGLProgram)
将定义好的着色器程序添加到当前的渲染状态中
- 绘制
gl.clearColor(red, green, blue, alpha)
设置清空颜色缓冲时的颜色值gl.clear(mask)
使用预设值来清空缓冲(画布)。- mask:
gl.COLOR_BUFFER_BIT
颜色缓冲区 - mask:
gl.DEPTH_BUFFER_BIT
深度缓冲区 - mask:
gl.STENCIL_BUFFER_BIT
模板缓冲区
- mask:
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:指定从哪个点开始绘制
- count:指定绘制需要使用到多少个点
- mode:绘制图元的方式。(图元类型?)
通过 javaScript 往着色器传递数据
html
<script type="shader-source" id="vertexShader">
// 设置浮点数精度为中等精度
precision mediump float;
// 接收点在 canvas 坐标系上的坐标(x,y)
attribute vec2 a_Position;
// 接收 canvas 的宽高尺寸;
attribute vec2 a_Screen_Size;
void main(){
// 将屏幕坐标系转化为裁剪坐标(裁剪坐标系)
vec2 position = (a_Position / a_Screen_Size) * 2.0 -1.0;
position = position * vec2(1.0 , -1.0);
gl_Position = vec4(position,0,1);
// 声明待绘制的点的大小
gl_PointSize = 10.0;
}
</script>
先定义两个attribute
变量:a_Position,a_Screen_Size。
vec2 position = (a_Position / a_Screen_Size) * 2.0 -1.0;
position = position * vec2(1.0 , -1.0);
这个操作将 canvas 坐标转为 NDC 坐标:
a_Position / a_Screen_Size
将(x,y) 转化到【0, 1】区间- 再将 【0, 1】之间的值乘以 2 转化到 【0, 2】区间
- 之后再减去 1 ,转化到 【-1, 1】之间的值
- 由于 webgl 坐标系的 y 轴正方向和 canvas y 轴正方向相反,所以 position * vec2(1.0, -1.0) 将 y 轴方向转换
片元着色器
html
<script type="shader-source" 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>
定义一个全局变量(uniform
修饰的变量)
学习记录
gl.getAttribLocation(WebGLProgram,name)
找到着色器中的 attribute 变量地址。gl.getUniformLocation(WebGLProgram,name)
找到着色器中的 uniform 变量地址。gl.vertexAttrib2f()
给 attribute 变量传递两个浮点数。gl.uniform4f()
给 uniform 变量传递四个浮点数。
遇到的问题
canvas 宽高与实际不符
每张画布有两种尺寸。
- 其绘图缓冲区的大小。这是画布中的像素数。
- 第二个大小是画布显示的大小。CSS 决定画布显示的大小。
通过两种方式设置画布的绘图缓冲区的大小:
html
<canvas id="c" width="400" height="300"></canvas>
js
const canvas = document.querySelector('#c')
canvas.width = 400
canvas.height = 300
至于设置一个画布的显示大小,如果你没有任何 CSS 影响画布的显示大小,显示大小将是相同的大小作为其绘图缓冲区。因此在上面的两个例子中,画布的绘图缓冲区是 400x300,它的显示大小也是 400x300。