在WebGL中使用gl.POINTS绘制点时如何忽略间隙?

时间:2019-06-26 09:48:09

标签: javascript opengl-es webgl webgl2

var gl, canvas;

const FLOAT_SIZE = 4;

var handleWebGLError = function (type, obj) {
	if (type === 'shader') {
		if (!gl.getShaderParameter(obj, gl.COMPILE_STATUS)) {
			console.error(gl.getShaderInfoLog(obj));
			return null;
		}
	} else if (type === 'program') {
		if (!gl.getProgramParameter(obj, gl.LINK_STATUS)) {
			console.error(gl.getProgramInfoLog(obj));
			return null;
		}
	}
	
};

var getAndCompileShaders = function (id, type) {
	var shader = gl.createShader(type);
	var shaderText = document.getElementById(id).text.trim();
	gl.shaderSource(shader, shaderText);
	gl.compileShader(shader);
	handleWebGLError('shader', shader);
	return shader;
};

var getProgram = function (vsId, fsId, use) {
	var vs = getAndCompileShaders(vsId, gl.VERTEX_SHADER);
	var fs = getAndCompileShaders(fsId, gl.FRAGMENT_SHADER);
	var program = gl.createProgram();
	gl.attachShader(program, vs);
	gl.attachShader(program, fs);
	gl.linkProgram(program);
	handleWebGLError('program', program);
	if (use) {
		gl.useProgram(program);
	}
	return program;
};

var createBuffer = function (gl, coords, isStatic) {
	var b = gl.createBuffer();
	gl.bindBuffer(gl.ARRAY_BUFFER, b);
	gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(coords), isStatic ? gl.STATIC_DRAW : gl.DYNAMIC_DRAW);
	return b;
};

var createBuffers = function (gl, coordsArr, isStatic) {
	var bufferArr = [];
	coordsArr.forEach (function (coords) {
		var b = gl.createBuffer();
		gl.bindBuffer(gl.ARRAY_BUFFER, b);
		gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(coords), isStatic ? gl.STATIC_DRAW : gl.DYNAMIC_DRAW);
		bufferArr.push(b);
	});
	return bufferArr;
};

var initWebGLCanvas = function (canvasId) {
	canvas = document.getElementById(canvasId);
	canvas.width = window.innerWidth * 0.90;
	canvas.height = window.innerHeight * 0.90;
	//get Context
	var gl = canvas.getContext('webgl2');
	//assign a default color 
	gl.clearColor(0.002, 0.12, 0.3, 1.0);
	gl.clear(gl.COLOR_BUFFER_BIT);
	return gl;
};

var clearCanvas = function (gl) {
	gl.clearColor(0.002, 0.12, 0.3, 1.0);
	gl.clear(gl.COLOR_BUFFER_BIT);
}

var fetchDataFromGPUAndRenderTrianglesToCanvas = function (o, gl) {
	o.buffer.forEach (function (data) {
		gl.bindBuffer(gl.ARRAY_BUFFER, data);
		gl.vertexAttribPointer(o.positionIndex, o.positionSize, gl.FLOAT, gl.FALSE, o.stride*FLOAT_SIZE, o.positionOffset*FLOAT_SIZE);
		gl.vertexAttribPointer(o.colorIndex, o.colorSize, gl.FLOAT, gl.FALSE, o.stride*FLOAT_SIZE, o.colorOffset*FLOAT_SIZE); 
		gl.drawArrays(gl.TRIANGLES, o.startIndexToDraw, o.numOfComponents);
	});
};

var fetchDataFromGPUAndRenderToCanvas = function (o, gl) {
	o.buffer.forEach (function (data) {
		gl.bindBuffer(gl.ARRAY_BUFFER, data);
        gl.vertexAttribPointer(o.positionIndex, o.positionSize, gl.FLOAT, gl.FALSE,
             (o.stride || 0)*FLOAT_SIZE, (o.colorOffset || 0)*FLOAT_SIZE);
        o.uniforms.forEach (function (uniform) {
            gl.uniform1f(gl.getUniformLocation(gl.program, uniform.key), uniform.value);
        });
		gl.drawArrays(o.drawingType, o.startIndexToDraw, o.numOfComponents);
	});
};

var enableVerticesToPickBinaryDataWithinGPU = (position, color) => {
    if (position) {
        gl.positionIndex = gl.getAttribLocation(gl.program, position);
        gl.enableVertexAttribArray(gl.positionIndex);
    }

    if (color) {
        gl.colorIndex = gl.getAttribLocation(gl.program, color);
	    gl.enableVertexAttribArray(gl.colorIndex);
    }
};

