如何在2d画布上绘制3d对象

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

这是完整的代码,我不得不从一些与问题无关的函数中删除空格,以确保im处于堆栈溢出的30k字符限制内

const EPSILON = 0.000001;
const mat4 = { rotateZ: function(out, a, rad) { let s = Math.sin(rad); let c = Math.cos(rad); let a00 = a[0]; let a01 = a[1]; let a02 = a[2]; let a03 = a[3]; let a10 = a[4]; let a11 = a[5]; let a12 = a[6]; let a13 = a[7]; if (a !== out) { out[8] = a[8]; out[9] = a[9]; out[10] = a[10]; out[11] = a[11]; out[12] = a[12]; out[13] = a[13]; out[14] = a[14]; out[15] = a[15]; } out[0] = a00 * c + a10 * s; out[1] = a01 * c + a11 * s; out[2] = a02 * c + a12 * s; out[3] = a03 * c + a13 * s; out[4] = a10 * c - a00 * s; out[5] = a11 * c - a01 * s; out[6] = a12 * c - a02 * s; out[7] = a13 * c - a03 * s; return out; }, create: function() { let out = new Float32Array(16); out[0] = 1; out[5] = 1; out[10] = 1; out[15] = 1; return out; }, perspective: function(out, fovy, aspect, near, far) { let f = 1.0 / Math.tan(fovy / 2), nf; out[0] = f / aspect; out[1] = 0; out[2] = 0; out[3] = 0; out[4] = 0; out[5] = f; out[6] = 0; out[7] = 0; out[8] = 0; out[9] = 0; out[11] = -1; out[12] = 0; out[13] = 0; out[15] = 0; if (far !== null && far !== Infinity) { nf = 1 / (near - far); out[10] = (far + near) * nf; out[14] = (2 * far * near) * nf; } else { out[10] = -1; out[14] = -2 * near; } return out; }, translate: function(out, a, v) { let x = v[0], y = v[1], z = v[2]; if (a === out) { out[12] = a[0] * x + a[4] * y + a[8] * z + a[12]; out[13] = a[1] * x + a[5] * y + a[9] * z + a[13]; out[14] = a[2] * x + a[6] * y + a[10] * z + a[14]; out[15] = a[3] * x + a[7] * y + a[11] * z + a[15]; return out; } else { let a00, a01, a02, a03; let a10, a11, a12, a13; let a20, a21, a22, a23; a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3]; a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7]; a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11]; out[0] = a00; out[1] = a01; out[2] = a02; out[3] = a03; out[4] = a10; out[5] = a11; out[6] = a12; out[7] = a13; out[8] = a20; out[9] = a21; out[10] = a22; out[11] = a23; out[12] = a00 * x + a10 * y + a20 * z + a[12]; out[13] = a01 * x + a11 * y + a21 * z + a[13]; out[14] = a02 * x + a12 * y + a22 * z + a[14]; out[15] = a03 * x + a13 * y + a23 * z + a[15]; return out; } }, scale: function(out, a, v) { let x = v[0], y = v[1], z = v[2]; out[0] = a[0] * x; out[1] = a[1] * x; out[2] = a[2] * x; out[3] = a[3] * x; out[4] = a[4] * y; out[5] = a[5] * y; out[6] = a[6] * y; out[7] = a[7] * y; out[8] = a[8] * z; out[9] = a[9] * z; out[10] = a[10] * z; out[11] = a[11] * z; out[12] = a[12]; out[13] = a[13]; out[14] = a[14]; out[15] = a[15]; return out; }, multiply: function(out, a, b) { let a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3]; let a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7]; let a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11]; let a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; let b0  = b[0], b1 = b[1], b2 = b[2], b3 = b[3]; out[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30; out[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31; out[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32; out[3] = b0*a03 + b1*a13 + b2*a23 + b3*a33; b0 = b[4]; b1 = b[5]; b2 = b[6]; b3 = b[7]; out[4] = b0*a00 + b1*a10 + b2*a20 + b3*a30; out[5] = b0*a01 + b1*a11 + b2*a21 + b3*a31; out[6] = b0*a02 + b1*a12 + b2*a22 + b3*a32; out[7] = b0*a03 + b1*a13 + b2*a23 + b3*a33; b0 = b[8]; b1 = b[9]; b2 = b[10]; b3 = b[11]; out[8] = b0*a00 + b1*a10 + b2*a20 + b3*a30; out[9] = b0*a01 + b1*a11 + b2*a21 + b3*a31; out[10] = b0*a02 + b1*a12 + b2*a22 + b3*a32; out[11] = b0*a03 + b1*a13 + b2*a23 + b3*a33; b0 = b[12]; b1 = b[13]; b2 = b[14]; b3 = b[15]; out[12] = b0*a00 + b1*a10 + b2*a20 + b3*a30; out[13] = b0*a01 + b1*a11 + b2*a21 + b3*a31; out[14] = b0*a02 + b1*a12 + b2*a22 + b3*a32; out[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33; return out; }, lookAt: function(out, eye, center, up) { let x0, x1, x2, y0, y1, y2, z0, z1, z2, len; let eyex = eye[0]; let eyey = eye[1]; let eyez = eye[2]; let upx = up[0]; let upy = up[1]; let upz = up[2]; let centerx = center[0]; let centery = center[1]; let centerz = center[2]; if (Math.abs(eyex - centerx) < EPSILON && Math.abs(eyey - centery) < EPSILON && Math.abs(eyez - centerz) < EPSILON) { return identity(out); } z0 = eyex - centerx; z1 = eyey - centery; z2 = eyez - centerz; len = 1 / Math.hypot(z0, z1, z2); z0 *= len; z1 *= len; z2 *= len; x0 = upy * z2 - upz * z1; x1 = upz * z0 - upx * z2; x2 = upx * z1 - upy * z0; len = Math.hypot(x0, x1, x2); if (!len) { x0 = 0; x1 = 0; x2 = 0; } else { len = 1 / len; x0 *= len; x1 *= len; x2 *= len; } y0 = z1 * x2 - z2 * x1; y1 = z2 * x0 - z0 * x2; y2 = z0 * x1 - z1 * x0; len = Math.hypot(y0, y1, y2); if (!len) { y0 = 0; y1 = 0; y2 = 0; } else { len = 1 / len; y0 *= len; y1 *= len; y2 *= len; } out[0] = x0; out[1] = y0; out[2] = z0; out[3] = 0; out[4] = x1; out[5] = y1; out[6] = z1; out[7] = 0; out[8] = x2; out[9] = y2; out[10] = z2; out[11] = 0; out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez); out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez); out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez); out[15] = 1; return out; }, moveToVec3: function(out, v) { out[12] = v[0]; out[13] = v[1]; out[14] = v[2]; } }; const mat3 = { clone: function(a) { let out = new Float32Array(9); out[0] = a[0]; out[1] = a[1]; out[2] = a[2]; out[3] = a[3]; out[4] = a[4]; out[5] = a[5]; out[6] = a[6]; out[7] = a[7]; out[8] = a[8]; return out; }, create: function() { let out = new Float32Array(9); out[0] = 1; out[4] = 1; out[8] = 1; return out; } }; const vec3 = { multiply: function(out, a, b) { out[0] = a[0] * b[0]; out[1] = a[1] * b[1]; return out; }, create: function() { return new Float32Array(3);; }, copy: function(out, a) { out[0] = a[0]; out[1] = a[1]; out[2] = a[2]; return out; } }; const vec2 = { create: function() { return new Float32Array(2);; }, copy: function(out, a) { out[0] = a[0]; out[1] = a[1]; return out; }, fromValues: function(x, y) { let out = new Float32Array(2); out[0] = x; out[1] = y; return out; }, multiply: function(out, a, b) { out[0] = a[0] * b[0]; out[1] = a[1] * b[1]; return out; }, add: function(out, a, b) { out[0] = a[0] + b[0]; out[1] = a[1] + b[1]; return out; } };
const FRAGMENT_SHADER = ` precision highp float; varying highp vec2 vTextureCoord; varying lowp vec4 vColor; uniform sampler2D uSampler; uniform bool aUseText; void main(void) { if( aUseText ){ gl_FragColor = texture2D(uSampler, vTextureCoord); } else { gl_FragColor = vColor; } } `;
const VERTEX_SHADER = ` attribute vec4 aVertexPosition; attribute vec4 aVertexColor; attribute vec2 aTextureCoord; uniform mat4 uModelViewMatrix; uniform mat4 uProjectionMatrix; uniform mat3 uTextMatrix; uniform float uPointSize; varying lowp vec4 vColor; varying highp vec2 vTextureCoord; void main(void) { gl_PointSize = uPointSize; gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition; vColor = aVertexColor; vTextureCoord = (vec3(aTextureCoord, 1)*uTextMatrix).xy; } `;

