Создать новую модель matrix Webgl

#javascript #html #webgl

#javascript #HTML #webgl

Вопрос:

Я новичок в webgl, и я пытался создать два куба, которые вращаются вокруг своей оси, но прямо сейчас они вращаются только по одной оси. Я хотел бы знать, что я делаю не так, (я думаю, это потому, что мне нужно создать новую матрицу модели для поворота, но я не уверен, как это сделать). Спасибо!

 // Application info.
var app = app || {};

function initGL()
{
    var gl = app.gl;

    gl.enable(gl.DEPTH_TEST);
    gl.depthFunc(gl.LEQUAL);

    gl.viewport(0,0,app.can.width, app.can.height);
    gl.clearColor(0.,0.,0., 1.0);
    gl.clear(app.gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

    var vs = createShaderFromElement(app.gl, "vs");
    var fs = createShaderFromElement(app.gl, "fs");
    app.progObject = buildProgram(app.gl, vs, fs);

    gl.useProgram(app.progObject);
}

function initScene()
{
    var gl = app.gl;

    // Creer le buffer de geometrie (vertex)
    //
    var positions = [
        // Front face
        -1.0, -1.0,  1.0,
         1.0, -1.0,  1.0,
         1.0,  1.0,  1.0,
         1.0,  1.0,  1.0,
        -1.0,  1.0,  1.0,
        -1.0, -1.0,  1.0,
        
        // Back face
        -1.0, -1.0, -1.0,
        -1.0,  1.0, -1.0,
         1.0,  1.0, -1.0,
         1.0,  1.0, -1.0,
         1.0, -1.0, -1.0,
        -1.0, -1.0, -1.0,
        
        // Top face
        -1.0,  1.0, -1.0,
        -1.0,  1.0,  1.0,
         1.0,  1.0,  1.0,
         1.0,  1.0,  1.0,
         1.0,  1.0, -1.0,
        -1.0,  1.0, -1.0,
        
        // Bottom face
        -1.0, -1.0, -1.0,
         1.0, -1.0, -1.0,
         1.0, -1.0,  1.0,
         1.0, -1.0,  1.0,
        -1.0, -1.0,  1.0,
        -1.0, -1.0, -1.0,
        
        // Right face
         1.0, -1.0, -1.0,
         1.0,  1.0, -1.0,
         1.0,  1.0,  1.0,
         1.0,  1.0,  1.0,
         1.0, -1.0,  1.0,
         1.0, -1.0, -1.0,
        
        // Left face
        -1.0, -1.0, -1.0,
        -1.0, -1.0,  1.0,
        -1.0,  1.0,  1.0,
        -1.0,  1.0,  1.0,
        -1.0,  1.0, -1.0,
        -1.0, -1.0, -1.0
    ];

    app.nPoints = positions.length / 3;

    var colors = [
        1,1,1,  1,1,1,  1,1,1, 1,1,1,  1,1,1,  1,1,1,
        1,0,0,  1,0,0,  1,0,0, 1,0,0,  1,0,0,  1,0,0,
        0,1,0,  0,1,0,  0,1,0, 0,1,0,  0,1,0,  0,1,0,
        0,0,1,  0,0,1,  0,0,1, 0,0,1,  0,0,1,  0,0,1,
        1,1,0,  1,1,0,  1,1,0, 1,1,0,  1,1,0,  1,1,0,
        1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1

    ];


    var loc, buffer;
    // Create and copy position buffer.
    loc = gl.getAttribLocation(app.progObject, "pos");
    buffer = gl.createBuffer();
    gl.enableVertexAttribArray(loc);
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
    gl.vertexAttribPointer(loc, 3, gl.FLOAT, false /*no normalization*/, 0 /*stride*/, 0 /*offset*/);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);


    // Create and copy color buffer.
    loc = gl.getAttribLocation(app.progObject, "color");
    buffer = gl.createBuffer();
    gl.enableVertexAttribArray(loc);
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
    gl.vertexAttribPointer(loc, 3, gl.FLOAT, false /*no normalization*/, 0 /*stride*/, 0 /*offset*/);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);

 // Look for uniforms.
 app.pmLocation = gl.getUniformLocation(app.progObject, "projMatrix");
 app.mmLocation = gl.getUniformLocation(app.progObject, "modelMatrix");
 app.vmLocation = gl.getUniformLocation(app.progObject, "viewMatrix");

    var mat4 = glMatrix.mat4;
    app.projMatrix = mat4.create();
    app.modelMatrix = mat4.create();
    app.viewMatrix = mat4.create();

    

    mat4.perspective(app.projMatrix, Math.PI / 4.0 /*45 degrees*/, 1, 0.1, 100);
    mat4.lookAt(app.viewMatrix, [0, 0, -10], [0, 0, 0], [0, 1, 0]);


}

