Какой эффективный способ остановить эти перекрытия прозрачности в webgl? - PullRequest
0 голосов
/ 30 сентября 2018

Я хотел бы сделать так, чтобы все эти блоки были нарисованы на одном слое, а не весь этот слой стал прозрачным.Или, если есть способ, которым я могу использовать функции смешивания или альфа-смешивания, это тоже будет хорошо.Большое спасибо.

1 Ответ

0 голосов
/ 02 октября 2018

Какое у вас определение эффективности?При каких обстоятельствах?Какие условия?

Вот несколько решений.Трудно сказать, подходят ли они без подробностей.

Сначала давайте повторим проблему

const m4 = twgl.m4;
const gl = document.querySelector('canvas').getContext('webgl');
const vs = `
attribute vec4 position;
uniform mat4 u_matrix;
void main() {
  gl_Position = u_matrix * position;
}
`;

const fs = `
precision mediump float;
void main() {
  gl_FragColor = vec4(0, .5, 0, .5);
}
`;

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

// create buffers and upload vertex data
const bufferInfo = twgl.primitives.createCubeBufferInfo(gl, 1);

render();
function render() {
  gl.clearColor(0, .4, 0, 1);
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
  
  gl.enable(gl.BLEND);
  gl.enable(gl.CULL_FACE);
  gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
  
  gl.useProgram(programInfo.program);

  const halfHeight = 1;
  const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
  const halfWidth = halfHeight * aspect;
  const projection = m4.ortho(
    -halfWidth, halfWidth, -halfHeight, halfWidth, 0.1, 20);

  const camera = m4.lookAt(
    [5, 2, 5],  // eye
    [0, -.5, 0],  // target
    [0, 1, 0],  // up
  );
  const view = m4.inverse(camera);
  const viewProjection = m4.multiply(projection, view);

  twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
  for (let x = -1; x <= 1; ++x) {
    let mat = m4.translate(viewProjection, [x, 0, 0]);
    twgl.setUniforms(programInfo, {
      u_matrix: mat,
    });
    // calls drawArrays or drawElements
    twgl.drawBufferInfo(gl, bufferInfo);
  }
}
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
<canvas></canvas>

Обратите внимание, что приведенный выше пример просто очищает фон до [0, .4, 0, 1], который темно-зеленый.Затем он рисует 3 куба, используя [0, .5, 0, .5], который полностью зеленый (как в [0, 1, 0, 1]), за исключением предварительно умноженного на 50% альфа.Используя предварительно умноженные цвета, смешивание устанавливается на gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA) Отбор лица включен.

Что касается решений с макушки головы, глядя на ваше изображение, вы можете

Рисовать спереди назад с помощью z-тест по

const m4 = twgl.m4;
const gl = document.querySelector('canvas').getContext('webgl');
const vs = `
attribute vec4 position;
uniform mat4 u_matrix;
void main() {
  gl_Position = u_matrix * position;
}
`;

const fs = `
precision mediump float;
void main() {
  gl_FragColor = vec4(0, .5, 0, .5);
}
`;

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

// create buffers and upload vertex data
const bufferInfo = twgl.primitives.createCubeBufferInfo(gl, 1);

render();
function render() {
  gl.clearColor(0, .4, 0, 1);
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
  
  gl.enable(gl.BLEND);
  gl.enable(gl.CULL_FACE);
  gl.enable(gl.DEPTH_TEST);
  
  gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
  
  gl.useProgram(programInfo.program);

  const halfHeight = 1;
  const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
  const halfWidth = halfHeight * aspect;
  const projection = m4.ortho(
    -halfWidth, halfWidth, -halfHeight, halfWidth, 0.1, 20);

  const camera = m4.lookAt(
    [5, 2, 5],  // eye
    [0, -.5, 0],  // target
    [0, 1, 0],  // up
  );
  const view = m4.inverse(camera);
  const viewProjection = m4.multiply(projection, view);
  
  twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
  for (let x = 1; x >= -1; --x) {
    let mat = m4.translate(viewProjection, [x, 0, 0]);
    twgl.setUniforms(programInfo, {
      u_matrix: mat,
    });
    // calls drawArrays or drawElements
    twgl.drawBufferInfo(gl, bufferInfo);
  }
}
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
<canvas></canvas>

