web画布上同一画布上的两个相等的对象(拆分模式)

时间:2019-04-06 16:36:18

标签: javascript canvas webgl

我尝试在拆分屏幕中使用同一对象(一个简单的多维数据集)。 最初,我使用两个不同的程序创建两个画布,并使用同一点渲染两次多维数据集。 显然没有用,我在Topic上读到我不能这样做。

答案建议使用

  

使用gl.enable(gl.SCISSOR_TEST),gl.scissor和   gl.viewport

我对这些东西不熟悉,我不知道该怎么做。

他也提出了一个例子,但是非常复杂,我不明白。

我的示例非常简单,我只想绘制两个具有不同投影的立方体(从相同点开始),以便实时查看不同投影之间的差异。

有人可以帮助我吗?

编辑:根据Gman的建议,我以这种方式编辑代码

window.onload = function init() {

    canvas = document.getElementById( "gl-canvas" );

    gl = WebGLUtils.setupWebGL( canvas );
    if ( !gl ) { alert( "WebGL isn't available" ); }

   //4
    const width = gl.canvas.width;
    const height = gl.canvas.height;
    const displayWidth = gl.canvas.clientWidth;
    const displayHeight = gl.canvas.clientHeight;




 gl.clearColor( 1.0, 1.0, 1.0, 1.0 );

    gl.viewport( 0, 0, canvas.width, canvas.height );

    gl.enable(gl.DEPTH_TEST);

//
//  Load shaders and initialize attribute buffers
//
program = initShaders( gl, "vertex-shader", "fragment-shader" );
gl.useProgram( program );

colorCube();



render(0, 0, width / 2, height, displayWidth / 2, displayHeight);

// draw on right
render(width / 2, 0, width / 2, height, displayWidth / 2, displayHeight);

而渲染功能是

var render = function(drawX, drawY, drawWidth, drawHeight, dispWidth, dispHeight) {



eye = vec3(radius*Math.sin(phi), radius*Math.sin(theta),radius*Math.cos(phi));


gl.enable(gl.SCISSOR_TEST);
gl.viewport(drawX, drawY, drawWidth, drawHeight);
gl.scissor(drawX, drawY, drawWidth, drawHeight);

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


mvMatrix = lookAt(eye, at , up);
const aspect = dispWidth / dispHeight;



pMatrix = ortho(left, right, bottom, ytop, near, far);


gl.uniformMatrix4fv( modelView, false, flatten(mvMatrix) );
gl.uniformMatrix4fv( projection, false, flatten(pMatrix) );




gl.drawArrays( gl.TRIANGLES, 0, numVertices );


//requestAnimFrame(render);

}

如果我不删除requestAnimFrame,我仅会看到2个立方体,毕竟将被删除。

1 个答案:

答案 0 :(得分:2)

使用gl.viewportgl.scissor没什么困难

典型的WebGL程序会执行此操作

gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);

const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;

const projection = someProjectionFunction(fieldOfView, aspect, zNear, zFar)

... draw stuff ...

因此,我们将其更改为采用投影的函数

function render(drawX, drawY, drawWidth, projection) {
   gl.viewport(drawX, drawY, drawWidth, drawHeight);

   ... draw stuff ...
}

我们现在可以这样称呼

const width = gl.canvas.width;
const height = gl.canvas.height;
const displayWidth = gl.canvas.clientWidth;
const displayHeight = gl.canvas.clientHeight;

const aspect = displayWidth / displayHeight;

const projection = someProjectionFunction(fieldOfView, aspect, zNear, zFar)

// draw on left
render(0, 0, width / 2, height, projection);

// draw on right
render(width / 2, 0, width / 2, height, projection);

已经处理了viewport部分,并且可以正常工作。剩下的就是剪刀

function render(drawX, drawY, drawWidth, drawHeight, projection) {
   gl.viewport(drawX, drawY, drawWidth, drawHeight);
   gl.scissor(drawX, drawY, drawWidth, drawHeight);
   gl.enable(gl.SCISSOR_TEST);

   ... draw stuff using projection ...
}

