我正在尝试对webgl进行2D转换。旋转没有问题,比例尺可能效果很好。另一方面,翻译仍然无法正常工作。我想,我犯了一个愚蠢的错误,我看不到我错过的东西。
handlePressedDownKeys(translation),我传递了数组,当我按w,s,d,a,translate [0]或translation [1]时,将增加或减少。我没有添加此功能,但效果很好,因为当我按下按钮时,我可以看到屏幕上的6.和7.值正在改变的矩阵。
这是我的代码:
var keyList = {
87: false,
83: false,
65: false,
68: false
};
var speed = 0.001;
function handleKeyDown(event){
keyList[event.keyCode] = true;
}
function handleKeyUp(event){
keyList[event.keyCode] = false;
}
function handlePressedDownKeys(vec2){
//console.log(vec2);
if(keyList[87]){ // w
vec2[0] += speed;
console.log(vec2)
}
else if(keyList[83]){
vec2[1] -= speed;
}
else if(keyList[65]){
vec2[0] -= speed;
}
else if(keyList[68]){
vec2[1] += speed;
}
}
class Mat{
constructor(matrixLenght){
this.matrixLenght = matrixLenght;
}
identity(){
if(this.matrixLenght == 3){
return new Float32Array([
1, 0, 0,
0, 1, 0,
0, 0, 1,
]);
}else if(this.matrixLenght == 4){
return new Float32Array([
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
]);
}else if(this.matrixLenght == 5){
return new Float32Array([
1, 0, 0, 0, 0,
0, 1, 0, 0, 0,
0, 0, 1, 0, 0,
0, 0, 0, 1, 0,
0, 0, 0, 0, 1,
]);
}
}
translate(tx, ty){
return new Float32Array([
1, 0, 0,
0, 1, 0,
tx, ty, 1,
]);
}
rotate(angle){
var c = Math.cos(angle * Math.PI / 180);
var s = Math.sin(angle * Math.PI / 180);
return new Float32Array([
c, -s, 0,
s, c, 0,
0, 0, 1,
]);
}
scale(sx, sy){
return new Float32Array([
sx, 0, 0,
0, sy, 0,
0, 0, 1,
]);
}
multiply(x, y){
var x_mat = [];
var for_x = 0, for_y = 0;
var y_mat = [];
var result = [];
var resultList = [];
// O(n^3) :(
for(var i=0; i < this.matrixLenght; i++){
x_mat[i] = [];
for(var j=0; j < this.matrixLenght; j++){
x_mat[i][j] = x[for_x];
for_x++;
}
}
for(var i=0; i < this.matrixLenght; i++){
y_mat[i] = [];
for(var j=0; j < this.matrixLenght; j++){
y_mat[i][j] = y[for_y];
for_y++;
}
}
for(var i=0; i < this.matrixLenght; i++){
result[i] = [];
for(var j = 0; j < this.matrixLenght; j++){
result[i][j] = 0;
for(var s = 0; s < this.matrixLenght; s++){
result[i][j] += x_mat[i][s] * y_mat[s][j];
}
resultList.push(result[i][j]);
}
}
return new Float32Array(resultList);
}
}
class ShaderProgram{
#program_id;
#gl;
constructor(gl, vertexShader, fragmentShader){
this.#gl = gl;
this.#program_id = this.#gl.createProgram();
this.createAndAttachShader(vertexShader, "vertex");
this.createAndAttachShader(fragmentShader, "fragment");
this.link();
this.m_uniforms = new Map();
}
createAndAttachShader(fileName, shaderType){
if(shaderType=="vertex") var shader = this.#gl.createShader(this.#gl.VERTEX_SHADER);
else if(shaderType=="fragment") var shader = this.#gl.createShader(this.#gl.FRAGMENT_SHADER);
else return null;
this.#gl.shaderSource(shader, fileName);
this.#gl.compileShader(shader);
let control = this.#gl.getShaderParameter(shader, this.#gl.COMPILE_STATUS);
if(!control){
console.error(`Error compiling ${shaderType} shader;`);
console.log(gl.getShaderInfoLog(shader));
}
this.#gl.attachShader(this.#program_id, shader);
}
use(){
this.#gl.useProgram(this.#program_id);
}
link(){
this.#gl.linkProgram(this.#program_id);
let control = this.#gl.getProgramParameter(this.#program_id, this.#gl.LINK_STATUS);
if(!control) console.error("Shaders have problem");
}
getProgram(){
return this.#program_id;
}
getGL(){
return this.#gl;
}
addUniform(uniformName){
// set ( uniformName , this uniform's location or id )
this.m_uniforms.set(uniformName, this.#gl.getUniformLocation(this.#program_id, uniformName));
}
setUniform(uniformName, vec2){
// gl.uniform1f ( location , value )
this.#gl.uniform3f(this.m_uniforms.get(uniformName), vec2.x, vec2.y, 0.0);
}
setUniformVec4(uniformName, vec4){
this.#gl.uniform4f(this.m_uniforms.get(uniformName), vec4.x, vec4.y, vec4.z, vec4.w);
}
setMatrix(uniformName, mat3){
this.#gl.uniformMatrix3fv(this.m_uniforms.get(uniformName), false, mat3);
}
}
var vertexShader = `#version 300 es
in vec3 aVertexPosition;
uniform mat3 uTransform;
uniform vec2 u_resolution;
void main(){
gl_Position = vec4(uTransform * aVertexPosition, 1.0);
}`;
var fragmentShader = `#version 300 es
precision highp float;
out vec4 outColor;
uniform vec4 uColor;
void main(){
outColor = uColor;
}`;
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
var mat3 = new Mat(3);
let gl;
var length = 0.08;
var positions = [
-length/2, length/2,
-length/2, -length/2,
length/2, -length/2,
-length/2, length/2,
length/2, -length/2,
length/2, length/2,
];
var vertices = [];
var indices = [];
class Square {
getColor() {
return {x:1,y:0,z:0,w:1};
}
}
function init(){
var textCanvas = document.getElementById("gl-text");
ctx = textCanvas.getContext("2d");
var shaderProgram = new ShaderProgram(getGLContext('gl-canvas'), vertexShader, fragmentShader);
shaderProgram.use();
var transform_m = mat3.identity();
var translateM, rotateM, scaleM;
var angle_rotation = 0.0;
var translation = new Float32Array([0,0]);
var scale = new Float32Array([1,1]);
gl = shaderProgram.getGL();
program = shaderProgram.getProgram();
var square1 = new Square(0, 0, 0.1);
shaderProgram.addUniform("uColor"); // getUniform
shaderProgram.addUniform("uTransform"); // getUniform
let vertexPositionAttributeLocation = gl.getAttribLocation(program, "aVertexPosition");
var positionBuffer = gl.createBuffer(); // vbo
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
var vao = gl.createVertexArray(); // vao
gl.bindVertexArray(vao); // activate VAO which we use
gl.enableVertexAttribArray(vertexPositionAttributeLocation);
gl.vertexAttribPointer(vertexPositionAttributeLocation, 2, gl.FLOAT, false, 0, 0);
gl.clearColor(0.9, 0.9, 0.9, 1.0);
let secondsPassed;
let oldTimeStamp;
let fps;
document.addEventListener('keydown', handleKeyDown, false);
document.addEventListener('keyup', handleKeyUp, false);
function animate (timeStamp) {
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
translateM = mat3.translate(translation[0], translation[1]);
rotateM = mat3.rotate(angle_rotation);
scaleM = mat3.scale(scale[0], scale[1]);
transform_m = mat3.multiply(transform_m, translateM);
transform_m = mat3.multiply(transform_m, rotateM);
transform_m = mat3.multiply(transform_m, scaleM);
angle_rotation += .001;
secondsPassed = (timeStamp - oldTimeStamp) / 1000;
oldTimeStamp = timeStamp;
fps = Math.round(1 / secondsPassed);
handlePressedDownKeys(translation);
shaderProgram.use();
shaderProgram.setUniformVec4("uColor", square1.getColor());
shaderProgram.setMatrix("uTransform", transform_m);
gl.drawArrays(gl.TRIANGLES, new Float32Array(positions), 6);
ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height);
ctx.fillText(transform_m[0].toFixed(2) + " " + transform_m[1].toFixed(2) + " " + transform_m[2].toFixed(2), 10, 10);
ctx.fillText(transform_m[3].toFixed(2) + " " + transform_m[4].toFixed(2) + " " + transform_m[5].toFixed(2), 10, 20);
ctx.fillText(transform_m[6].toFixed(2) + " " + transform_m[7].toFixed(2) + " " + transform_m[8].toFixed(2), 10, 30);
ctx.fillText("FPS: " + fps, 10, 40);
window.requestAnimationFrame(animate);
}
animate(0);
}
init();
function getGLContext(id){
var canvas = document.getElementById(id);
return canvas.getContext('webgl2');
}
<canvas id="gl-canvas"></canvas>
<canvas id="gl-text"></canvas>
问题是顶点着色器中的数学运算或传递给它的数据
gl_Position = vec4(uTransform * aVertexPosition, 1.0);
uTransform
是mat3
,aVertexPosition
是vec3
。除非将aVertexPosition.z
设置为1
,否则翻译将被忽略。
您既可以将数据添加到顶点,也可以在顶点着色器中对其进行修复
gl_Position = vec4(uTransform * vec3(aVertexPosition.xy, 1), 1);
var keyList = {
87: false,
83: false,
65: false,
68: false
};
var speed = 0.001;
function handleKeyDown(event){
keyList[event.keyCode] = true;
}
function handleKeyUp(event){
keyList[event.keyCode] = false;
}
function handlePressedDownKeys(vec2){
//console.log(vec2);
if(keyList[87]){ // w
vec2[0] += speed;
console.log(vec2)
}
else if(keyList[83]){
vec2[1] -= speed;
}
else if(keyList[65]){
vec2[0] -= speed;
}
else if(keyList[68]){
vec2[1] += speed;
}
}
class Mat{
constructor(matrixLenght){
this.matrixLenght = matrixLenght;
}
identity(){
if(this.matrixLenght == 3){
return new Float32Array([
1, 0, 0,
0, 1, 0,
0, 0, 1,
]);
}else if(this.matrixLenght == 4){
return new Float32Array([
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
]);
}else if(this.matrixLenght == 5){
return new Float32Array([
1, 0, 0, 0, 0,
0, 1, 0, 0, 0,
0, 0, 1, 0, 0,
0, 0, 0, 1, 0,
0, 0, 0, 0, 1,
]);
}
}
translate(tx, ty){
return new Float32Array([
1, 0, 0,
0, 1, 0,
tx, ty, 1,
]);
}
rotate(angle){
var c = Math.cos(angle * Math.PI / 180);
var s = Math.sin(angle * Math.PI / 180);
return new Float32Array([
c, -s, 0,
s, c, 0,
0, 0, 1,
]);
}
scale(sx, sy){
return new Float32Array([
sx, 0, 0,
0, sy, 0,
0, 0, 1,
]);
}
multiply(x, y){
var x_mat = [];
var for_x = 0, for_y = 0;
var y_mat = [];
var result = [];
var resultList = [];
// O(n^3) :(
for(var i=0; i < this.matrixLenght; i++){
x_mat[i] = [];
for(var j=0; j < this.matrixLenght; j++){
x_mat[i][j] = x[for_x];
for_x++;
}
}
for(var i=0; i < this.matrixLenght; i++){
y_mat[i] = [];
for(var j=0; j < this.matrixLenght; j++){
y_mat[i][j] = y[for_y];
for_y++;
}
}
for(var i=0; i < this.matrixLenght; i++){
result[i] = [];
for(var j = 0; j < this.matrixLenght; j++){
result[i][j] = 0;
for(var s = 0; s < this.matrixLenght; s++){
result[i][j] += x_mat[i][s] * y_mat[s][j];
}
resultList.push(result[i][j]);
}
}
return new Float32Array(resultList);
}
}
class ShaderProgram{
#program_id;
#gl;
constructor(gl, vertexShader, fragmentShader){
this.#gl = gl;
this.#program_id = this.#gl.createProgram();
this.createAndAttachShader(vertexShader, "vertex");
this.createAndAttachShader(fragmentShader, "fragment");
this.link();
this.m_uniforms = new Map();
}
createAndAttachShader(fileName, shaderType){
if(shaderType=="vertex") var shader = this.#gl.createShader(this.#gl.VERTEX_SHADER);
else if(shaderType=="fragment") var shader = this.#gl.createShader(this.#gl.FRAGMENT_SHADER);
else return null;
this.#gl.shaderSource(shader, fileName);
this.#gl.compileShader(shader);
let control = this.#gl.getShaderParameter(shader, this.#gl.COMPILE_STATUS);
if(!control){
console.error(`Error compiling ${shaderType} shader;`);
console.log(gl.getShaderInfoLog(shader));
}
this.#gl.attachShader(this.#program_id, shader);
}
use(){
this.#gl.useProgram(this.#program_id);
}
link(){
this.#gl.linkProgram(this.#program_id);
let control = this.#gl.getProgramParameter(this.#program_id, this.#gl.LINK_STATUS);
if(!control) console.error("Shaders have problem");
}
getProgram(){
return this.#program_id;
}
getGL(){
return this.#gl;
}
addUniform(uniformName){
// set ( uniformName , this uniform's location or id )
this.m_uniforms.set(uniformName, this.#gl.getUniformLocation(this.#program_id, uniformName));
}
setUniform(uniformName, vec2){
// gl.uniform1f ( location , value )
this.#gl.uniform3f(this.m_uniforms.get(uniformName), vec2.x, vec2.y, 0.0);
}
setUniformVec4(uniformName, vec4){
this.#gl.uniform4f(this.m_uniforms.get(uniformName), vec4.x, vec4.y, vec4.z, vec4.w);
}
setMatrix(uniformName, mat3){
this.#gl.uniformMatrix3fv(this.m_uniforms.get(uniformName), false, mat3);
}
}
var vertexShader = `#version 300 es
in vec3 aVertexPosition;
uniform mat3 uTransform;
uniform vec2 u_resolution;
void main(){
gl_Position = vec4(uTransform * vec3(aVertexPosition.xy, 1), 1);
}`;
var fragmentShader = `#version 300 es
precision highp float;
out vec4 outColor;
uniform vec4 uColor;
void main(){
outColor = uColor;
}`;
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
var mat3 = new Mat(3);
let gl;
var length = 0.08;
var positions = [
-length/2, length/2,
-length/2, -length/2,
length/2, -length/2,
-length/2, length/2,
length/2, -length/2,
length/2, length/2,
];
var vertices = [];
var indices = [];
class Square {
getColor() {
return {x:1,y:0,z:0,w:1};
}
}
function init(){
var textCanvas = document.getElementById("gl-text");
ctx = textCanvas.getContext("2d");
var shaderProgram = new ShaderProgram(getGLContext('gl-canvas'), vertexShader, fragmentShader);
shaderProgram.use();
var transform_m = mat3.identity();
var translateM, rotateM, scaleM;
var angle_rotation = 0.0;
var translation = new Float32Array([0,0]);
var scale = new Float32Array([1,1]);
gl = shaderProgram.getGL();
program = shaderProgram.getProgram();
var square1 = new Square(0, 0, 0.1);
shaderProgram.addUniform("uColor"); // getUniform
shaderProgram.addUniform("uTransform"); // getUniform
let vertexPositionAttributeLocation = gl.getAttribLocation(program, "aVertexPosition");
var positionBuffer = gl.createBuffer(); // vbo
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
var vao = gl.createVertexArray(); // vao
gl.bindVertexArray(vao); // activate VAO which we use
gl.enableVertexAttribArray(vertexPositionAttributeLocation);
gl.vertexAttribPointer(vertexPositionAttributeLocation, 2, gl.FLOAT, false, 0, 0);
gl.clearColor(0.9, 0.9, 0.9, 1.0);
let secondsPassed;
let oldTimeStamp;
let fps;
document.addEventListener('keydown', handleKeyDown, false);
document.addEventListener('keyup', handleKeyUp, false);
function animate (timeStamp) {
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
translateM = mat3.translate(translation[0], translation[1]);
rotateM = mat3.rotate(angle_rotation);
scaleM = mat3.scale(scale[0], scale[1]);
transform_m = mat3.multiply(transform_m, translateM);
transform_m = mat3.multiply(transform_m, rotateM);
transform_m = mat3.multiply(transform_m, scaleM);
angle_rotation += .001;
secondsPassed = (timeStamp - oldTimeStamp) / 1000;
oldTimeStamp = timeStamp;
fps = Math.round(1 / secondsPassed);
handlePressedDownKeys(translation);
shaderProgram.use();
shaderProgram.setUniformVec4("uColor", square1.getColor());
shaderProgram.setMatrix("uTransform", transform_m);
gl.drawArrays(gl.TRIANGLES, new Float32Array(positions), 6);
ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height);
ctx.fillText(transform_m[0].toFixed(2) + " " + transform_m[1].toFixed(2) + " " + transform_m[2].toFixed(2), 10, 10);
ctx.fillText(transform_m[3].toFixed(2) + " " + transform_m[4].toFixed(2) + " " + transform_m[5].toFixed(2), 10, 20);
ctx.fillText(transform_m[6].toFixed(2) + " " + transform_m[7].toFixed(2) + " " + transform_m[8].toFixed(2), 10, 30);
ctx.fillText("FPS: " + fps, 10, 40);
window.requestAnimationFrame(animate);
}
animate(0);
}
init();
function getGLContext(id){
var canvas = document.getElementById(id);
return canvas.getContext('webgl2');
}
<canvas id="gl-canvas"></canvas>
<canvas id="gl-text"></canvas>
此外,对gl.drawArrays
的调用应为gl.drawArrays(primitiveType, offset, count)
,但您要传递整个数组作为偏移量。这是没有意义的。运气很快就将其自动转换为0。
您可能会发现these tutorials有用。