Webgl, как справиться с порядком рисования в 3d - PullRequest
0 голосов
/ 12 июня 2018

Итак, я начал реализовывать 3D-рендеринг в своем движке, рисование одного куба прекрасно работает.Все грани корректно отображаются и проверка глубины включена.Проблема в том, что у моего движка рендеринга есть система рендеринга слоев, их порядок хранится в зацикленном массиве.Так, например, я помещаю, например, 10 3d-боксов рядом друг с другом на один и тот же слой, и камера не будет знать, какой из них визуализировать первым.

enter image description here

Каждая 3d-рамкавизуализируется отдельно друг от друга, и перемещение камеры не меняет порядок рендеринга.Тест глубины включен.Реализация алгоритма рисования кажется слишком сложной для системы, есть ли способ, которым WebGL может справиться с этим?

1 Ответ

0 голосов
/ 14 июня 2018

Глубинное тестирование - это то, как WebGL управляет видимостью.Я не уверен, как вы справляетесь с этим в вашем движке, но вы, возможно, где-то допустили ошибку.

Ниже я привел пример, который может поставить вас на правильный путь.

var sgl = function() {
	
	"use strict";
	
	var gl = null;
	var programs = [];
	var buffers = [];
	var textures = [];
	
	addEventListener("unload",function() {
		for (var i = 0; i < programs.length; ++i) {
			gl.deleteProgram(programs[i]);
		}
		
		for (var i = 0; i < buffers.length; ++i) {
			gl.deleteBuffer(buffers[i]);
		}
		
		for (var i = 0; i < textures.length; ++i) {
			gl.deleteTexture(textures[i]);
		}
		
		gl = null;
	});
	
	return {
		set ctx(_gl) {
			if (_gl instanceof WebGLRenderingContext) {
				gl = _gl;
			}
		},
		
		createProgram: function(vc,fc) {
			if (!gl) {
				return null;
			}
			
			var vs = gl.createShader(gl.VERTEX_SHADER);
			var fs = gl.createShader(gl.FRAGMENT_SHADER);
			
			gl.shaderSource(vs,vc);
			gl.shaderSource(fs,fc);
			gl.compileShader(vs);
			gl.compileShader(fs);
			
			try {
				if (!gl.getShaderParameter(vs,gl.COMPILE_STATUS)) {
					throw "VS: " + gl.getShaderInfoLog(vs);
				}
				
				if (!gl.getShaderParameter(fs,gl.COMPILE_STATUS)) {
					throw "FS: " + gl.getShaderInfoLog(fs);
				}
			} catch(log) {
				gl.deleteShader(vs);
				gl.deleteShader(fs);
				console.error(log);
			}
			
			var p = gl.createProgram();
			
			gl.attachShader(p,vs);
			gl.attachShader(p,fs);
			gl.linkProgram(p);
			gl.deleteShader(vs);
			gl.deleteShader(fs);
			
			programs.push(p);
			
			return p;
		},
		
		createIndexBuffer: function(d) {
			d = d instanceof Uint16Array ? d : new Uint16Array(d);
			
			var b = gl.createBuffer();
			
			gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,b);
			gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,d,gl.STATIC_DRAW);
			
			buffers.push(b);
			
			return b;
		},
		
		createVertexBuffer: function(d) {
			d = d instanceof Float32Array ? d : new Float32Array(d);
			
			var b = gl.createBuffer();
			
			gl.bindBuffer(gl.ARRAY_BUFFER,b);
			gl.bufferData(gl.ARRAY_BUFFER,d,gl.STATIC_DRAW);
			
			buffers.push(b);
			
			return b;
		},
		
		createTexture: function(pixels,width,height) {
			var t = gl.createTexture();
			
			gl.activeTexture(gl.TEXTURE0);
			gl.bindTexture(gl.TEXTURE_2D,t);
			gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.NEAREST);
			gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.NEAREST);
			gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_S,gl.CLAMP_TO_EDGE);
			gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_T,gl.CLAMP_TO_EDGE);
			gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,width,height,0,gl.RGBA,gl.UNSIGNED_BYTE,pixels);
			
			textures.push(t);
			
			return t;
		}
	};
	
}();