class WebglEntity {
    constructor() {
        this.matrix = mat4.create();
        this.coords = vec3.create();
    }
    translate(newCoords) {
        const {
            matrix,
            coords
        } = this;
        mat4.translate(matrix, matrix, newCoords);
        vec3.copy(coords, [matrix[12], matrix[13], matrix[14]]);

        return this;
    }
    move(newCoords) {
        const {
            matrix,
            coords
        } = this;
        vec3.copy(coords, newCoords);
        mat4.moveToVec3(matrix, coords);

        return this;
    }
}
class Camera extends WebglEntity {
    constructor(fieldOfView, aspect, zNear, zFar) {
      super();

      this.projection = mat4.perspective(mat4.create(), fieldOfView, aspect, zNear, zFar);

    }
    lookAt(lookAt) {
        const {
            matrix,
            projection,
            coords
        } = this;
        mat4.lookAt(matrix, coords, lookAt, [0, 1, 0]);
        mat4.multiply(matrix, projection, matrix);
        return this;
    }
}
class Rect extends WebglEntity{

  constructor(){

    super();

    this.positionsBuffer = undefined;
    this.fragColorPos = undefined;

    this.strokeColorPos = undefined;
    this.strokePositionBuffer = undefined;

    this.vertexAttribInfo = undefined;
    this.vertextColorAttribInfo = undefined;

    this.vertexCount = undefined;
    this.textureInfo = undefined;


    this.multiTextures = false;

    this.strokeSize = 1;
    this.fillers = {
      fill: false,
      texture: false,
      stroke: false
    };
  }
  setup(matrix, positionsBuffer,  strokePositionBuffer, vertexAttribInfo, vertextColorAttribInfo, vertexCount){

    this.matrix = matrix;

    this.positionsBuffer = positionsBuffer;
    this.strokePositionBuffer = strokePositionBuffer;

    this.vertexAttribInfo = vertexAttribInfo;
    this.vertextColorAttribInfo = vertextColorAttribInfo;

    this.vertexCount = vertexCount;

    return this;
  }

}