function animate(time)
{
    var gl = app.gl;
    var mat4 = glMatrix.mat4;


    // converts to seconds.
    var seconds = time * 1E-3;
    var dtime = time - app.oldTime;

    var angle = dtime * 0.001;
    mat4.rotateY(app.modelMatrix, app.modelMatrix, angle);
    var mm1 = mat4.create();
    mat4.translate(mm1, app.modelMatrix, [2, 0, 0]);
    app.oldTime = time;

    gl.clear(app.gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

    gl.uniformMatrix4fv(app.pmLocation, false, app.projMatrix );
    gl.uniformMatrix4fv(app.mmLocation, false, mm1 );
    gl.uniformMatrix4fv(app.vmLocation, false, app.viewMatrix );
    gl.drawArrays(gl.TRIANGLES, 0, app.nPoints);

    // Pour dessiner autre cube, calculer autre model matrix
    // et redessiner ... gl.drawArrays(gl.TRIANGLES, 0, app.nPoints);
    

    mat4.rotateY( app.modelMatrix,  app.modelMatrix, angle)
    var mm2 = mat4.create();
    mat4.translate(mm2, app.modelMatrix, [-2, 0, 0]);
    gl.uniformMatrix4fv(app.pmLocation, false, app.projMatrix);
    gl.uniformMatrix4fv(app.mmLocation, false, mm2);
    gl.uniformMatrix4fv(app.vmLocation, false, app.viewMatrix);
    gl.drawArrays(gl.TRIANGLES, 0, app.nPoints);

    window.requestAnimationFrame(animate);
}

function fovChanged(id, value)
{
    console.log("FOV Angle: ", value);
    var label = document.getElementById( 'output-fov' );
    label.innerHTML = value;

}

function farChanged(id, value)
{
    console.log("Far Plane: ", value);
    var label = document.getElementById( 'output-far' );
    label.innerHTML = value;
}

function init()
{
    [app.can, app.gl] = getContextGL('can');
    if (app.can == null || app.gl == null)
    {
        alert("Can't init canvas or context");
        return;
    }

    app.can.width = app.can.height * (app.can.clientWidth / app.can.clientHeight);
    
    var rect = app.can.getBoundingClientRect();
  app.scaleX = app.can.width / rect.width;
  app.scaleY = app.can.height / rect.height; 

    initGL();
    initScene();

    app.oldTime = 0;
    animate(0);
}  
 div 
{
}

#main-div
{
display:inline-block;
}

#viewport, #manager
{
    float: left;
    margin: auto;
}

.color
{
    width:100px;
    height:50px;
}

.blue{
    background:#0f0;
}

#viewport
{
    width: 600px;
    height:700px;
}

#can
{
    width: 600px;
    height: 500px;
    border:1px solid orange;
}

#manager
{
    width: 200px;
    height:300px;
    padding: 0 0 0 5px;

}

#obj-list
{
    width: 200px;
}  
 <!DOCTYPE html>
<html>

<head>
    <title>Cube Transform</title>
    <link rel="stylesheet" type="text/css" href="style.css">
    <script src="transforms.js"></script> 
    <script src="utils.js"></script> 
    <script src="gl-matrix-min.js"></script> 

    <script id="vs" type="x-shader/x-vertex">
        precision mediump float;

        uniform mat4 projMatrix;
        uniform mat4 viewMatrix;
        uniform mat4 modelMatrix;


        attribute vec3 pos;
        attribute vec3 color;
        varying vec3 fColor;

        void main()
        {
        fColor = color;
        vec4 pt = vec4(pos, 1.0);
        gl_Position = projMatrix * viewMatrix * modelMatrix * pt;
        }
    </script>

    <script id="fs" type="x-shader/x-fragment">
  precision mediump float;
    varying vec3 fColor;

  void main() 
    {
    gl_FragColor = vec4(fColor,1);
  }
  </script>

</head>

<body onload="init();">

    <div id="main-div">

            <div id="viewport">
                <canvas id="can" >Your browser doesn't seem to support canvas!</canvas>
                <div class="slider">
                        <span class="slider-label">FOV cam</span>
                        <input id="fov" class="slider-input" type="range" min="20" max="90" step="1" value="0" onClick="fovChanged(this.id, this.value)" />
                        <span id="output-fov" class="slider-value">20</span>
                    </div>


                    <div class="slider">
                        <span class="slider-label">Far Plane</span>
                        <input id="far" class="slider-input" type="range" min="5" max="30" step="0.1" value="0"  onClick="farChanged(this.id, this.value)" />
                        <span id="output-far" class="slider-value">5</span>
                    </div>

            </div>

    </div>

</body>
</html>  

Ответ №1:

Я не совсем уверен, что пытается сделать ваш код.

В любом случае, в общем, чтобы повернуть на месте, чтобы перевести, а затем повернуть

 mat = idenity
mat = mat * translation
mat = mat * rotation
  

или в зависимости от библиотеки

 mat = identity
translate(mat, ...)
rotate(mat, ...)
  

или

 mat = translation(...);
rotate(mat, ...);
  

и т.д.

 // Application info.
var app = app || {};

function initGL() {
  var gl = app.gl;

  gl.enable(gl.DEPTH_TEST);
  gl.depthFunc(gl.LEQUAL);

  gl.viewport(0, 0, app.can.width, app.can.height);
  gl.clearColor(0., 0., 0., 1.0);
  gl.clear(app.gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

  var vs = createShaderFromElement(app.gl, "vs");
  var fs = createShaderFromElement(app.gl, "fs");
  app.progObject = buildProgram(app.gl, vs, fs);

  gl.useProgram(app.progObject);
}

function initScene() {
  var gl = app.gl;

  // Creer le buffer de geometrie (vertex)
  //
  var positions = [
    // Front face
    -1.0, -1.0, 1.0,
    1.0, -1.0, 1.0,
    1.0, 1.0, 1.0,
    1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0,

    // Back face
    -1.0, -1.0, -1.0, -1.0, 1.0, -1.0,
    1.0, 1.0, -1.0,
    1.0, 1.0, -1.0,
    1.0, -1.0, -1.0, -1.0, -1.0, -1.0,

    // Top face
    -1.0, 1.0, -1.0, -1.0, 1.0, 1.0,
    1.0, 1.0, 1.0,
    1.0, 1.0, 1.0,
    1.0, 1.0, -1.0, -1.0, 1.0, -1.0,

    // Bottom face
    -1.0, -1.0, -1.0,
    1.0, -1.0, -1.0,
    1.0, -1.0, 1.0,
    1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0,

    // Right face
    1.0, -1.0, -1.0,
    1.0, 1.0, -1.0,
    1.0, 1.0, 1.0,
    1.0, 1.0, 1.0,
    1.0, -1.0, 1.0,
    1.0, -1.0, -1.0,

    // Left face
    -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0
  ];

  app.nPoints = positions.length / 3;

  var colors = [
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0,
    0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0,
    0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1,
    1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0,
    1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1

  ];


  var loc, buffer;
  // Create and copy position buffer.
  loc = gl.getAttribLocation(app.progObject, "pos");
  buffer = gl.createBuffer();
  gl.enableVertexAttribArray(loc);
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
  gl.vertexAttribPointer(loc, 3, gl.FLOAT, false /*no normalization*/ , 0 /*stride*/ , 0 /*offset*/ );
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);


  // Create and copy color buffer.
  loc = gl.getAttribLocation(app.progObject, "color");
  buffer = gl.createBuffer();
  gl.enableVertexAttribArray(loc);
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
  gl.vertexAttribPointer(loc, 3, gl.FLOAT, false /*no normalization*/ , 0 /*stride*/ , 0 /*offset*/ );
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);

  // Look for uniforms.
  app.pmLocation = gl.getUniformLocation(app.progObject, "projMatrix");
  app.mmLocation = gl.getUniformLocation(app.progObject, "modelMatrix");
  app.vmLocation = gl.getUniformLocation(app.progObject, "viewMatrix");

  var mat4 = glMatrix.mat4;
  app.projMatrix = mat4.create();
  app.modelMatrix = mat4.create();
  app.viewMatrix = mat4.create();



  mat4.perspective(app.projMatrix, Math.PI / 4.0 /*45 degrees*/ , 1, 0.1, 100);
  mat4.lookAt(app.viewMatrix, [0, 0, -10], [0, 0, 0], [0, 1, 0]);


}