Обратите внимание, что единственными изменениями в верхней версии являются добавление

 gl.enable(gl.DEPTH_TEST);

и рисование в обратном порядке

 for (let x = 1; x >= -1; --x) {

Понятия не имею, как хранятся ваши данные.Предполагая, что это сетка, вам нужно написать код для итерации по сетке в правильном порядке с точки зрения камеры.

В вашем примере показан только зеленый фон, поэтому вы можете просто рисовать непрозрачно и умножать или смешиватьцветом, таким же, как ваш фон.

const m4 = twgl.m4;
const gl = document.querySelector('canvas').getContext('webgl');
const vs = `
attribute vec4 position;
uniform mat4 u_matrix;
void main() {
  gl_Position = u_matrix * position;
}
`;

const fs = `
precision mediump float;
uniform vec4 u_backgroundColor;
uniform float u_mixAmount;
void main() {
  gl_FragColor = mix(vec4(0, 1, 0, 1), u_backgroundColor, u_mixAmount);
}
`;

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

// create buffers and upload vertex data
const bufferInfo = twgl.primitives.createCubeBufferInfo(gl, 1);

render();
function render() {
  gl.clearColor(0, .4, 0, 1);
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
  
  gl.enable(gl.CULL_FACE);
  gl.enable(gl.DEPTH_TEST);
  
  gl.useProgram(programInfo.program);

  const halfHeight = 1;
  const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
  const halfWidth = halfHeight * aspect;
  const projection = m4.ortho(
    -halfWidth, halfWidth, -halfHeight, halfWidth, 0.1, 20);

  const camera = m4.lookAt(
    [5, 2, 5],  // eye
    [0, -.5, 0],  // target
    [0, 1, 0],  // up
  );
  const view = m4.inverse(camera);
  const viewProjection = m4.multiply(projection, view);
  
  twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
  for (let x = 1; x >= -1; --x) {
    let mat = m4.translate(viewProjection, [x, 0, 0]);
    twgl.setUniforms(programInfo, {
      u_matrix: mat,
      u_backgroundColor: [0, 0.4, 0, 1],
      u_mixAmount: 0.5,
    });
    // calls drawArrays or drawElements
    twgl.drawBufferInfo(gl, bufferInfo);
  }
}
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
<canvas></canvas>

Приведенное выше решение изменяет фрагментный шейдер на

uniform vec4 u_backgroundColor;
uniform float u_mixAmount;
void main() {
  gl_FragColor = mix(vec4(0, 1, 0, 1), u_backgroundColor, u_mixAmount);
}

Где vec4(0, 1, 0, 1) - зеленый цвет куба.Затем мы устанавливаем u_backgroundColor, чтобы соответствовать цвету фона 0, .4, 0, 1, и устанавливаем u_mixAmount на .5 (50%)

. Это решение может показаться глупым, но обычно желание исчезнутьна цвет фона, который в основном, как туман работает.На самом деле вы не делаете вещи более прозрачными на расстоянии, вы просто рисуете цветом тумана.

рисуете все плитки без прозрачности в другую текстуру, а затем рисуете эту текстуру с прозрачностью

const m4 = twgl.m4;
const gl = document.querySelector('canvas').getContext('webgl', {alpha: false});
const vs = `
attribute vec4 position;
uniform mat4 u_matrix;
void main() {
  gl_Position = u_matrix * position;
}
`;

const fs = `
precision mediump float;
void main() {
  gl_FragColor = vec4(0, 1, 0, 1);
}
`;

const mixVs = `
attribute vec4 position;
attribute vec2 texcoord;
uniform mat4 u_matrix;
varying vec2 v_texcoord;
void main() {
  gl_Position = u_matrix * position;
  v_texcoord = texcoord;
}
`;

const mixFs = `
precision mediump float;
varying vec2 v_texcoord;
uniform sampler2D u_tex;
uniform float u_alpha;
void main() {
  gl_FragColor = texture2D(u_tex, v_texcoord) * u_alpha;
}
`;

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

// create buffers and upload vertex data
const bufferInfo = twgl.primitives.createCubeBufferInfo(gl, 1);
const xyQuadBufferInfo = twgl.primitives.createXYQuadBufferInfo(gl);

// create framebuffer with RGBA/UNSIGNED_BYTE texture
// and depth buffer renderbuffer that matches the size 
// of the canvas
const fbi = twgl.createFramebufferInfo(gl);

render();

function render() {
  renderTiles();
  renderScene();
}

function renderScene() {
  // bind canvas and set viewport
  twgl.bindFramebufferInfo(gl, null);
  gl.clearColor(0, 0.4, 0, 1);
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

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

  gl.useProgram(mixProgramInfo.program);
  twgl.setBuffersAndAttributes(gl, mixProgramInfo, xyQuadBufferInfo);
  twgl.setUniforms(mixProgramInfo, {
    u_matrix: m4.identity(),
    u_tex: fbi.attachments[0],  // the texture
    u_alpha: .5,
  });
  // calls drawArrays or drawElements
  twgl.drawBufferInfo(gl, xyQuadBufferInfo);
}

function renderTiles() {
  // bind framebuffer and set viewport
  twgl.bindFramebufferInfo(gl, fbi);
  gl.clearColor(0, 0, 0, 0);
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

  gl.disable(gl.BLEND);
  gl.enable(gl.CULL_FACE);
  gl.enable(gl.DEPTH_TEST);
  
  gl.useProgram(programInfo.program);

  const halfHeight = 1;
  const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
  const halfWidth = halfHeight * aspect;
  const projection = m4.ortho(
    -halfWidth, halfWidth, -halfHeight, halfWidth, 0.1, 20);

  const camera = m4.lookAt(
    [5, 2, 5],  // eye
    [0, -.5, 0],  // target
    [0, 1, 0],  // up
  );
  const view = m4.inverse(camera);
  const viewProjection = m4.multiply(projection, view);
  
  twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
  for (let x = 1; x >= -1; --x) {
    let mat = m4.translate(viewProjection, [x, 0, 0]);
    twgl.setUniforms(programInfo, {
      u_matrix: mat,
      u_backgroundColor: [0, 0.4, 0, 1],
      u_mixAmount: 0.5,
    });
    // calls drawArrays or drawElements
    twgl.drawBufferInfo(gl, bufferInfo);
  }
}
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
<canvas></canvas>

Приведенное выше изменение создает текстуру RGBA и буфер рендеринга глубины того же размера, что и холст, и присоединяет их к буферу кадров.Затем он рендерит плитки в эту текстуру непрозрачно.Затем он рендерит текстуру поверх холста с 50% альфа.Обратите внимание, что холст сам по себе установлен на {alpha: false}, чтобы холст не смешивался с элементами позади него.

Создание новой геометрии без скрытых поверхностей

Проблемаэто твой рисунок 3 кубика и края между ними.Решение, подобное Minecraft, вероятно, будет генерировать новую геометрию, которая не имеет внутренних краев.Было бы довольно легко пройтись по сетке плиток и решить, следует ли добавить этот край куба, основываясь на том, есть сосед или нет.

В Minecraft они должны генерировать новую геометрию только тогда, когда блокидобавляются или удаляются с использованием некоторого творческого кодирования, которое может включать в себя только изменение нескольких вершин, а не восстановление всей сетки.Они также, вероятно, генерируют в области размером с 64x64x64.

...