为什么我使用GL.POINTS绘制的这些体素不对齐?我该如何解决?

时间:2019-05-28 01:39:42

标签: webgl

我一直在使用webgl开发体素引擎。它使用gl.points根据您到点的距离使用正方形绘制体素。

这是工作原理的基础

Vertex: 

//Get position using the projection matrix and block XYZ 
gl_Position =  uMatrix * uModelMatrix * vec4(aPixelPosition[0],-aPixelPosition[2],aPixelPosition[1],1.0);

//Set size of point based on screen height and divide it by depth to size based on distance
gl_PointSize = (uScreenSize[1]) / gl_Position[2];

这是从非问题角度看的样子。

enter image description here

您可以看到,它看起来就像我想要的样子(当然不如真实的立方体,但在移动设备上的瓶坯却令人赞叹),现在让我们进入这个空心的立方体,看看它是什么样子。这张照片是我看着角落里的

enter image description here

我更改了背景颜色以突出显示该问题。基本上,如果您直接查看这些块,它们会很好地工作,但是如果它们与您成一定角度,它们会很小并且会留有很大的空隙。这张照片是我直接看着墙壁

enter image description here

您可以看到面向后墙效果很好,但其他所有墙面看起来都很糟糕。

很明显,我在做错事,或者没有正确考虑某事。我尝试了很多不同的方法来尝试和修复它,但是我的修复均无法正常工作。

我尝试过使它朝着屏幕边缘变大,这解决了问题,但同时也使不必要的块变大了。就像看平墙一样,即使看平墙都没有问题,边缘也会变得更大。

我也尝试过扩大正方形并对此进行了修复,但随后它们在各处重叠并且看起来不那么干净。

您可以在此处看到问题的示例(仅需一秒钟即可生成结构)  https://sebastian97.itch.io/voxel-glitchy WASD运动 箭头键/鼠标-外观

1 个答案:

答案 0 :(得分:0)

假设您分离出投影矩阵,我想您想成为gl_PointSize

vec4 modelViewPosition = view * model * position;

gl_PointSize = someSize / -modelViewPosition.z;

gl_Position = projection * modelViewPosition;

'use strict';

/* global window, twgl, requestAnimationFrame, document */

const height = 120;
const width = 30
const position = [];
const color = [];
const normal = [];
for (let z = 0; z < width; ++z) {
  for (let x = 0; x < width; ++x) {
    position.push(x, 0, z);
    color.push(r(0.5), 1, r(0.5));
    normal.push(0, 1, 0);
  }
}
for (let y = 1; y < height ; ++y) {
  for (let x = 0; x < width; ++x) {
    position.push(x, -y, 0);
    color.push(0.6, 0.6, r(0.5));
    normal.push(0, 0, -1);
    
    position.push(x, -y, width - 1);
    color.push(0.6, 0.6, r(0.5));
    normal.push(0, 0, 1);
    
    position.push(0, -y, x);
    color.push(0.6, 0.6, r(0.5));
    normal.push(-1, 0, 0);
    
    position.push(width - 1, -y, x);
    color.push(0.6, 0.6, r(0.5));
    normal.push(1, 0, 0);
  }
}

function r(min, max) {
  if (max === undefined) {
    max = min;
    min = 0;
  }
  return Math.random() * (max - min) + min;
}

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

const vs = `
attribute vec4 position;
attribute vec3 normal;
attribute vec3 color;

uniform mat4 projection;
uniform mat4 modelView;

varying vec3 v_normal;
varying vec3 v_color;

void main() {
  vec4 modelViewPosition = modelView * position;
  gl_Position = projection * modelViewPosition;
  gl_PointSize = 850.0 / -modelViewPosition.z;
  v_normal = mat3(modelView) * normal;
  v_color = color;
}
`;

const fs = `
precision highp float;

varying vec3 v_normal;
varying vec3 v_color;

void main() {
  vec3 lightDirection = normalize(vec3(1, 2, 3));  // arbitrary light direction
  
  float l = dot(lightDirection, normalize(v_normal)) * .5 + .5;
  gl_FragColor = vec4(v_color * l, 1);
}
`;

// compile shader, link, look up locations
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);

// make some vertex data
const bufferInfo = twgl.createBufferInfoFromArrays(gl, {
  position,
  normal,
  color: { numComponents: 3, data: color },
});

const keys = [];
const eye = [10, 10, 55];
const target = [0, 0, 0];
const up = [0, 1, 0];
const speed = 50;

const kUp = 38;
const kDown = 40;
const kLeft = 37;
const kRight = 39;
const kForward = 87;
const kBackward = 83;
const kSlideLeft = 65;
const kSlideRight = 68;

const keyMove = new Map();
keyMove.set(kForward,    { ndx: 8, eye:  1, target: -1 });
keyMove.set(kBackward,   { ndx: 8, eye:  1, target:  1 });
keyMove.set(kSlideLeft,  { ndx: 0, eye:  1, target: -1 });
keyMove.set(kSlideRight, { ndx: 0, eye:  1, target:  1 });
keyMove.set(kLeft,       { ndx: 0, eye:  0, target: -1 });
keyMove.set(kRight,      { ndx: 0, eye:  0, target:  1 });
keyMove.set(kUp,         { ndx: 4, eye:  0, target: -1 });
keyMove.set(kDown,       { ndx: 4, eye:  0, target:  1 });

let then = 0;
function render(time) {
  time *= 0.001;  // seconds
  const deltaTime = time - then;
  then = time;
  
  twgl.resizeCanvasToDisplaySize(gl.canvas);
  
  gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
  gl.enable(gl.DEPTH_TEST);
  gl.enable(gl.CULL_FACE);
  
  const fov = Math.PI * 0.25;
  const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
  const near = 0.1;
  const far = 1000;
  const projection = m4.perspective(fov, aspect, near, far);
  
  const camera = m4.lookAt(eye, target, up);
  const view = m4.inverse(camera);
  const modelView = m4.translate(view, [width / -2, 0, width / -2]);
  
  keyMove.forEach((move, key) => {
    if (keys[key]) {
      const dir = camera.slice(move.ndx, move.ndx + 3);
 	    const delta = v3.mulScalar(dir, deltaTime * speed * move.target);
	    v3.add(target, delta, target);
			if (move.eye) {
		   v3.add(eye, delta, eye);
      }    
    }
  });

  gl.useProgram(programInfo.program);
  
  // calls gl.bindBuffer, gl.enableVertexAttribArray, gl.vertexAttribPointer
  twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
  
  // calls gl.activeTexture, gl.bindTexture, gl.uniformXXX
  twgl.setUniforms(programInfo, {
    projection,
    modelView,
  });  
  
  // calls gl.drawArrays or gl.drawElements
  twgl.drawBufferInfo(gl, bufferInfo, gl.POINTS);

  requestAnimationFrame(render);
}
requestAnimationFrame(render);

window.addEventListener('keydown', (e) => {
  e.preventDefault();
  keys[e.keyCode] = true;
});
window.addEventListener('keyup', (e) => {
  keys[e.keyCode] = false;
});
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
#i { position: absolute; top: 0; left: 5px; font-family: monospace; }
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
<canvas></canvas>
<div id="i">ASWD ⬆️⬇️⬅️➡️</div>