class Display{

 constructor(gl, programInfo, zAxis, texture){
   this.gl = gl;
   this.programInfo = programInfo;

   this.canvas = gl.canvas;

   this.currentCamera = new Camera(45 * Math.PI / 180, gl.canvas.width/gl.canvas.height, 0.1, 100.0);

   this.currentCamera.translate([0, 0, zAxis]).lookAt([0, 0, 0]);

   this.zAxis = zAxis;
   this.drawZAxis = 0;

   this.last = {};

   texture.textAttribInfo = {
     numComponents: 2,
     type: gl.FLOAT,
     normalize: false,
     stride: 0,
     offset: 0
   };

   this.texture = texture;
   this.spriteSheets = [];

   const context = texture.context;
   const canvas = texture.canvas;

   this.images = {};

 }


 clear(color){

   const gl = this.gl;

   gl.clearColor(0.1, 0.1, 0.1, 1);

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

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


 }

 rect(x, y, w, h){

   const {rect, stroke} = this.createRectPos(w, h);

   const square = new Rect();
   square.setup(...this.getRectInfo(x, y, rect, stroke));

   return square;
 }

 fillRect(rect, color){
   const {createStaticDrawBuffer, gl, parseColor} = this;

   rect.fillers.fill = true;

   if(color){
     rect.fragColorPos = createStaticDrawBuffer(gl, [0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1]);

   }
 }

