Combining custom webgl with ThreeJS

I have a webgl program that displays some information on the screen. I have provided an example (not functional) which demonstrates the kind of program I’m trying to integrate with Threejs. Please note the example serves as a generic template, I will need to combine Threejs with other types webgl programs (much more complicated). What is the general approach? Can multiple program objects with different shaders be used?

 var TEXT_VSHADER =
 	'attribute vec4 a_Position;\n' +
 	'attribute vec2 a_TexCoord;\n' +
 	'uniform mat4 u_ViewMatrix;\n' +
 	'uniform mat4 u_ModelMatrix;\n' +
 	'uniform mat4 u_ProjectionMatrix;\n' +
 	'varying vec2 v_TexCoord;\n' +
 	'void main() {\n' +
 	'  gl_Position =  a_Position * u_ViewMatrix;\n' +
 	'v_TexCoord = a_TexCoord;\n' +
 	'}\n';


 var TEXT_FSHADER =
 	'#ifdef GL_ES\n' +
 	'precision mediump float;\n' +
 	'#endif\n' +
 	'uniform sampler2D u_Sampler;\n' +
 	'uniform vec4 u_FragColor;\n' +
 	'varying vec2 v_TexCoord;\n' +
 	'void main() {\n' +
 	'  gl_FragColor = vec4(u_FragColor.rgb , u_FragColor.a);\n' +
 	'}\n';

 var canvas;
 var textCtx;

 function main() {

 	var elementArray = ['123', '246', '369'];
 	var vertices = new Float32Array([0.0, 0.5, 12.0, 12.5, 40.0, 45.5]);
 	var vshader;
 	var fshader;
 	var compiled;
 	var message;
 	var textProgram;
 	var linked;
 	var a_Position;
 	var u_FragColor;
 	var u_ViewMatrix;
 	var u_ProjectionMatrix;
 	var viewMatrix;
 	var vertexBuffer;
 	var textBufferInfo;


 	canvas = document.getElementById('webgl');


 	var gl = WebGLDebugUtils.makeDebugContext(canvas.getContext("webgl"));
 	textCtx = document.createElement("canvas").getContext("2d");

 	if (!gl) {
 		console.log('Failed to get the rendering context for WebGL');
 		return;
 	}



 	vshader = gl.createShader(gl.VERTEX_SHADER);
 	fshader = gl.createShader(gl.FRAGMENT_SHADER);


 	gl.shaderSource(vshader, TEXT_VSHADER);
 	gl.shaderSource(fshader, TEXT_FSHADER);

 	gl.compileShader(vshader);


 	compiled = gl.getShaderParameter(vshader, gl.COMPILE_STATUS);
 	if (!compiled) {
 		var error = gl.getShaderInfoLog(vshader);
 		console.log('Failed to compile shader: ' + error);
 		gl.deleteShader(vshader);
 		return null;
 	}

 	message = gl.getShaderInfoLog(vshader);

 	gl.compileShader(fshader);


 	compiled = gl.getShaderParameter(fshader, gl.COMPILE_STATUS);
 	if (!compiled) {
 		var error = gl.getShaderInfoLog(fshader);
 		console.log('Failed to compile shader: ' + error);
 		gl.deleteShader(fshader);
 		return null;
 	}


 	message = gl.getShaderInfoLog(fshader);

 	textProgram = gl.createProgram();

 	if (textProgram == null) {

 	}

 	gl.attachShader(textProgram, vshader);
 	gl.attachShader(textProgram, fshader);

 	gl.linkProgram(textProgram);

 	linked = gl.getProgramParameter(textProgram, gl.LINK_STATUS);
 	if (!linked) {
 		var error = gl.getProgramInfoLog(textProgram);
 		console.log('Failed to link program: ' + error);
 		gl.deleteProgram(textProgram);
 		gl.deleteShader(fshader);
 		gl.deleteShader(vshader);

 	}

 	gl.useProgram(textProgram);
 	gl.program = textProgram;




 	viewMatrix = new Matrix4();
 	viewMatrix.setLookAt(0, 0, 0, 0, -1, 0, 0, 1, 0);

 	// ' u_FragColor = texture2D(u_Sampler, v_TexCoord);\n' +
 	u_FragColor = gl.getUniformLocation(gl.program, 'u_FragColor')

 	if (u_FragColor == null) {
 		console.log('Fail to get the storage location of u_FragColor')
 		return;
 	}

 	u_ViewMatrix = gl.getUniformLocation(gl.program, 'u_ViewMatrix')

 	if (u_ViewMatrix == null) {
 		console.log('Fail to get the storage location of u_ViewMatrix')
 		return;
 	}




 	gl.uniformMatrix4fv(u_ViewMatrix, false, viewMatrix.elements);

 	vertexBuffer = gl.createBuffer();

 	if (!vertexBuffer) {
 		console.log('Failed to create vertex buffer object');
 		return (-1);
 	}

 	gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
 	gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);


 	a_Position = gl.getAttribLocation(gl.program, 'a_Position');
 	if (a_Position < 0) {
 		console.log('Fail to get the storage location of a_Position')
 		return;
 	}

 	gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);


 	gl.enableVertexAttribArray(a_Position);



 	var textTextures = [
 		"0",
 		"1",
 		"2",
 		"3",
 		"4",
 		"5",
 		"6",
 		"7",
 		"8",
 		"9"
 	].map(function (elementArray) {
 		var textCanvas = makeTextCanvas(elementArray, 10, 26);
 		var textWidth = textCanvas.width;
 		var textHeight = textCanvas.height;
 		var elementIDtexture = gl.createTexture();
 		gl.bindTexture(gl.TEXTURE_2D, elementIDtexture);
 		gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
 		gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, textCanvas);

 		gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_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);
 		return {
 			texture: elementIDtexture,
 			width: textWidth,
 			height: textHeight,
 		};
 	});

 	//  gl.resizeCanvasToDisplaySize(gl.canvas); 


 	gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);

 	gl.enable(gl.CULL_FACE);
 	gl.enable(gl.DEPTH_TEST);
 	gl.disable(gl.BLEND);
 	gl.depthMask(true);


 	gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

 	//  gl.drawArrays(gl.TRIANGLES, 0, 3);
 	gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_SHORT, 0);

 }



 function makeTextCanvas(text, width, height) {
 	textCtx.canvas.width = width;
 	textCtx.canvas.height = height;
 	textCtx.font = "20px monospace";
 	textCtx.textAlign = "center";
 	textCtx.textBaseline = "middle";
 	textCtx.fillStyle = "black";
 	textCtx.clearRect(0, 0, textCtx.canvas.width, textCtx.canvas.height);
 	textCtx.fillText(text, width / 2, height / 2);
 	return textCtx.canvas;
 }

 main()

In general, you cannot easily combine custom WebGL calls with three.js in the same context (separate canvases may work, though). But the good news is you can easily replace all your WebGL calls with simpler three.js code in this case. The text canvas can be used as texture in three.js, and the shaders can also be used in three.js. The attributes and matrices look quite standard, and should be functionally replaced easily with three.js. That is, unless I overlooked something important when glancing over your code.

Well… :confused: :thinking:

2 Likes