void function() {
	
	"use strict";
	
	var canvasWidth = 180;
	var canvasHeight = 160;
	var canvas = null;
	var gl = null;
	
	var program = null;
	
	var uLightDir = null;
	var uModel = null;
	var uView = null;
	var uProj = null;
	var uTexture = null;
	
	var buffer = null;
	var texture = null;
	
	var modelMatrix = mat4.create();
	var viewMatrix = mat4.create();
	var projMatrix = mat4.perspective(
		mat4.create(),
		1.0472,
		canvasWidth / canvasHeight,
		1.0,
		100.0
	);
	
	var instances = [];
	var cameraAngle = 0.0;
	var cameraDistance = 15.0;
	var light = vec3.create();
	var camera = vec3.fromValues(0,0,5);
	var center = vec3.fromValues(0,0,0);
	var up = vec3.fromValues(0,1,0);
	
	onload = function() {
		canvas = document.getElementById("canvas");
		canvas.width = canvasWidth;
		canvas.height = canvasHeight;
		
		gl = canvas.getContext("webgl") || console.error("WebGL Not Supported.");
		
		sgl.ctx = gl;
		
		program = sgl.createProgram(`
			precision lowp float;
			
			const vec4 LIGHT_DIR = vec4(0.0,0.0,1.0,0.0);
			
			attribute vec3 aPosition;
			attribute vec3 aNormal;
			attribute vec2 aUV;
			
			varying float vDiffuse;
			varying vec2 vUV;
			
			uniform vec3 uLightDir;
			uniform mat4 uModel;
			uniform mat4 uView;
			uniform mat4 uProj;
			
			void main() {
				vUV = aUV;
				vDiffuse = max(0.4,dot(vec4(uLightDir,0.0),(uModel * vec4(aNormal,0.0))));
				gl_Position = uProj * uView * uModel * vec4(aPosition,1.0);
			}
		`,`
			precision lowp float;
			
			varying float vDiffuse;
			varying vec2 vUV;
			
			uniform sampler2D uTexture;
			
			void main() {
				gl_FragColor = texture2D(uTexture,vUV) * vDiffuse;
			}
		`);
		
		uLightDir = gl.getUniformLocation(program,"uLightDir");
		uModel = gl.getUniformLocation(program,"uModel");
		uView = gl.getUniformLocation(program,"uView");
		uProj = gl.getUniformLocation(program,"uProj");
		uTexture = gl.getUniformLocation(program,"uTexture");
		
		buffer = sgl.createVertexBuffer([
			// Position 	  Normal		 UV
			
			// Front
			 1.0, 1.0, 1.0,  0.0, 0.0, 1.0,  1.0,0.0,
			-1.0, 1.0, 1.0,  0.0, 0.0, 1.0,  0.0,0.0,
			-1.0,-1.0, 1.0,  0.0, 0.0, 1.0,  0.0,1.0,
			
			-1.0,-1.0, 1.0,  0.0, 0.0, 1.0,  0.0,1.0,
			 1.0,-1.0, 1.0,  0.0, 0.0, 1.0,  1.0,1.0,
			 1.0, 1.0, 1.0,  0.0, 0.0, 1.0,  1.0,0.0,
			
			// Back
			-1.0,-1.0,-1.0,  0.0, 0.0,-1.0,  1.0,0.0,
			-1.0, 1.0,-1.0,  0.0, 0.0,-1.0,  0.0,0.0,
			 1.0, 1.0,-1.0,  0.0, 0.0,-1.0,  0.0,1.0,
			
			 1.0, 1.0,-1.0,  0.0, 0.0,-1.0,  0.0,1.0,
			 1.0,-1.0,-1.0,  0.0, 0.0,-1.0,  1.0,1.0,
			-1.0,-1.0,-1.0,  0.0, 0.0,-1.0,  1.0,0.0,
			
			// Left
			-1.0, 1.0, 1.0, -1.0, 0.0, 0.0,  0.0,0.0,
			-1.0,-1.0,-1.0, -1.0, 0.0, 0.0,  1.0,1.0,
			-1.0,-1.0, 1.0, -1.0, 0.0, 0.0,  0.0,1.0,
			
			-1.0, 1.0, 1.0, -1.0, 0.0, 0.0,  0.0,0.0,
			-1.0, 1.0,-1.0, -1.0, 0.0, 0.0,  1.0,0.0,
			-1.0,-1.0,-1.0, -1.0, 0.0, 0.0,  1.0,1.0,
			
			// Right
			 1.0,-1.0, 1.0,  1.0, 0.0, 0.0,  1.0,0.0,
			 1.0,-1.0,-1.0,  1.0, 0.0, 0.0,  0.0,0.0,
			 1.0, 1.0, 1.0,  1.0, 0.0, 0.0,  1.0,1.0,
			
			 1.0,-1.0,-1.0,  1.0, 0.0, 0.0,  0.0,0.0,
			 1.0, 1.0,-1.0,  1.0, 0.0, 0.0,  1.0,0.0,
			 1.0, 1.0, 1.0,  1.0, 0.0, 0.0,  1.0,1.0,
			
			// Top
			 1.0, 1.0,-1.0,  0.0, 1.0, 0.0,  1.0,0.0,
			-1.0, 1.0,-1.0,  0.0, 1.0, 0.0,  0.0,0.0,
			 1.0, 1.0, 1.0,  0.0, 1.0, 0.0,  1.0,1.0,
			 
			 1.0, 1.0, 1.0,  0.0, 1.0, 0.0,  1.0,1.0,
			-1.0, 1.0,-1.0,  0.0, 1.0, 0.0,  0.0,0.0,
			-1.0, 1.0, 1.0,  0.0, 1.0, 0.0,  0.0,1.0,
			
			// Bottom
			 1.0,-1.0, 1.0,  0.0,-1.0, 0.0,  1.0,1.0,
			-1.0,-1.0,-1.0,  0.0,-1.0, 0.0,  0.0,0.0,
			 1.0,-1.0,-1.0,  0.0,-1.0, 0.0,  1.0,0.0,
			
			-1.0,-1.0, 1.0,  0.0,-1.0, 0.0,  0.0,1.0,
			-1.0,-1.0,-1.0,  0.0,-1.0, 0.0,  0.0,0.0,
			 1.0,-1.0, 1.0,  0.0,-1.0, 0.0,  1.0,1.0
		]);
		
		var width = 10;
		var height = 10;
		var pixels = new Uint8Array((width * height) << 2);
		
		for (var i = 0; i < pixels.length; i += 4) {
			var c = Math.random() < 0.5 ? 255 : 0;
			
			pixels[i + 0] = c;
			pixels[i + 1] = c;
			pixels[i + 2] = c;
			pixels[i + 3] = 255;
		}
		
		for (var x = 0; x < width; ++x) {
			var index = x << 2;
			
			pixels[index + 0] = 255;
			pixels[index + 1] = 255;
			pixels[index + 2] = 0;
			pixels[index + 3] = 255;
			
			index = (x + (height - 1) * width) << 2;
			
			pixels[index + 0] = 255;
			pixels[index + 1] = 255;
			pixels[index + 2] = 0;
			pixels[index + 3] = 255;
		}
		
		for (var y = 0; y < height; ++y) {
			var index = (y * width) << 2;
			
			pixels[index + 0] = 255;
			pixels[index + 1] = 255;
			pixels[index + 2] = 0;
			pixels[index + 3] = 255;
			
			index = ((width - 1) + y * width) << 2;
			
			pixels[index + 0] = 255;
			pixels[index + 1] = 255;
			pixels[index + 2] = 0;
			pixels[index + 3] = 255;
		}
		
		texture = sgl.createTexture(pixels,width,height);
		
		gl.useProgram(program);
		gl.bindBuffer(gl.ARRAY_BUFFER,buffer);
		gl.vertexAttribPointer(0,3,gl.FLOAT,false,32,0);
		gl.vertexAttribPointer(1,3,gl.FLOAT,false,32,12);
		gl.vertexAttribPointer(2,2,gl.FLOAT,false,32,24);
		gl.enableVertexAttribArray(0);
		gl.enableVertexAttribArray(1);
		gl.enableVertexAttribArray(2);
		
		gl.activeTexture(gl.TEXTURE0);
		gl.bindTexture(gl.TEXTURE_2D,texture);
		
		gl.enable(gl.CULL_FACE);
		gl.enable(gl.DEPTH_TEST);
		
		gl.clearColor(0.5,0.5,0.5,1.0);
		
		gl.uniformMatrix4fv(uModel,false,modelMatrix);
		gl.uniformMatrix4fv(uView,false,viewMatrix);
		gl.uniformMatrix4fv(uProj,false,projMatrix);
		
		var size = 5;
		var hSize = size >> 1;
		
		for (var x = -hSize << 1; x <= hSize << 1; x += 2) {
			for (var y = -hSize << 1; y <= hSize << 1; y += 2) {
				for (var z = -hSize << 1; z <= hSize << 1; z += 2) {
					if (Math.random() < 0.3) {
						instances.push(vec3.fromValues(x,y,z));
					}
				}
			}
		}
		
		loop();
	}
	
	function loop() {
		cameraAngle += 0.01;
		
		if (cameraAngle > 2.0 * Math.PI) {
			cameraAngle = 0.0;
		}
		
		camera[0] = Math.cos(cameraAngle) * cameraDistance;
		camera[1] = 1.0;
		camera[2] = Math.sin(cameraAngle) * cameraDistance;
		
		gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
		
		vec3.sub(light,camera,center);
		vec3.normalize(light,light);
		gl.uniform3fv(uLightDir,light);
		
		mat4.lookAt(viewMatrix,camera,center,up);
		gl.uniformMatrix4fv(uView,false,viewMatrix);
		
		for (var i = 0; i < instances.length; ++i) {
			mat4.fromTranslation(modelMatrix,instances[i]);
			gl.uniformMatrix4fv(uModel,false,modelMatrix);
			gl.drawArrays(gl.TRIANGLES,0,36);
		}
		
		requestAnimationFrame(loop);
	}
	
}();
body {
	background-color: black;
}

canvas {
	display: block;
	margin: 30px auto 0px auto;
	border: solid 1px white;
	border-radius: 10px;
}

script {
	display: none;
}
<!doctype html>
<html>
	<head>
		<meta charset="utf-8">
	</head>
	<body>
    <script type="application/javascript" src="https://cdn.rawgit.com/toji/gl-matrix/8226d776/dist/gl-matrix-min.js"></script>
		<canvas id="canvas"></canvas>
	</body>
</html>
...