现在更新它可以传递更多信息,例如不同的投影或不同的相机

const gl = document.querySelector('canvas').getContext('webgl');
const m4 = twgl.m4;

const vs = `
attribute vec4 position;
uniform mat4 matrix;
void main() {
  gl_Position = matrix * position;
}
`;
const fs = `
precision mediump float;
void main() {
  gl_FragColor = vec4(1, 0, 0, 1);
}
`;

const program = twgl.createProgram(gl, [vs, fs]);
const posLoc = gl.getAttribLocation(program, 'position');
const matLoc = gl.getUniformLocation(program, 'matrix');

const buf = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buf);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
  -1, -1, -1, 
   1, -1, -1,
  -1,  1, -1,
   1,  1, -1,
  -1, -1,  1, 
   1, -1,  1,
  -1,  1,  1,
   1,  1,  1,
]), gl.STATIC_DRAW);

const indices = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indices);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array([
  0, 1, 1, 3, 3, 2, 2, 0,
  4, 5, 5, 7, 7, 6, 6, 4,
  0, 4, 1, 5, 3, 7, 2, 6,
]), gl.STATIC_DRAW);

function renderLoop(time) {
  time *= 0.001;
  
  function render(drawX, drawY, drawWidth, drawHeight, projection) {
     gl.viewport(drawX, drawY, drawWidth, drawHeight);
     gl.scissor(drawX, drawY, drawWidth, drawHeight);
     gl.enable(gl.SCISSOR_TEST);
     
     gl.clear(gl.COLOR_BUFFER_BIT);
     
     let mat = m4.copy(projection);
     mat = m4.translate(mat, [0, 0, -5]);
     mat = m4.rotateZ(mat, time);
     mat = m4.rotateX(mat, time * 0.5);
     gl.useProgram(program);
     gl.uniformMatrix4fv(matLoc, false, mat);
     gl.enableVertexAttribArray(posLoc);
     gl.bindBuffer(gl.ARRAY_BUFFER, buf);
     gl.vertexAttribPointer(posLoc, 3, gl.FLOAT, false, 0, 0);
     gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indices);
     gl.drawElements(gl.LINES, 24, gl.UNSIGNED_SHORT, 0);
  }

  const width = gl.canvas.width;
  const height = gl.canvas.height;
  const displayWidth = gl.canvas.clientWidth;
  const displayHeight = gl.canvas.clientHeight;

  // draw on left
  {
    const drawX = 0;
    const drawY = 0;
    const drawWidth = width / 2;
    const drawHeight = height;
    const dispWidth = displayWidth / 2;
    const dispHeight = displayHeight;
    
    const fieldOfView = 45 * Math.PI / 180;
    const aspect = dispWidth / dispHeight;
    const zNear = 0.1;
    const zFar = 20;
    const projection = m4.perspective(fieldOfView, aspect, zNear, zFar)

    gl.clearColor(1, 1, 0, 1);
    render(drawX, drawY, drawWidth, drawHeight, projection);
  }

  // draw on right
  {
    const drawX = width / 2;
    const drawY = 0;
    const drawWidth = width / 2;
    const drawHeight = height;
    const dispWidth = displayWidth / 2;
    const dispHeight = displayHeight;
  
    const aspect = dispWidth / dispHeight;
    const top = 2;
    const bottom = -top;
    const right = top * aspect;
    const left = -right;
    const zNear = 0.1;
    const zFar = 20;
    
    const projection = m4.ortho(left, right, bottom, top, zNear, zFar);
    gl.clearColor(0, 1, 1, 1);
    render(drawX, drawY, drawWidth, drawHeight, projection);
  }

  requestAnimationFrame(renderLoop);
}
requestAnimationFrame(renderLoop);
<canvas></canvas>
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>

使用书本示例的示例

"use strict";

var canvas;
var gl;

var NumVertices  = 36;

var pointsArray = [];
var colorsArray = [];