 createRectPos(w, h){

   const rect = [ w/2,  h/2, -w/2,  h/2, w/2, -h/2, -w/2, -h/2 ];
   const stroke = [ -w/2,  h/2, w/2,  h/2, w/2, -h/2, -w/2, -h/2, ];
   return {rect, stroke};
 }

 getRectInfo(x, y, rect, stroke){
   return this.createSquareBuffer(rect, stroke, [x, y, this.drawZAxis]);
 }

 createStaticDrawBuffer(gl, data){

   const buffer = gl.createBuffer();
   gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
   gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(data), gl.STATIC_DRAW);

   return buffer;
 }

 createSquareBuffer(positions, strokePosition, coords) {
   const {gl, createStaticDrawBuffer} = this;

   const positionsBuffer      = createStaticDrawBuffer(gl, positions);
   const strokePositionBuffer = createStaticDrawBuffer(gl, strokePosition);
   const modelViewMatrix = mat4.create();

   mat4.translate(modelViewMatrix, modelViewMatrix, coords);

   return [modelViewMatrix, positionsBuffer, strokePositionBuffer, this.createAttribInfo(2, gl.FLOAT, false, 0, 0), this.createAttribInfo(4, gl.FLOAT, false, 0, 0), positions.length/2]; }

 createAttribInfo(numComponents, type, normalize, stride, offset){

   return { numComponents, type, normalize, stride, offset};
 }

 enableAttrib(buffer, attrib, gl, {numComponents, type, normalize, stride, offset}){

   gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
   gl.vertexAttribPointer(attrib, numComponents,type,normalize,stride,offset);
   gl.enableVertexAttribArray(attrib);

 }

 drawBuffer(buffer){

   const {gl, drawTexture, enableAttrib, createStaticDrawBuffer, currentCamera, texture: {context, canvas, textAttribInfo}, programInfo: {uniformLocations, program, attribLocations: {vertexPosition, vertexColor, textureCoord}}} = this;

   const cameraMatrix = currentCamera.matrix;

   const {positionsBuffer, fragColorPos, strokeColorPos, strokePositionBuffer, matrix, vertexAttribInfo, vertextColorAttribInfo, vertexCount, fragTextPos, fillers: {fill, stroke, texture}, strokeSize, textureInfo, multiTextures} = buffer;

   gl.uniformMatrix4fv(uniformLocations.projectionMatrix, false, cameraMatrix);
   gl.uniformMatrix4fv(uniformLocations.modelViewMatrix, false, matrix);

   if(fill){

     enableAttrib(positionsBuffer, vertexPosition, gl, vertexAttribInfo);
     enableAttrib(fragColorPos, vertexColor, gl, vertextColorAttribInfo);
     gl.drawArrays(gl.TRIANGLE_STRIP, 0, vertexCount);
     gl.disableVertexAttribArray(vertexColor);

   }

 }

 static loadShader(gl, program, type, source) {

   const shader = gl.createShader(type);
   gl.shaderSource(shader, source);
   gl.compileShader(shader);
   gl.attachShader(program, shader);

 }

 static async create(canvas, width, height, zAxis = 6){
   canvas.width  = width;
   canvas.height = height;

   const gl = canvas.getContext("webgl");

   const shaderProgram = gl.createProgram();

   Display.loadShader(gl, shaderProgram, gl.VERTEX_SHADER, VERTEX_SHADER);
   Display.loadShader(gl, shaderProgram, gl.FRAGMENT_SHADER, FRAGMENT_SHADER);

   gl.linkProgram(shaderProgram);

   const programInfo = {
     program: shaderProgram,
     attribLocations: {
       vertexPosition: gl.getAttribLocation(shaderProgram, 'aVertexPosition'),
       vertexColor: gl.getAttribLocation(shaderProgram, 'aVertexColor'),
       textureCoord: gl.getAttribLocation(shaderProgram, 'aTextureCoord'),


     },
     uniformLocations: {
       projectionMatrix: gl.getUniformLocation(shaderProgram, 'uProjectionMatrix'),
       modelViewMatrix: gl.getUniformLocation(shaderProgram, 'uModelViewMatrix'),
       textMatrix: gl.getUniformLocation(shaderProgram, 'uTextMatrix'),
       sampler: gl.getUniformLocation(shaderProgram, 'uSampler'),
       useText: gl.getUniformLocation(shaderProgram, 'aUseText'),
       pointSize: gl.getUniformLocation(shaderProgram, 'uPointSize'),
     },
   };

   gl.useProgram(programInfo.program);

   gl.uniform1f(programInfo.uniformLocations.pointSize, 1.0);

   gl.enable(gl.BLEND);
   gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);

   const textureBuffer = gl.createTexture();

   gl.activeTexture(gl.TEXTURE0);
   gl.bindTexture(gl.TEXTURE_2D, textureBuffer);
   gl.uniform1i(programInfo.uniformLocations.uSampler, 0);

   const textureCanvas = document.createElement("canvas");

   textureCanvas.width = 0;
   textureCanvas.height = 0;

   let texture = {
       canvas: textureCanvas,
       buffer: textureBuffer,
       context: textureCanvas.getContext("2d"),
     };

   return new Display(gl, programInfo, zAxis, texture);
 }
}

