Какое у вас определение эффективности?При каких обстоятельствах?Какие условия?
Вот несколько решений.Трудно сказать, подходят ли они без подробностей.
Сначала давайте повторим проблему
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.