var vertices = [
    vec4(-0.5, -0.5,  1.5, 1.0),
    vec4(-0.5,  0.5,  1.5, 1.0),
    vec4(0.5,  0.5,  1.5, 1.0),
    vec4(0.5, -0.5,  1.5, 1.0),
    vec4(-0.5, -0.5, 0.5, 1.0),
    vec4(-0.5,  0.5, 0.5, 1.0),
    vec4(0.5,  0.5, 0.5, 1.0),
    vec4( 0.5, -0.5, 0.5, 1.0)
];

var vertexColors = [
    vec4( 0.0, 0.0, 0.0, 1.0 ),  // black
    vec4( 1.0, 0.0, 0.0, 1.0 ),  // red
    vec4( 1.0, 1.0, 0.0, 1.0 ),  // yellow
    vec4( 0.0, 1.0, 0.0, 1.0 ),  // green
    vec4( 0.0, 0.0, 1.0, 1.0 ),  // blue
    vec4( 1.0, 0.0, 1.0, 1.0 ),  // magenta
    vec4( 0.0, 1.0, 1.0, 1.0 ),  // cyan
    vec4( 1.0, 1.0, 1.0, 1.0 ),  // white
];


var near = 0.3;
var far = 3.0;
var radius = 4.0;
var theta  = 0.0;
var phi    = 0.0;
var dr = 5.0 * Math.PI/180.0;

var  fovy = 45.0;  // Field-of-view in Y direction angle (in degrees)
var  aspect;       // Viewport aspect ratio

var mvMatrix, pMatrix;
var modelView, projection;
var eye;
const at = vec3(0.0, 0.0, 0.0);
const up = vec3(0.0, 1.0, 0.0);

function quad(a, b, c, d) {
     pointsArray.push(vertices[a]);
     colorsArray.push(vertexColors[a]);
     pointsArray.push(vertices[b]);
     colorsArray.push(vertexColors[a]);
     pointsArray.push(vertices[c]);
     colorsArray.push(vertexColors[a]);
     pointsArray.push(vertices[a]);
     colorsArray.push(vertexColors[a]);
     pointsArray.push(vertices[c]);
     colorsArray.push(vertexColors[a]);
     pointsArray.push(vertices[d]);
     colorsArray.push(vertexColors[a]);
}


function colorCube()
{
    quad( 1, 0, 3, 2 );
    quad( 2, 3, 7, 6 );
    quad( 3, 0, 4, 7 );
    quad( 6, 5, 1, 2 );
    quad( 4, 5, 6, 7 );
    quad( 5, 4, 0, 1 );
}


function init() {

    canvas = document.getElementById( "gl-canvas" );

    gl = WebGLUtils.setupWebGL( canvas );
    if ( !gl ) { alert( "WebGL isn't available" ); }

    gl.viewport( 0, 0, canvas.width, canvas.height );

    aspect =  canvas.width/canvas.height;

    gl.clearColor( 1.0, 1.0, 1.0, 1.0 );

    gl.enable(gl.DEPTH_TEST);


    //
    //  Load shaders and initialize attribute buffers
    //
    var program = initShaders( gl, "vertex-shader", "fragment-shader" );
    gl.useProgram( program );

    colorCube();

    var cBuffer = gl.createBuffer();
    gl.bindBuffer( gl.ARRAY_BUFFER, cBuffer );
    gl.bufferData( gl.ARRAY_BUFFER, flatten(colorsArray), gl.STATIC_DRAW );

    var vColor = gl.getAttribLocation( program, "vColor" );
    gl.vertexAttribPointer( vColor, 4, gl.FLOAT, false, 0, 0 );
    gl.enableVertexAttribArray( vColor);

    var vBuffer = gl.createBuffer();
    gl.bindBuffer( gl.ARRAY_BUFFER, vBuffer );
    gl.bufferData( gl.ARRAY_BUFFER, flatten(pointsArray), gl.STATIC_DRAW );

    var vPosition = gl.getAttribLocation( program, "vPosition" );
    gl.vertexAttribPointer( vPosition, 4, gl.FLOAT, false, 0, 0 );
    gl.enableVertexAttribArray( vPosition );

    modelView = gl.getUniformLocation( program, "modelView" );
    projection = gl.getUniformLocation( program, "projection" );
// buttons for viewing parameters

    document.getElementById("Button1").onclick = function(){near  *= 1.1; far *= 1.1;};
    document.getElementById("Button2").onclick = function(){near *= 0.9; far *= 0.9;};
    document.getElementById("Button3").onclick = function(){radius *= 2.0;};
    document.getElementById("Button4").onclick = function(){radius *= 0.5;};
    document.getElementById("Button5").onclick = function(){theta += dr;};
    document.getElementById("Button6").onclick = function(){theta -= dr;};
    document.getElementById("Button7").onclick = function(){phi += dr;};
    document.getElementById("Button8").onclick = function(){phi -= dr;};

    render();
}