class Engine { constructor(time_step, update, render, allowedSkippedFrames) { this.accumulated_time = 0; this.animation_frame_request = undefined, this.time = undefined, this.time_step = time_step, this.updated = false; this.update = update; this.render = render; this.allowedSkippedFrames = allowedSkippedFrames; this.run = this.run.bind(this); this.end = false; } run(time_stamp) { const { accumulated_time, time, time_step, updated, update, render, allowedSkippedFrames, end } = this; this.accumulated_time += time_stamp - time; this.time = time_stamp; if (accumulated_time > time_stamp * allowedSkippedFrames) { this.accumulated_time = time_stamp; } while (this.accumulated_time >= time_step) { this.accumulated_time -= time_step; update(time_stamp); this.updated = true; } if (updated) { this.updated = false; render(time_stamp); } if (end) { return; } this.animation_frame_request = requestAnimationFrame(this.run); } start() { this.accumulated_time = this.time_step; this.time = performance.now(); this.animation_frame_request = requestAnimationFrame(this.run); } stop() { this.end = true; cancelAnimationFrame(this.animation_frame_request); } }

class Entity extends Rect {

  constructor(){

    super();

    this.velocity = vec2.create();
    this.area = undefined;
    this.mass = 2;

    this.updateFillers = {};
    this.delete = false;
    this.draw = true;
  }

  setup(w, h, ...args){
    this.area = vec2.fromValues(w, h);
    super.setup(...args);

    return this;
  }

  fill(...args){
    this.updateFillers.fill = args;
  }

  update(deltaTime, speed){

    return this;
  }

  move(x, y){

    super.move([x, y, this.coords[2]]);

    return this;

  }

}

class Quixotic{

  constructor(display){

    this.display = display;

    this.engine = undefined;

    this.render = undefined;
    this.update = undefined;
    this.frameRate = undefined;

    this.time = 0; this.speed = 1;
    this.world = {

      objects: {},
      objectsCollisionInfo: {},
      objectsArray: [],
      classesInfo: {}

    };

    this.timePassed = 0;

  }

  createEntity(Class, ...args){
    const display = this.display; const {rect, stroke} = display.createRectPos(5, 5); Class = Class ? Class : Entity; const className = Class.name; if(className !== "Entity" && !Entity.prototype.isPrototypeOf(Class.prototype)){ throw new TypeError("Expected extended class of Entity. Instead got: " + className); } let instance; const {objectsArray, classesInfo, objects} = this.world; const classInfo = classesInfo[className]; if(classInfo){ if(classInfo.args){ instance = new Class(...[...classInfo.args, ...args]); } else { instance = new Class(...args); } const name = classInfo.name; if(Array.isArray(objects[name])){ objects[name].push(instance); instance.name = name; } else { console.warn("Didn't save object in world.objects object, object wouldn't detect collision"); } } else { instance = new Class(...args); } instance.setup(5, 5, ...display.getRectInfo(0, 0, rect, stroke, "#000")); objectsArray.push(instance); return instance; }

