);
gl_Position、gl_PointSize、gl_FragColor 是 GLSL 的内置属性
gl_Position:
顶点的裁剪坐标系坐标,包含 X, Y, Z,W 四个坐标分量
顶点着色器接收到这个坐标之后,对它进行透视除法,即将各个分量同时除以 W,转换成 NDC 坐标
NDC 坐标每个分量的取值范围都在【-1, 1】之间,GPU 获取这个属性值作为顶点的最终位置进行绘制
gl_PointSize:
绘制到屏幕的点的大小,只有在绘制图元是点的时候才会生效
gl_FragColor:
片元(像素)颜色,包含 R, G, B, A 四个颜色分量,且每个分量的取值范围在【0,1】之间,GPU 获取这个值作为像素的最终颜色进行着色
常规颜色的【0,255】取值范围,转换公式为: (R值/255,G值/255,B值/255,A值/1)
vec4:
包含四个浮点元素的容器类型,vec 是 vector(向量)。
vec4 代表包含 4 个浮点数的向量。 延伸:vec2包含2个浮点数的容器
(1)在页面上画一个点
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<meta content="text/html; charset=utf-8" http-equiv="Content-Type"/>
<title>WebGL</title>
</head>
<body style="background: #000">
<canvas id="canvas"></canvas>
</body>
<!-- 顶点着色器源码 -->
<script type="shader-source" id="vertexShader">
void main(){
//声明顶点位置
gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
//声明要绘制的点的大小。
gl_PointSize = 5.0;
</script>
<!-- 片元着色器源码 -->
<script type="shader-source" id="fragmentShader">
void main(){
//设置像素颜色为红色
gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);
</script>
<script type="text/javascript">
var canvas = document.querySelector('#canvas');
var gl = canvas.getContext('webgl') || canvas.getContext("experimental-webgl");
// 获取顶点着色器源码
var vertexShaderSource = document.querySelector('#vertexShader').innerHTML;
// 创建顶点着色器对象
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
// 将源码分配给顶点着色器对象
gl.shaderSource(vertexShader, vertexShaderSource);
// 编译顶点着色器程序
gl.compileShader(vertexShader);
// 获取片元着色器源码
var fragmentShaderSource = document.querySelector('#fragmentShader').innerHTML;
// 创建片元着色器程序
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
// 将源码分配给片元着色器对象
gl.shaderSource(fragmentShader, fragmentShaderSource);
// 编译片元着色器
gl.compileShader(fragmentShader);
//创建着色器程序
var program = 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);
</script>
</html>
gl.drawArrays(mode, first, count);
mode,代表图元类型。
first,代表从第几个点开始绘制即顶点的起始位置
count,代表绘制的点的数量。
(2)在鼠标点击过的位置绘制一个随机颜色的点
增加为着色器中变量进行赋值部分
绘制过程:
声明一个数组变量 points,存储点击位置的坐标。
绑定 canvas 的点击事件。
触发点击操作时,把点击坐标添加到数组 points 中。
遍历每个点执行 drawArrays(gl.Points, 0, 1) 绘制操作
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<meta content="text/html; charset=utf-8" http-equiv="Content-Type"/>
<title>WebGL</title>
</head>
<body style="background: #000">
<canvas id="canvas"></canvas>
</body>
<!-- 顶点着色器源码 -->
<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);
//end 将屏幕坐标系转化为裁剪坐标(裁剪坐标系)
//声明要绘制的点的大小。
gl_PointSize = 5.0;
</script>
<!-- 片元着色器源码 -->
<script type="shader-source" id="fragmentShader">
//设置浮点数精度为中等精度
precision mediump float;
//接收 JavaScript 传过来的颜色值(RGBA)。
uniform vec4 u_Color;
void main(){
//设置像素颜色为红色
vec4 color = u_Color / vec4(255, 255, 255, 1);
gl_FragColor = color;
</script>
<script type="text/javascript" src="helper.js"></script>
<script type="text/javascript">
var canvas = getCanvas('#canvas');
resizeCanvas(canvas);
var gl = getContext(canvas);
//创建顶点着色器
var vertexShader = createShaderFromScript(gl, gl.VERTEX_SHADER,'vertexShader');
//创建片元着色器
var fragmentShader = createShaderFromScript(gl, gl.FRAGMENT_SHADER,'fragmentShader');
//创建着色器程序
var program = createSimpleProgram(gl ,vertexShader, fragmentShader);
// 使用刚创建好的着色器程序。
gl.useProgram(program);
//找到顶点着色器中的变量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 = [];
canvas.addEventListener('click', e => {
var x = e.pageX;
var y = e.pageY;
var color = randomColor();
points.push({ x: x, y: y, color: color })
render(gl);
//绘制函数
function render(gl){
//清除屏幕
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);
//向顶点着色器传递坐标信息。
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);
//绘制
render(gl);
</script>
</html>
helper.js
var random = Math.random;
function randomColor() {
return {
r: random() * 255,
g: random() * 255,
b: random() * 255,
a: random() * 1
function $$(str) {
if (!str) return null;
if (str.startsWith('#')) {
return document.querySelector(str);
let result = document.querySelectorAll(str);
if (result.length == 1) {
return result[0];
return result;
function getCanvas(id) {
return $$(id);
function resizeCanvas(canvas, width, height) {
if (canvas.width !== width) {
canvas.width = width ? width : window.innerWidth;
if (canvas.height !== height) {
canvas.height = height ? height : window.innerHeight;
function getContext(canvas) {
return canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
function createSimpleProgram(gl, vertexShader, fragmentShader) {
if (!vertexShader || !fragmentShader) {
console.warn('着色器不能为空');
return;
let program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
let success = gl.getProgramParameter(program, gl.LINK_STATUS);
if (success) {
return program;
console.error(gl.getProgramInfoLog(program));
gl.deleteProgram(program);
function createShader(gl, type, source) {
let shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
//检测是否编译正常。
let success = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
if (success) {
return shader;
console.error(gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
function createShaderFromScript(gl, type, scriptId) {
let sourceScript = $$('#' + scriptId);
if (!sourceScript) {
return null;
return createShader(gl, type, sourceScript.innerHTML);
View Code
向着色器中传递数据
getAttribLocation:找到着色器中的 attribute 变量地址
getUniformLocation:找到着色器中的 uniform 变量地址
vertexAttrib2f:给 attribute 变量传递两个浮点数
uniform4f:给uniform变量传递四个浮点数
WebGL学习笔记二