var getSampleTriangleUsingPoints = () => {
    //left
    var triangleVertices = new Float32Array(20 + 2 + 20 + 20);
    for (var i = 0; i < 19; i = i + 2) {
        var lastX = i === 0 ? -1.1 : triangleVertices[i - 2];
        var lastY = i === 0 ? -1.2 : triangleVertices[i - 1];
        triangleVertices[i] = lastX + 0.1;
        triangleVertices[i + 1] = lastY + 0.2;
    }
	//top
	triangleVertices[20] = 0.0; triangleVertices[21] = 1.0; 

	//right
    for (var i = 22; i < 40; i = i + 2) {
        triangleVertices[i] = triangleVertices[i - 2] + 0.1;
        triangleVertices[i + 1] = triangleVertices[i - 1] - 0.2;
	}
	
	triangleVertices[40] = 1.0; triangleVertices[41] = -1.0; 
	
	//bottom
	var x = -1.0, y = -1.0;
	for (var i = 42; i <= 60; i = i + 2) {
		if (i !== 42) {
			x += 0.2;
		}
		triangleVertices[i] = x;
        triangleVertices[i + 1] = y;
	}
    
	//allocate a memory in GPU
	var verticesBuffer = gl.createBuffer();
	//link CPU variable to point to GPU using gl.ARRAY_BUFFER gate
	gl.bindBuffer(gl.ARRAY_BUFFER, verticesBuffer);
	//Send data to the memory location allocated above, gl.STATIC_DRAW means vertices won't be changed later and GPU will store the vertices far from the CPU.
    gl.bufferData(gl.ARRAY_BUFFER, triangleVertices, gl.STATIC_DRAW);
    return verticesBuffer;
}

var getBufferUsingPoints = function (points) {
    var f32a = new Float32Array(points);
    //allocate a memory in GPU
	var verticesBuffer = gl.createBuffer();
	//link CPU variable to point to GPU using gl.ARRAY_BUFFER gate
	gl.bindBuffer(gl.ARRAY_BUFFER, verticesBuffer);
	//Send data to the memory location allocated above, gl.STATIC_DRAW means vertices won't be changed later and GPU will store the vertices far from the CPU.
    gl.bufferData(gl.ARRAY_BUFFER, f32a, gl.STATIC_DRAW);
    return verticesBuffer;
};


document.addEventListener('DOMContentLoaded', function () {
	//resize canvas
	gl = initWebGLCanvas('canvas');
	gl.program = getProgram('vertexShader', 'fragmentShader', true);
	
	clearCanvas(gl);
	var isDragging = false;
	var points = [];
	var clear = document.getElementById('clear');
	clear.onclick = () => {
		points = [];
		clearCanvas(gl);
	};

	canvas.onmouseup = (e) => {
		isDragging = false;
	};

	canvas.onmouseout = (e) => {
		isDragging = false;
	};

	canvas.onmousedown = (e) => {
		isDragging = true;
	};

	canvas.onmousemove = (e) => {
		if (isDragging) {
			clearCanvas(gl);
			enableVerticesToPickBinaryDataWithinGPU('position');
			points.push(-1.0 + e.offsetX/canvas.width*2.0, 1.0 - e.offsetY/canvas.height*2.0);
			var pointsBuffer = getBufferUsingPoints(points);
			fetchDataFromGPUAndRenderToCanvas({
				positionIndex : gl.positionIndex,
				buffer : [pointsBuffer],
				positionSize : 2,
				uniforms : [{key : 'vSize', value : 1/canvas.width}],
				startIndexToDraw : 0,
				numOfComponents : points.length/2,
				drawingType : gl.POINTS
			}, gl);
		}
	};
});
<canvas id="canvas"></canvas>
	<button id="clear">Clear</button>
  
  <script type="vertexShader" id="vertexShader">
	#version 300 es
	in vec2 position;
	in vec4 color;
	out vec4 fcolor;
	uniform float vSize;
	void main () {
        gl_Position = vec4(position, 0.0, 1.0);
        gl_PointSize = 1.0;
		fcolor = color;
	}
</script>

<script type="fragmentShader" id="fragmentShader">
	#version 300 es
	precision mediump float;
	in vec4 fcolor;
	out vec4 finalColor;
	void main () {
		finalColor = vec4(0.0, 1.0, 0.0, 1.0);
	}
</script>

我试图在WebGL中实现一个解决方案,在该解决方案中,我能够通过拖动鼠标动态绘制点。但是,如果我拖动得太快,我会看到点之间的间隙,如果我使用gl_PointSize来增加点的大小,则确实会增加点的大小并节省了间隙,但是我认为这是不对的。

我们可以尝试其他方法来完全渲染点吗?

0 个答案:

没有答案