  createBackground(objects){
    const buffer = document.createElement("canvas").getContext("2d");

    const bufferRect = this.createEntity();
    let {zAxis, canvas: {width, height}} = this.display;
    zAxis--;
    const halfZ = zAxis/2;
    let {coords: [x, y], area: [w, h]} = objects[objects.length - 1];

    let [mX, mY, mW, mH] = [x, y, w, h];
    for(let i = objects.length-1; i--;){

      const {coords: [_x, _y], area: [_w, _h]} = objects[i];
      x < _x ? _x : x;
      y < _y ? _y : y;

      if(mX < _x){
         mX = _x;
         mW = _w;
      }
      if(mY < _y){
         mY = _y;
         mH = _h;
       }
    }

    buffer.canvas.width = width;
    buffer.canvas.height = height;
    for(let i = objects.length; i--;){

      const {coords: [_x, _y], area: [_w, _h]} = objects[i];
      buffer.fillRect(((_x-halfZ-_w*2)/zAxis+1)*width, ((-_y-halfZ-_h*2)/zAxis+1)*height, _w*2/zAxis*width, _h*2/zAxis*height);
    }

    document.body.appendChild(buffer.canvas)

  }

  buildWorld({objects, classes, tileMap}){

    const world = this.world;

    if(Array.isArray(objects)){
      for(let i = objects.length - 1; i > -1; i --){
        const object = objects[i];
        const {name, array, amount, position, collision, args, area} = object;

        let createClass;

        if(!object.class){
          createClass = Entity;
        }

        const _args = args ? args : [];

        let pos;

        if(position){
            let p = amount;
            if(array){
              const positions = position.positions;
              pos = function(){
                p--;
                return positions[p];
              };
            } else {
              pos = function(){
                return position.position;
              };
            }
          }

        if(array){

          let _array = [];

          for(let j = amount; j--;){

            const instance = this.createEntity(createClass, ..._args);
            instance.name = name;

            if(position){
              instance.move(...pos());
            }

            if(area){

              instance.setSize(area);

            }
            _array.push(instance);
          }
          world.objects[name] = _array;
          world.objectsArray.push(..._array);

        }
      }
    }

    return;

  }

  setup(game){

    const {style: {backgroundColor, backgroundImage, stroke}, world, engine: {frameRate, update, render}, setup} = game; this.buildWorld(world); const {display, entitySystem, world: {objectsArray, objects}} = this; if(backgroundImage){ display.gl.canvas.style.background = `url(${backgroundImage})`; if(repeatX || repeatY){ console.log("not read yet"); } } this.frameRate = frameRate; let lastUpdated = 0; this.update = (time) =>{ let deltaTime = time - lastUpdated; lastUpdated = time; const speed = this.speed; this.timePassed += deltaTime*speed; for(let i = objectsArray.length; i--;){ const object = objectsArray[i]; if(object.delete){ objectsArray.splice(i, 1); } object.update(deltaTime/1000, speed); } update(deltaTime/1000, this); }; let lastRendered = 0; this.render = (timeStamp) => { const deltaTime = timeStamp - lastRendered; lastRendered = timeStamp; if(backgroundColor) display.clear(backgroundColor); const length = objectsArray.length; for(let i = objectsArray.length; i--; ){ const object = objectsArray[length - i - 1]; if(object.draw){ const updateFillers = Object.entries(object.updateFillers); const fillersLength = updateFillers.length; if(fillersLength){ for(let i = fillersLength; i--;){ const [func, args] = updateFillers[fillersLength - i - 1]; display[func + "Rect"](object, ...args); } object.updateFillers = {}; } display.drawBuffer(object); } } const speed = this.speed; const spriteSheets = display.spriteSheets; for(let i = spriteSheets.length; i--;){ spriteSheets[i].update(deltaTime/1000*speed); } render(display, this); }; setup(this, display, this.world); this.engine = new Engine(this.frameRate, this.update, this.render, 3); this.engine.start(); return game;
  }

  static async create({display: {canvas, width, height, zAxis}, homeURL}){

    const display = await Display.create(canvas, width, height, zAxis);

    return new Quixotic(display);
  }

}


