webgl基本图形绘制上下文,步骤,涉及的方法,含义,实现效果等
实现webgl程序时,首先要创立允许webgl运行的环境,这个环境一般被称为webgl绘图上下文,是基于canvas标签创立的
// 获取webgl上下文
let canvas = document.getElementById('canvas');
const gl = canvas.getContext('webgl');
gl.clearColor(r,g,b,a):设置背景色
- r: 红色分量[0.0, 1.0]
- g: 绿色分量[0.0, 1.0]
- b: 蓝色分量[0.0, 1.0]
- a: 透明度[0.0, 1.0]
gl.clearColor(r,g,b,a)中的参数取值范围都在0.0~1.0之间,若超出的话不会报错,会自动设置为边界值。背景色一旦设置,除非再次调用该方法,否则不会改变
gl.clear(buffer):将指定的缓冲区设置为预设的值
- buffer:所要清空的缓存类型,枚举如下
– gl.COLOR_BUFFER_BIT: 将颜色缓存清空,采用之前定义的背景色(gl.clearColor())填充
– gl.DESPTH_BUFFER_BIT: 清除深度缓存,深度用来表示物体在三维世界的前后顺序,体现在遮挡效果上
– gl.STENCIL_BUFFER_BIT: 模版缓存
综上,用一个最简单的示例总结以上方法,屏幕上将会出现由webgl渲染的,被黄色填充的区域
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>webgltitle>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<style>
body {
margin: 0;
padding: 0;
}
canvas {
width: 500px;
height: 500px;
}
style>
head>
<body>
<canvas id="canvas">canvas>
<script>
/** @type {HTMLCanvasElement} */
// 获取webgl上下文
let canvas = document.getElementById('canvas');
const gl = canvas.getContext('webgl');
if (!gl) {
throw new Error('WebGL not supported');
}
// 设置背景色
gl.clearColor(1.0, 1.0, 0.0, 1.0)
// 清空缓冲区
gl.clear(gl.COLOR_BUFFER_BIT)
script>
body>
html>
在之前的文章对着色器的使用过程有过比较详细的介绍,这里会更系统介绍着色器使用步骤以及涉及的方法
// 创建顶点着色器
let vertexShader = gl.createShader(gl.VERTEX_SHADER)
// 创建顶点着色器的代码GLSL
gl.shaderSource(vertexShader, `
void main() {
gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
gl_PointSize = 20.0;
}
`)
// 编译顶点着色器
gl.compileShader(vertexShader)
if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
console.error(gl.getShaderInfoLog(vertexShader));
throw new Error('could not compile vertexShader');
}
// 创建片元着色器
let fragmentShader = gl.createShader(gl.FRAGMENT_SHADER)
// 创建片元着色器的代码GLSL
gl.shaderSource(fragmentShader, `
void main(){
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`)
// 编译片元着色器
gl.compileShader(fragmentShader)
if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
console.error(gl.getShaderInfoLog(fragmentShader));
throw new Error('could not compile fragmentShader');
}
// 创建程序
let program = gl.createProgram();
console.log(program)
// 程序关联顶点着色器和片元着色器
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
// 链接程序
gl.linkProgram(program);
// 使用程序进行渲染
gl.useProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
console.log(gl.getProgramInfoLog(program));
throw new Error('could not link shaders');
}
着色器的使用流程固定,可以将初始着色器的代码封装使用,会更加轻便
function initShader(gl, vertex, fragment) {
// 创建顶点着色器
let vertexShader = gl.createShader(gl.VERTEX_SHADER)
// 创建顶点着色器的代码GLSL
gl.shaderSource(vertexShader, vertex)
// 编译顶点着色器
gl.compileShader(vertexShader)
if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
console.error(gl.getShaderInfoLog(vertexShader));
throw new Error('could not compile vertexShader');
}
// 创建片元着色器
let fragmentShader = gl.createShader(gl.FRAGMENT_SHADER)
// 创建片元着色器的代码GLSL
gl.shaderSource(fragmentShader, fragment)
// 编译片元着色器
gl.compileShader(fragmentShader)
if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
console.error(gl.getShaderInfoLog(fragmentShader));
throw new Error('could not compile fragmentShader');
}
// 创建程序
let program = gl.createProgram();
console.log(program)
// 程序关联顶点着色器和片元着色器
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
// 链接程序
gl.linkProgram(program);
// 使用程序进行渲染
gl.useProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
console.log(gl.getProgramInfoLog(program));
throw new Error('could not link shaders');
}
return program
}
gl.drawArrays(mode, first, count): 执行顶点着色器,按照mode模式绘制图形
mode:绘制的方式,常见的类型包括以下几种,详细的可以参照这里
– gl.Points: 绘制点,count>0
– gl.Lines: 绘制线,count>1
– gl.TRIANGLES: 绘制三角形,count>2first:从第几个点开始绘制
count:使用几个点进行绘制
当函数gl.drawArrays()执行过程中,顶点着色器供执行了count次,每当执行完顶点着色器,片元着色器都会立即出发执行,如此往复。
`
结合上述示例,我们绘制一个点在canvas中央
let canvas = document.getElementById('canvas');
// 获取webgl绘图上下文
const gl = canvas.getContext('webgl');
if (!gl) {
throw new Error('WebGL not supported');
}
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
gl.viewport(0, 0, canvas.width, canvas.height)
// 设置背景色
gl.clearColor(1.0, 1.0, 0.0, 1.0)
// 清空缓冲区
gl.clear(gl.COLOR_BUFFER_BIT)
const vertex = `
void main() {
gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
gl_PointSize = 20.0;
}
`
const fragment = `
void main(){
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`
// 使用shader
initShader(gl, vertex, fragment)
// 绘制三角形
gl.drawArrays(gl.POINTS, 0, 1);
示例:
当我设置canvas画布未铺满全屏时,使用顶点着色器会出现坐标偏移的情况:
在获取webgl上下文时,可先通过gl.viewport()设置窗口大小
canvas.width = window.innerWidth // 500;
canvas.height = window.innerHeight // 500;
gl.viewport(0, 0, canvas.width, canvas.height)
我们在设置顶点着色器位置时,其值为一个四维向量
void main() {
gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
gl_PointSize = 20.0;
}
gl_Position实际上是一个四维向量,对应的是齐次坐标,齐次坐标的前两项对应浏览器的屏幕坐标,其中心位于(0.0,0.0)处,前两项坐标均处于[-1.0,1.0]之间,如下图:
虽然采用上述方法实现了绘制点,但是存在一个明显的问题:绘制的坐标全是静态写死在顶点着色器程序中,无法在javascript中灵活传递坐标。为此可以使用attribute和uniform变量灵活传递变量。
webgl基本环境搭建
着色器绘制图形
绘制图形
不足
绘制的坐标全是静态写死在顶点着色器程序中,无法在javascript中灵活传递坐标。为此可以使用attribute和uniform变量灵活传递变量