我尝试学习WebGL。我读了这篇教程https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Tutorial/Using_shaders_to_apply_color_in_WebGL 但为了更好地学习,我编写自己的代码,而不是从教程中复制过去的代码。我在这里上传了我的代码https://github.com/Azaravicius/GLCanvas 文件glUtils.js和sylvester.js来自教程作为依赖项。 文件glcanvas.js和run.js都有我的代码。
代码应该像教程一样用四种颜色绘制正方形,但我在Firefox中使用红色正方形,在Chromium中使用黑色正方形。
<script id="shader-vs" type="x-shader/x-vertex">
attribute vec3 aVertexPosition;
attribute vec4 aVertexColor;
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
varying lowp vec4 vColor;
void main(void) {
gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
vColor = aVertexColor;
}
</script>
我认为vertext着色器不能获得aVertexColor的值,但是这里没有控制台中的错误。为了测试我已经将代码更改为vColor = vec4(aVertexPosition,1.0);它起作用了。因此片段着色器从片段着色器获取数据。 我不知道如何在代码中找到bug。
class GLCanvas {
constructor(canvasID, clear = [1.0, 1.0, 1.0, 1.0], contextAttributes = {}) {
// WebGLRenderingContext
this.gl = null;
// Object to hold all created programs. {programName:program}
this.programs = {};
// All variables of current program {variableName: variableLoction}
this.variables = {};
// Buffers in use
this.buffers = {};
// HTML5 canvas element
this.canvas = document.getElementById(canvasID);
if (!this.canvas) {
console.log("ERROR: Can't find canvas with id", canvasID);
return;
}
// contextAttributes = {alpha: true, depth: true, stencil: false, antialias: true,
// premultipliedAlpha: true, preserveDrawingBuffer: false,
// failIfMajorPerformanceCaveat: false }
this.gl = this.canvas.getContext('webgl', contextAttributes) ||
this.canvas.getContext('experimental-webgl', contextAttributes);
if (!this.gl) {
console.log("ERROR: Unable to get WebGL context. Your browser may not support it.");
return;
}
this.gl.clearColor(clear[0], clear[1], clear[2], clear[3]);
this.gl.clear(this.gl.COLOR_BUFFER_BIT);
}
initProgram(vShader, fShader, program) {
var fragmentShader, vertexShader;
vertexShader = this.initShader(vShader, this.gl.VERTEX_SHADER);
if (!vertexShader) {
console.log('Vertex shader not loaded.');
return;
}
fragmentShader = this.initShader(fShader, this.gl.FRAGMENT_SHADER);
if (!fragmentShader) {
console.log('Fragment shader not loaded.');
return;
}
this.programs[program] = this.gl.createProgram();
this.gl.attachShader(this.programs[program], vertexShader);
this.gl.attachShader(this.programs[program], fragmentShader);
this.gl.linkProgram(this.programs[program]);
if (!this.gl.getProgramParameter(this.programs[program], this.gl.LINK_STATUS)) {
console.log('Unable to initialize the shader program: ' + this.gl.getProgramInfoLog(this.programs[program]));
this.gl.deleteProgram(this.programs[program]);
delete this.programs[program];
return;
}
}
initShader(shaderScript, type) {
var shader = this.gl.createShader(type);
this.gl.shaderSource(shader, shaderScript);
this.gl.compileShader(shader);
if (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)) {
console.log('An error occurred compiling the shaders: ' + this.gl.getShaderInfoLog(shader));
this.gl.deleteShader(shader);
return null;
}
return shader;
}
useProgram(program, variables) {
var attr;
this.gl.useProgram(this.programs[program]);
for (attr in variables["attributes"]) {
this.variables[variables["attributes"][attr]] = this.gl.getAttribLocation(this.programs[program], variables["attributes"][attr]);
if (this.variables[variables["attributes"][attr]] == -1) {
console.log(variables["attributes"][attr], " vertex position attribut not found.");
continue;
}
this.gl.enableVertexAttribArray(this.variables[attr]);
}
for (attr in variables["uniforms"]) {
this.variables[variables["uniforms"][attr]] = this.gl.getUniformLocation(this.programs[program], variables["uniforms"][attr]);
if (!this.variables[variables["uniforms"][attr]]) {
console.log(variables["uniforms"][attr], " uniform attribut not found.");
continue;
}
}
}
// Create and bind buffer and initializes and creates the buffer object's data store.
// Parameters:
// name - buffer name
// data - An ArrayBuffer that will be copied into the data store.
// target - A GLenum specifying the binding point (target). Default ARRAY_BUFFER.
// usage - A GLenum specifying the usage pattern of the data store. Default STATIC_DRAW
initBuffer(name, data, target = this.gl.ARRAY_BUFFER, usage = this.gl.STATIC_DRAW) {
this.buffers[name] = this.gl.createBuffer();
this.gl.bindBuffer(target, this.buffers[name]);
this.gl.bufferData(target, new Float32Array(data), usage);
}
//resize canvas and viewport.
// Parameters:
// width - width to resize. Default window.innerWidth.
// height - height to resize. Default window.innerHeight.
// return value - None.
resize(width = window.innerWidth, height = window.innerHeight) {
this.canvas.width = width;
this.canvas.height = height;
this.gl.viewport(0, 0, width, height);
}
// Clear COLOR_BUFFER_BIT and DEPTH_BUFFER_BIT.
// return value - None.
clear() {
// COLOR_BUFFER_BIT; STENCIL_BUFFER_BIT; DEPTH_BUFFER_BIT
this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT);
}
// Parameters:
// name - buffer name
// location - string, name of the vertex attribute that is to be modified.
// size - A GLint specifying the number of components per vertex attribute. Default 3.
// type - A GLenum specifying the data type of each component in the array. Default FLOAT.
// normalized - A GLboolean specifying whether integer data values should be normalized when being casted to a float. Default false.
// stride - A GLsizei specifying the offset in bytes between the beginning of consecutive vertex attributes. Cannot be larger than 255. Default 0.
// offset - A GLintptr specifying an offset in bytes of the first component in the vertex attribute array. Must be a multiple of type. Default 0.
// return value - None.
useBuffer(location, size = 3, target = this.gl.ARRAY_BUFFER, type = this.gl.FLOAT, normalized = false, stride = 0, offset = 0) {
this.gl.bindBuffer(target, this.buffers[location]);
this.gl.vertexAttribPointer(this.variables[location], size, type, normalized, stride, offset);
}
// Parameters:
// location - string, name of the uniform attribute to modify.
// value - A Float32Array of float values.
// transpose - A GLboolean specifying whether to transpose the matrix. Default false.
// return value - None.
uniformMatrix4fv(location, value, transpose = false) {
this.gl.uniformMatrix4fv(this.variables[location], transpose, new Float32Array(value));
}
// Returns canvas aspect ratio of width and height.
aspect() {
return this.canvas.width / this.canvas.height;
}
}
var canvas;
var programs = ["first"];
var para = {
"first": {
"var": {
"attributes": ["aVertexPosition", "aVertexColor"],
"uniforms": ["uPMatrix", "uMVMatrix"]
},
"shaders": {
"vs": "shader-vs",
"fs": "shader-fs"
}
}
};
var vertices = [
0.9, 0.9, 0.0, -0.9, 0.9, 0.0,
0.9, -0.9, 0.0, -0.9, -0.9, 0.0
];
var colors = [
1.0, 1.0, 1.0, 1.0, // white
1.0, 0.0, 0.0, 1.0, // red
0.0, 1.0, 0.0, 1.0, // green
0.0, 0.0, 1.0, 1.0 // blue
];
function start() {
canvas = new GLCanvas("canvasGL");
if (canvas.gl) {
canvas.initProgram(getShader(para[programs[0]]["shaders"]["vs"]), getShader(para[programs[0]]["shaders"]["fs"]), programs[0]);
canvas.useProgram(programs[0], para[programs[0]]["var"]);
canvas.initBuffer(para[programs[0]]["var"]["attributes"][0], vertices);
canvas.initBuffer(para[programs[0]]["var"]["attributes"][1], colors);
window.addEventListener('resize', draw, false);
draw();
}
}
function getShader(id) {
var shaderScript = document.getElementById(id);
if (!shaderScript) {
console.log('ERROR: Shader not loaded.');
return null;
}
return shaderScript.text;
}
function draw() {
canvas.resize();
var perspective = makePerspective(30, canvas.aspect(), 0.1, 100);
canvas.clear();
loadIdentity();
mvTranslate([0.0, 0.0, -3.5]);
canvas.useBuffer(para[programs[0]]["var"]["attributes"][0]);
canvas.useBuffer(para[programs[0]]["var"]["attributes"][1], 4);
canvas.uniformMatrix4fv(para[programs[0]]["var"]["uniforms"][0], perspective.flatten());
canvas.uniformMatrix4fv(para[programs[0]]["var"]["uniforms"][1], mvMatrix.flatten());
canvas.gl.drawArrays(canvas.gl.TRIANGLE_STRIP, 0, 4);
}
// augment Sylvester some
Matrix.Translation = function(v) {
if (v.elements.length == 2) {
var r = Matrix.I(3);
r.elements[2][0] = v.elements[0];
r.elements[2][1] = v.elements[1];
return r;
}
if (v.elements.length == 3) {
var r = Matrix.I(4);
r.elements[0][3] = v.elements[0];
r.elements[1][3] = v.elements[1];
r.elements[2][3] = v.elements[2];
return r;
}
throw "Invalid length for Translation";
}
Matrix.prototype.flatten = function() {
var result = [];
if (this.elements.length == 0)
return [];
for (var j = 0; j < this.elements[0].length; j++)
for (var i = 0; i < this.elements.length; i++)
result.push(this.elements[i][j]);
return result;
}
Matrix.prototype.ensure4x4 = function() {
if (this.elements.length == 4 &&
this.elements[0].length == 4)
return this;
if (this.elements.length > 4 ||
this.elements[0].length > 4)
return null;
for (var i = 0; i < this.elements.length; i++) {
for (var j = this.elements[i].length; j < 4; j++) {
if (i == j)
this.elements[i].push(1);
else
this.elements[i].push(0);
}
}
for (var i = this.elements.length; i < 4; i++) {
if (i == 0)
this.elements.push([1, 0, 0, 0]);
else if (i == 1)
this.elements.push([0, 1, 0, 0]);
else if (i == 2)
this.elements.push([0, 0, 1, 0]);
else if (i == 3)
this.elements.push([0, 0, 0, 1]);
}
return this;
};
Matrix.prototype.make3x3 = function() {
if (this.elements.length != 4 ||
this.elements[0].length != 4)
return null;
return Matrix.create([
[this.elements[0][0], this.elements[0][1], this.elements[0][2]],
[this.elements[1][0], this.elements[1][1], this.elements[1][2]],
[this.elements[2][0], this.elements[2][1], this.elements[2][2]]
]);
};
Vector.prototype.flatten = function() {
return this.elements;
};
function mht(m) {
var s = "";
if (m.length == 16) {
for (var i = 0; i < 4; i++) {
s += "<span style='font-family: monospace'>[" + m[i * 4 + 0].toFixed(4) + "," + m[i * 4 + 1].toFixed(4) + "," + m[i * 4 + 2].toFixed(4) + "," + m[i * 4 + 3].toFixed(4) + "]</span><br>";
}
} else if (m.length == 9) {
for (var i = 0; i < 3; i++) {
s += "<span style='font-family: monospace'>[" + m[i * 3 + 0].toFixed(4) + "," + m[i * 3 + 1].toFixed(4) + "," + m[i * 3 + 2].toFixed(4) + "]</font><br>";
}
} else {
return m.toString();
}
return s;
}
//
// gluLookAt
//
function makeLookAt(ex, ey, ez,
cx, cy, cz,
ux, uy, uz) {
var eye = $V([ex, ey, ez]);
var center = $V([cx, cy, cz]);
var up = $V([ux, uy, uz]);
var mag;
var z = eye.subtract(center).toUnitVector();
var x = up.cross(z).toUnitVector();
var y = z.cross(x).toUnitVector();
var m = $M([
[x.e(1), x.e(2), x.e(3), 0],
[y.e(1), y.e(2), y.e(3), 0],
[z.e(1), z.e(2), z.e(3), 0],
[0, 0, 0, 1]
]);
var t = $M([
[1, 0, 0, -ex],
[0, 1, 0, -ey],
[0, 0, 1, -ez],
[0, 0, 0, 1]
]);
return m.x(t);
}
//
// glOrtho
//
function makeOrtho(left, right,
bottom, top,
znear, zfar) {
var tx = -(right + left) / (right - left);
var ty = -(top + bottom) / (top - bottom);
var tz = -(zfar + znear) / (zfar - znear);
return $M([
[2 / (right - left), 0, 0, tx],
[0, 2 / (top - bottom), 0, ty],
[0, 0, -2 / (zfar - znear), tz],
[0, 0, 0, 1]
]);
}
//
// gluPerspective
//
function makePerspective(fovy, aspect, znear, zfar) {
var ymax = znear * Math.tan(fovy * Math.PI / 360.0);
var ymin = -ymax;
var xmin = ymin * aspect;
var xmax = ymax * aspect;
return makeFrustum(xmin, xmax, ymin, ymax, znear, zfar);
}
//
// glFrustum
//
function makeFrustum(left, right,
bottom, top,
znear, zfar) {
var X = 2 * znear / (right - left);
var Y = 2 * znear / (top - bottom);
var A = (right + left) / (right - left);
var B = (top + bottom) / (top - bottom);
var C = -(zfar + znear) / (zfar - znear);
var D = -2 * zfar * znear / (zfar - znear);
return $M([
[X, 0, A, 0],
[0, Y, B, 0],
[0, 0, C, D],
[0, 0, -1, 0]
]);
}
//
// glOrtho
//
function makeOrtho(left, right, bottom, top, znear, zfar) {
var tx = -(right + left) / (right - left);
var ty = -(top + bottom) / (top - bottom);
var tz = -(zfar + znear) / (zfar - znear);
return $M([
[2 / (right - left), 0, 0, tx],
[0, 2 / (top - bottom), 0, ty],
[0, 0, -2 / (zfar - znear), tz],
[0, 0, 0, 1]
]);
}
function loadIdentity() {
mvMatrix = Matrix.I(4);
}
function multMatrix(m) {
mvMatrix = mvMatrix.x(m);
}
function mvTranslate(v) {
multMatrix(Matrix.Translation($V([v[0], v[1], v[2]])).ensure4x4());
}
body {
height: 100%;
width: 100%;
margin: 0px;
padding: 0px;
overflow: hidden;
/* Disable scrollbars */
display: block;
/* No floating content on sides */
border: 0;
}
* {
box-sizing: border-box;
}
canvas {
position: absolute;
left: 0px;
top: 0px;
}
<!DOCTYPE html>
<html>
<head>
<title>Geo</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body onload="start()">
<canvas id="canvasGL">
Your browser does not support the HTML5 canvas tag.
</canvas>
<script id="shader-vs" type="x-shader/x-vertex">
attribute vec3 aVertexPosition; attribute vec4 aVertexColor; uniform mat4 uMVMatrix; uniform mat4 uPMatrix; varying lowp vec4 vColor; void main(void) { gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0); vColor = aVertexColor; }
</script>
<script id="shader-fs" type="x-shader/x-fragment">
varying lowp vec4 vColor; void main(void) { gl_FragColor = vColor; }
</script>
<script src="https://mdn.github.io/webgl-examples/tutorial/sylvester.js"></script>
</body>
</html>
答案 0 :(得分:0)
使用错误的索引在useProgram函数中获取属性位置引用。
unset x y ; seq 250 5 280 | grep "$x" | grep "$y" | grep "$z"
270
275
小心......