const fps = document.querySelector("#fps");
const minLength = innerWidth > innerHeight ? innerHeight : innerWidth;
const game = {

  create: {

    display: {

      canvas: document.querySelector("#canvas"),
      zAxis: 96,
      width: minLength,
      height: minLength,

    },

    homeURL: "/src"
  },

  style: {
    backgroundColor: "#111122"
  },

  world: {
    objects: [
      {
        name: "trees",

        array: true,
        amount: 5,
        position: {
	         type: "set",
	         positions: [ [-37.5, 37.5], [0,0], [-37.5,-37.5], [37.5,-37.5], [37.5,37.5], [10,10], [15,10], [20,10], [25,10], [30,10]]

        }
      }
    ]
  },

  engine: {

    frameRate: 1000/30,

    update: function(deltaTime, engine){
      fps.innerText = 1/deltaTime;
    },

    render: function(display){}
  },

  setup: function(engine, display, {objects: {trees}}){

     trees.forEach(tree => {
       tree.fill("#00ff00")
     })
    engine.createBackground(trees);
  }

};



Quixotic.create(game.create)
  .then(engine => {

    engine.setup(game);
  });
 * {
         box-sizing:border-box;
         margin:0;
         padding:0;
    }
     body {
         background-color: #111c31;
         overflow: hidden;
         align-items:space-around;
         display:grid;
         height:100%;
         width:100%;
    }
     #canvas {
         background-color: #152646;
         /* justify-self: center; */
    }
    #fps {
      position: fixed;
      color: white;
      right: 0;
    }
    canvas {
      position: fixed
    }
   
<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title>webgl x 2dCanvas</title>
  </head>
  <body>
    <canvas id="canvas" width="300" height="300"></canvas>
    <p id = "fps"></p>
  </body>
</html>

这里是发生问题的第374行的代码

createBackground(objects){ //method
  const buffer = document.createElement("canvas").getContext("2d");

  const bufferRect = this.createEntity();
  let {zAxis, canvas: {width, height}} = this.display;
  zAxis--; //zAxis is where the camera is at, currently 96, but with webgl the objects have to be 1 point lower, so 95.

  const halfZ = zAxis/2;
  let {coords: [x, y], area: [w, h]} = objects[objects.length - 1];

  let [mX, mY, mW, mH] = [x, y, w, h];
  for(let i = objects.length-1; i--;){

    const {coords: [_x, _y], area: [_w, _h]} = objects[i];
    x < _x ? _x : x;
    y < _y ? _y : y;

    if(mX < _x){
       mX = _x;
       mW = _w;
    }
    if(mY < _y){
       mY = _y;
       mH = _h;
     }
  }

  buffer.canvas.width = ((mX-halfZ+mW*2)/zAxis+1)*width;
  buffer.canvas.height = ((mY-halfZ+mH*2)/zAxis+1)*height;

  for(let i = objects.length; i--;){

    const {coords: [_x, _y], area: [_w, _h]} = objects[i];
    buffer.fillRect(((_x-halfZ-_w*2)/zAxis+1)*width, ((_y-halfZ-_h*2)/zAxis+1)*height, _w*2/zAxis*width, _h*2/zAxis*height);
  }

  document.body.appendChild(buffer.canvas)

}

[我具有此功能,可以使用webgl在带有3个矢量和矩阵的3d世界中绘制的对象,基本上我可以将它们的所有位置和体积绘制到2d画布上,这是到目前为止我得到的结果] >

results, black squares not quit covering the green square

[绿色正方形是使用webgl绘制的,黑色正方形是在画布渲染2d上绘制的,最终结果应该是覆盖绿色正方形的黑色正方形,但我的数学位置不正确。

完整的代码可以在这里找到https://github.com/bahaaaldin214/Quixotic-Engine/tree/test

着色器在src / modules / webgl / shaders中

其他信息

相机位置:96,

绿色方块位置:

[
    [-37.5, 37.5], //bottom left
    [0,0], //center
    [-37.5,-37.5],  //top left
    [37.5,-37.5], //bottom right
    [37.5,37.5], //top right
]

这是完整的代码,我必须从一些与问题无关的函数中删除空格,以确保im处于堆栈溢出const EPSILON = 0.000001的30k字符限制内; ...

javascript canvas webgl
1个回答
0
投票

现在我已经看过代码了。首先,我很糟糕,但是我不清楚您应该发布minimal

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