本文标题:WebGL第八课:搞一搞 vertex shader(2)
上次课,我们一开始画了一个周期的sin函数,然后画了两个周期的sin函数。
不过,我们是直接改的 vertex shader
代码。
如果我们在网页里,能通过一个滑竿(slider)来拖动改变,然后反应到图形里就好了。
根据上面的需求,我们先在网页里加一个,slider input 控件,
整个代码改动如下:
<!doctype html>
<html>
<head>
<style>
canvas {
border: 1px solid #000000;
}
</style>
</head>
<body>
<input id="slider" type="range" min="0" max="100" value="50" step="1" οnchange="sliderfunc()" />
<canvas id="point" style="width:300px; height:300px">
</canvas>
<script id="vertex_shader" type="myshader">
// Vertex Shader
precision mediump int;
precision mediump float;
attribute vec2 a_PointVertex;
void main() {
gl_Position = vec4(a_PointVertex, 0.0, 1.0);
gl_Position.y = sin(gl_Position.x * 3.14);
gl_PointSize = 3.0;
}
</script>
<script id="fragment_shader" type="myshader">
// Fragment shader
precision mediump int;
precision mediump float;
void main() {
gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
}
</script>
<script type="text/javascript">
var pointCanvas = document.getElementById('point'); // 我们的纸
var gl = pointCanvas.getContext('webgl', { preserveDrawingBuffer: true }); // 我们的笔
var pointCount = 0;
var pointData = [];
for (var idx = -500; idx <= 500; idx++) {
pointCount++;
pointData.push(idx / 500);
pointData.push(0);
}
//
var pointArray = new Float32Array(pointData);
var buffer_id;
buffer_id = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer_id);
gl.bufferData(gl.ARRAY_BUFFER, pointArray, gl.STATIC_DRAW);
//
var vertex_shader_code = document.getElementById('vertex_shader').textContent;
console.log(vertex_shader_code);
var vertex_shader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertex_shader, vertex_shader_code);
gl.compileShader(vertex_shader);
//
var fragment_shader_code = document.getElementById('fragment_shader').textContent;
var fragment_shader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragment_shader, fragment_shader_code);
gl.compileShader(fragment_shader);
//
var program = gl.createProgram();
gl.attachShader(program, vertex_shader);
gl.attachShader(program, fragment_shader);
gl.linkProgram(program);
gl.useProgram(program);
//
var a_PointVertex = gl.getAttribLocation(program, 'a_PointVertex');
gl.vertexAttribPointer(a_PointVertex, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(a_PointVertex);
//
// gl.drawArrays(gl.POINTS, 0, pointCount);
</script>
<script>
var sliderDom = document.getElementById("slider");
function sliderfunc() {
}
sliderDom.addEventListener("change", sliderfunc);
</script>
</script>
</body>
</html>
我们在前面,加了一个 slider input 控件,在最后将这个控件绑定了一个事件,也就是
这个控件的值改变的时候,我们可以在 sliderfunc
函数中做一些事情。
var sliderDom = document.getElementById("slider");
function sliderfunc() {
// 应该在这里来改变图形的绘制
}
sliderDom.addEventListener("change", sliderfunc);
重点新概念:uniform 变量
uniform
变量是可以写在vertex shader
和fragment shader
中的变量- 随时都可以通过
gl
的api
,改变uniform
变量的值
我们改动我们的 vertex shader
, 如下:
<script id="vertex_shader" type="myshader">
// Vertex Shader
precision mediump int;
precision mediump float;
uniform float u_x_offset;
attribute vec2 a_PointVertex;
void main() {
gl_Position = vec4(a_PointVertex, 0.0, 1.0);
gl_Position.y = sin(gl_Position.x * 3.14 * u_x_offset);
gl_PointSize = 3.0;
}
</script>
- 注意,声明了一个
float
类型的uniform
变量u_x_offset
; - 注意,sin 的传入参数,变成了
gl_Position.x * 3.14 * u_x_offset
- 也就是说,我们可以把
u_x_offset
当做一个调节因子.
光这些还没用,我们要在 sliderfunc 里写一些代码,来从外面改变 vertex shader
中的 u_x_offset
变量。
最后的代码改动如下:
<script>
var u_x_offset_loc = gl.getUniformLocation(program, "u_x_offset");
var sliderDom = document.getElementById("slider");
function sliderfunc() {
gl.uniform1f(u_x_offset_loc, parseFloat(sliderDom.value) / 10);
gl.clearColor(0, 0, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.POINTS, 0, pointCount);
}
sliderDom.addEventListener("change", sliderfunc);
</script>
详解:
- gl.getUniformLocation , 用于得到
vertex shader
中的 uniform 变量的位置 - gl.uniform1f 改变
vertex shader
中的 uniform变量的值 - gl.clear(gl.COLOR_BUFFER_BIT) 清空整个图像 ,否则会重复绘制,越来越乱
- gl.drawArrays(gl.POINTS, 0, pointCount) 重新绘制
效果如下:
随着我们拖动滑竿,不同周期的sin
图像会被绘制到页面上。
正文结束,下面是答疑
小鸭鸭说:既然可以在 js 代码改变 uniform 变量的值,那么我搞个定时器,是不是就是动画了?
- 答:完全正确✔️!!!!!下课~
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!