webgl入门也挺麻烦的,需要了解JavaScript脚本编辑语言,需要会Html,需要懂点Opengl,还要有懂些计算机图形学的知识。做得精还需要会编写shader。
当然,这些都可以慢慢学,而且webgl看似难入门,其实把它各个部分割裂开,也挺简单的。当然,JavaScript和Html知识是必备的技能。
编辑器还是选择强大的visual studio。然后创建TypeScript的Html项目。这里创建这个项目就可以直接在chrome上查看结果,很方便,不用搞什么服务器什么的。
好,来看第一个部分,创建几何图形。
首先在index.html里写入主体代码。这里写了两个着色器,顶点着色器和片面着色器,当然也可以放在其他地方。然后,确定画布大小。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>HTML App</title>
<script id="shader-vs">
attribute vec3 v3Position;
void main(void)
{
gl_Position = vec4(v3Position, 1.0);
}
</script>
<script id="shader-fs">
precision mediump float;
void main(void)
{
gl_FragColor = vec4(0.0, 1.0, 1.0, 1.0);
}
</script>
<script type="text/javascript" src="Common/gl-matrix.js"></script>
<script type="text/javascript" src="Common/initShaders.js"></script>
<script type="text/javascript" src="Common/webgl_utils.js"></script>
<script type="text/javascript" src="Test/test001.js"></script>
</head>
<body>
<canvas id="gl-canvas" width="512" height="512"></canvas>
<script>
function Init()
{
var canvas = document.getElementById('gl-canvas');
webgl = canvas.getContext("webgl");
webgl.viewport(0, 0, canvas.clientWidth, canvas.clientHeight);
InitGeometry(webgl);
}
Init()
</script>
</body>
</html>
接下来创建着色器,并应用着色器到程序中,这部分可以不用细究,后面再学。这部分是initshader.js.
function initShaderToWebgl(webgl, v3PositionIndex)
{
vertexShaderObject = webgl.createShader(webgl.VERTEX_SHADER);
fragmentShaderObject = webgl.createShader(webgl.FRAGMENT_SHADER);
webgl.shaderSource(vertexShaderObject, getShaderSource("shader-vs"));
webgl.shaderSource(fragmentShaderObject, getShaderSource("shader-fs"));
webgl.compileShader(vertexShaderObject);
webgl.compileShader(fragmentShaderObject);
if (!webgl.getShaderParameter(vertexShaderObject, webgl.COMPILE_STATUS)) {
alert("error:vertexShaderObject");
return;
}
if (!webgl.getShaderParameter(fragmentShaderObject, webgl.COMPILE_STATUS)) {
alert("error:fragmentShaderObject");
return;
}
programObject = webgl.createProgram();
webgl.attachShader(programObject, vertexShaderObject);
webgl.attachShader(programObject, fragmentShaderObject);
webgl.bindAttribLocation(programObject, v3PositionIndex, "v3Position");
webgl.linkProgram(programObject);
if (!webgl.getProgramParameter(programObject, webgl.LINK_STATUS)) {
alert("error:programObject");
return;
}
webgl.useProgram(programObject);
}
//
// Initialize a shader program, so WebGL knows how to draw our data
//
function initShaderProgram(gl, vsSource, fsSource) {
const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);
const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);
// Create the shader program
const shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
// If creating the shader program failed, alert
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
alert('Unable to initialize the shader program: ' + gl.getProgramInfoLog(shaderProgram));
return null;
}
return shaderProgram;
}
//
// creates a shader of the given type, uploads the source and
// compiles it.
//
function loadShader(gl, type, source) {
const shader = gl.createShader(type);
// Send the source to the shader object
gl.shaderSource(shader, source);
// Compile the shader program
gl.compileShader(shader);
// See if it compiled successfully
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
return null;
}
return shader;
}
function getShaderSource(scriptID) {
var shaderScript = document.getElementById(scriptID);
if (shaderScript == null) return "";
var sourceCode = "";
var child = shaderScript.firstChild;
while (child) {
if (child.nodeType == child.TEXT_NODE) sourceCode += child.textContent;
child = child.nextSibling;
}
return sourceCode;
}
最后就是他的几何部分,卸载test001.js中。
var webgl = null;
var vertexShaderObject = null;
var fragmentShaderObject = null;
var programObject = null;
var triangleBuffer = null;
var v3PositionIndex = 0;
function InitGeometry(webgl) {
var jsArrayData =
[
0.0, 1.0, 0.0,//上顶点
-1.0, -1.0, 0.0,//左顶点
1.0, -1.0, 0.0
];//右顶点
render(webgl, v3PositionIndex, jsArrayData);
//开启着色器中的顶点属性
webgl.enableVertexAttribArray(v3PositionIndex);
//描述顶点数组中的数据形式
webgl.vertexAttribPointer(v3PositionIndex, 3, webgl.FLOAT, false, 0, 0);
//画三角形
webgl.drawArrays(webgl.TRIANGLES, 0, 3);
}
function render(webgl, v3PositionIndex, jsArrayData)
{
//初始化定义shader
initShaderToWebgl(webgl, v3PositionIndex);
initBuffer(webgl, jsArrayData);
webgl.clearColor(0.0, 0.0, 0.0, 1.0);
webgl.clear(webgl.COLOR_BUFFER_BIT);
}
//创建缓冲区并绑定顶点数据
function initBuffer(webgl, jsArrayData)
{
triangleBuffer = webgl.createBuffer();
webgl.bindBuffer(webgl.ARRAY_BUFFER, triangleBuffer);
webgl.bufferData(webgl.ARRAY_BUFFER, new Float32Array(jsArrayData), webgl.STATIC_DRAW);
}
webgl_utils.js用来写各种小工具。gl-matrix.js用来存放矩阵计算的方法。暂时用不上。
最后结果:
现在来画几条线,这个就简单了,直接在上面的InitGeometry()方法里修改,比如我要画四条直线,那就是8个点。只需要在jsArrayData里添加点即可,另外,需要把drawArray里的3改为8,另外用上webgl.LINES的模式。更多样式请参考:https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/drawArrays
各个实例请参考:http://www.cocoachina.com/ios/20170710/19798.html
function InitGeometry(webgl) {
var jsArrayData =
[
-0.5, -0.5, 0.0,
-0.5, 0.5, 0.0,
-0.5, 0.5, 0.0,
0.5, 0.5, 0.0,
0.5, 0.5, 0.0,
0.5, -0.5, 0.0,
0.5, -0.5, 0.0,
-0.5, -0.5, 0.0,
];//右顶点
render(webgl, v3PositionIndex, jsArrayData);
//开启着色器中的顶点属性
webgl.enableVertexAttribArray(v3PositionIndex);
//描述顶点数组中的数据形式
webgl.vertexAttribPointer(v3PositionIndex, 3, webgl.FLOAT, false, 0, 0);
//画直线
webgl.drawArrays(webgl.LINES, 0, 8);
}
讲得比较简单,最好结合书和视频教程来看。但是把各个部分分隔开,还是很好理解的。