对象无法旋转,但可以使用变换矩阵旋转

问题描述 投票:0回答:1

我正在尝试对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>
webgl
1个回答
1
投票

问题是顶点着色器中的数学运算或传递给它的数据

gl_Position = vec4(uTransform * aVertexPosition, 1.0);

uTransformmat3aVertexPositionvec3。除非将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有用。

© www.soinside.com 2019 - 2024. All rights reserved.