function animate(time) {
  var gl = app.gl;
  var mat4 = glMatrix.mat4;


  // converts to seconds.
  var seconds = time * 1E-3;
  var dtime = time - app.oldTime;

  var mm1 = mat4.create();
  mat4.translate(mm1, app.modelMatrix, [2, 0, 0]);
  var angle = time * 0.001;
  mat4.rotateY(mm1, mm1, angle);
  app.oldTime = time;

  gl.clear(app.gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

  gl.uniformMatrix4fv(app.pmLocation, false, app.projMatrix);
  gl.uniformMatrix4fv(app.mmLocation, false, mm1);
  gl.uniformMatrix4fv(app.vmLocation, false, app.viewMatrix);
  gl.drawArrays(gl.TRIANGLES, 0, app.nPoints);

  // Pour dessiner autre cube, calculer autre model matrix
  // et redessiner ... gl.drawArrays(gl.TRIANGLES, 0, app.nPoints);


  var mm2 = mat4.create();
  mat4.translate(mm2, app.modelMatrix, [-2, 0, 0]);
  mat4.rotateY(mm2, mm2, angle)
  gl.uniformMatrix4fv(app.pmLocation, false, app.projMatrix);
  gl.uniformMatrix4fv(app.mmLocation, false, mm2);
  gl.uniformMatrix4fv(app.vmLocation, false, app.viewMatrix);
  gl.drawArrays(gl.TRIANGLES, 0, app.nPoints);

  window.requestAnimationFrame(animate);
}

function fovChanged(id, value) {
  console.log("FOV Angle: ", value);
  var label = document.getElementById('output-fov');
  label.innerHTML = value;

}

function farChanged(id, value) {
  console.log("Far Plane: ", value);
  var label = document.getElementById('output-far');
  label.innerHTML = value;
}

function init() {
  [app.can, app.gl] = getContextGL('can');
  if (app.can == null || app.gl == null) {
    alert("Can't init canvas or context");
    return;
  }

  app.can.width = app.can.height * (app.can.clientWidth / app.can.clientHeight);

  var rect = app.can.getBoundingClientRect();
  app.scaleX = app.can.width / rect.width;
  app.scaleY = app.can.height / rect.height;

  initGL();
  initScene();

  app.oldTime = 0;
  animate(0);
}

init();

// -----

function getContextGL(id) {
  const can = document.getElementById(id);
  const gl = can.getContext('webgl');
  return [can, gl];
}

function createShaderFromElement(gl, id) {
  const e = document.getElementById(id);
  const s = gl.createShader(e.type.indexOf('vertex') >= 0 ? gl.VERTEX_SHADER : gl.FRAGMENT_SHADER);
  gl.shaderSource(s, e.text);
  gl.compileShader(s);
  return s;
}

function buildProgram(gl, vs, fs) {
  const p = gl.createProgram();
  gl.attachShader(p, vs);
  gl.attachShader(p, fs);
  gl.linkProgram(p);
  return p;
}  
 div {}

#main-div {
  display: inline-block;
}

