1. demo效果
如上图,绘制出了三个红色的小圆点
2. 实现要点
2.1 绘制原理
我们已经知道在绘制图形时有一个光栅化的过程,在光栅化的过程中可以在片元着色器中通过内置变量 gl_FragCoord 来访问片元的坐标,实际上片元着色器还提供了另一个内置变量来获取当前片元在所属点内的坐标,它就是 gl_PointCoord ,归纳一下这两个变量
片元着色器内置变量(输入)
变量类型名称 | 描述 |
---|---|
vec4 gl_FragCoord | 片元的窗口坐标 |
vec4 gl_PointCoord | 当前片元在所属点内的坐标(从0.0到1.0) |
上图用来说明通过内置变量 gl_PointCoord 绘制圆点的原理,上图中的所有小方块表示当前绘制点所有片元,为了将这个点削成圆形,从图上得知,该点的正中心的坐标为(0.5,0.5),我们只要削掉以这点为圆心,半径大于0.5的片元,就可以绘制成成一个圆点
2.1 绘制实现
- 计算片元距离所属点中心的距离
首先定义圆的中心点vec2(0.5, 0.5),与内置变量gl_PointCoord计算距离,通过内置函数 distance() 实现
' float d = distance(gl_PointCoord, vec2(0.5, 0.5));\n' + //计算像素距离中心点的距离
- 根据距离大小(是否大于0.5)判断是否舍弃像素
上一步中已经计算出了片元片元到圆心的距离,这里我们只需要判断这个距离是否大于0.5,如果大于0.5则使用 discard 语句舍弃当前片元
' if(d < 0.5) {\n' + //距离大于0.5放弃片元,小于0.5保留片元
' gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' +
' } else { discard; }\n' +
3. demo代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<!--通过canvas标签创建一个800px*800px大小的画布-->
<canvas id="webgl" width="800" height="800"></canvas>
<script type="text/javascript" src="./lib/cuon-matrix.js"></script>
<script>
//顶点着色器
var VSHADER_SOURCE = '' +
'attribute vec4 a_Position;\n' + //声明attribute变量a_Position,用来存放顶点位置信息
'void main(){\n' +
' gl_Position = a_Position;\n' + //将顶点坐标赋值给顶点着色器内置变量gl_Position
' gl_PointSize = 30.0;\n' + //设置顶点大小
'}\n'
//片元着色器
var FSHADER_SOURCE = '' +
'#ifdef GL_ES\n' +
' precision mediump float;\n' + // 设置精度
'#endif\n' +
'varying vec4 v_Color;\n' + //声明varying变量v_Color,用来接收顶点着色器传送的片元颜色信息
'void main(){\n' +
' float d = distance(gl_PointCoord, vec2(0.5, 0.5));\n' + //计算像素距离中心点的距离
' if(d < 0.5) {\n' + //距离大于0.5放弃片元,小于0.5保留片元
' gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' +
' } else { discard; }\n' +
'}\n'
//初始化着色器函数
function initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE) {
//创建顶点着色器对象
var vertexShader = loadShader(gl, gl.VERTEX_SHADER, VSHADER_SOURCE)
//创建片元着色器对象
var fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, FSHADER_SOURCE)
if (!vertexShader || !fragmentShader) {
return null
}
//创建程序对象program
var program = gl.createProgram()
if (!gl.createProgram()) {
return null
}
//分配顶点着色器和片元着色器到program
gl.attachShader(program, vertexShader)
gl.attachShader(program, fragmentShader)
//链接program
gl.linkProgram(program)
//检查程序对象是否连接成功
var linked = gl.getProgramParameter(program, gl.LINK_STATUS)
if (!linked) {
var error = gl.getProgramInfoLog(program)
console.log('程序对象连接失败: ' + error)
gl.deleteProgram(program)
gl.deleteShader(fragmentShader)
gl.deleteShader(vertexShader)
return null
}
//使用program
gl.useProgram(program)
gl.program = program
//返回程序program对象
return program
}
function loadShader(gl, type, source) {
// 创建顶点着色器对象
var shader = gl.createShader(type)
if (shader == null) {
console.log('创建着色器失败')
return null
}
// 引入着色器源代码
gl.shaderSource(shader, source)
// 编译着色器
gl.compileShader(shader)
// 检查顶是否编译成功
var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS)
if (!compiled) {
var error = gl.getShaderInfoLog(shader)
console.log('编译着色器失败: ' + error)
gl.deleteShader(shader)
return null
}
return shader
}
function init() {
//通过getElementById()方法获取canvas画布
var canvas = document.getElementById('webgl')
//通过方法getContext()获取WebGL上下文
var gl = canvas.getContext('webgl')
//初始化着色器
if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
console.log('初始化着色器失败')
return
}
// 设置canvas的背景色
gl.clearColor(0.0, 0.0, 0.0, 1.0)
//清空颜色缓冲区
gl.clear(gl.COLOR_BUFFER_BIT)
//初始化顶点坐标和顶点颜色
var n = initVertexBuffers(gl)
//绘制点
gl.drawArrays(gl.POINTS, 0, n)
}
//初始化顶点坐标和顶点颜色
function initVertexBuffers(gl) {
//顶点
var vertices = new Float32Array([
0, 0.5, -0.5, -0.5, 0.5, -0.5
])
var n = 3
//创建缓冲区对象
var buffer = gl.createBuffer()
//将顶点坐标和顶点颜色信息写入缓冲区对象
gl.bindBuffer(gl.ARRAY_BUFFER, buffer)
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW)
//获取顶点着色器attribute变量a_Position存储地址, 分配缓存并开启
var a_Position = gl.getAttribLocation(gl.program, 'a_Position')
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0)
gl.enableVertexAttribArray(a_Position)
return n
}
init()
</script>
</body>
</html>