var render = function(){

    function renderScene(drawX, drawY, drawWidth, drawHeight, pMatrix) {
      gl.enable(gl.SCISSOR_TEST);
      gl.viewport(drawX, drawY, drawWidth, drawHeight);
      gl.scissor(drawX, drawY, drawWidth, drawHeight);
      
      gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

      eye = vec3(radius*Math.sin(theta)*Math.cos(phi),
          radius*Math.sin(theta)*Math.sin(phi), radius*Math.cos(theta));
      mvMatrix = lookAt(eye, at , up);

      gl.uniformMatrix4fv( modelView, false, flatten(mvMatrix) );
      gl.uniformMatrix4fv( projection, false, flatten(pMatrix) );

      gl.drawArrays( gl.TRIANGLES, 0, NumVertices );
    }
    
    const width = gl.canvas.width;
    const height = gl.canvas.height;
    const displayWidth = gl.canvas.clientWidth;
    const displayHeight = gl.canvas.clientHeight;

    // draw left
    {
      const dispWidth = displayWidth / 2;
      const dispHeight = displayHeight;
      const aspect = dispWidth / dispHeight;
      const pMatrix = perspective(fovy, aspect, near, far);
      gl.clearColor(0.1, 0.1, 0.1, 1);
      renderScene(0, 0, width / 2, height, pMatrix);
    }
    
    // draw right
    {
      const dispWidth = displayWidth / 2;
      const dispHeight = displayHeight;
      const aspect = dispWidth / dispHeight;
      const top = 1;
      const bottom = -top;
      const right = top * aspect;
      const left = -right;
      const pMatrix = ortho(left, right, bottom, top,  near, far);
      gl.clearColor(0.2, 0.2, 0.2, 1);
      renderScene(width / 2, 0, width / 2, height, pMatrix);
    }

    requestAnimFrame(render);
}

init();
<p> </p>
<button id = "Button1">Increase Z</button>
<button id = "Button2">Decrease Z</button>
<button id = "Button3">Increase R</button>
<button id = "Button4">Decrease R</button>

<p> </p>
<button id = "Button5">Increase theta</button>
<button id = "Button6">Decrease theta</button>
<button id = "Button7">Increase phi</button>
<button id = "Button8">Decrease phi</button>
<p> </p>


<script id="vertex-shader" type="x-shader/x-vertex">
attribute  vec4 vPosition;
attribute  vec4 vColor;
varying vec4 fColor;
uniform mat4 modelView;
uniform mat4 projection;
void main() 
{
    gl_Position = projection*modelView*vPosition;
    fColor = vColor;
} 
</script>

<script id="fragment-shader" type="x-shader/x-fragment">
precision mediump float;
varying vec4 fColor;
void
main()
{
    gl_FragColor = fColor;
}
</script>

<script src="https://esangel.github.io/WebGL/Common/webgl-utils.js"></script>
<script src="https://esangel.github.io/WebGL/Common/initShaders.js"></script>
<script src="https://esangel.github.io/WebGL/Common/MV.js"></script>

<canvas id="gl-canvas" width="400" height="100"></canvas>