#viewport,
#manager {
  float: left;
  margin: auto;
}

.color {
  width: 100px;
  height: 50px;
}

.blue {
  background: #0f0;
}

#viewport {
  width: 600px;
  height: 700px;
}

#can {
  width: 600px;
  height: 500px;
  border: 1px solid orange;
}

#manager {
  width: 200px;
  height: 300px;
  padding: 0 0 0 5px;
}

#obj-list {
  width: 200px;
}  
 <script src="https://cdn.jsdelivr.net/npm/gl-matrix@3.3.0/gl-matrix-min.js"></script>

    <script id="vs" type="x-shader/x-vertex">
        precision mediump float;

        uniform mat4 projMatrix;
        uniform mat4 viewMatrix;
        uniform mat4 modelMatrix;


        attribute vec3 pos;
        attribute vec3 color;
        varying vec3 fColor;

        void main()
        {
        fColor = color;
        vec4 pt = vec4(pos, 1.0);
        gl_Position = projMatrix * viewMatrix * modelMatrix * pt;
        }
    </script>

    <script id="fs" type="x-shader/x-fragment">
  precision mediump float;
    varying vec3 fColor;

  void main() 
    {
    gl_FragColor = vec4(fColor,1);
  }
  </script>

</head>

    <div id="main-div">

            <div id="viewport">
                <canvas id="can" >Your browser doesn't seem to support canvas!</canvas>
                <div class="slider">
                        <span class="slider-label">FOV cam</span>
                        <input id="fov" class="slider-input" type="range" min="20" max="90" step="1" value="0" onClick="fovChanged(this.id, this.value)" />
                        <span id="output-fov" class="slider-value">20</span>
                    </div>


                    <div class="slider">
                        <span class="slider-label">Far Plane</span>
                        <input id="far" class="slider-input" type="range" min="5" max="30" step="0.1" value="0"  onClick="farChanged(this.id, this.value)" />
                        <span id="output-far" class="slider-value">5</span>
                    </div>

            </div>

    </div>  

Я бы предложил эти статьи о матрицах в WebGL

Кроме того, пожалуйста, взгляните на то, как сделать ваш фрагмент доступным для выполнения, поскольку доступный для выполнения фрагмент намного полезнее.