Visualizing Drillhole information

I would like to add a drillhole (from surface going down into the ground) to my scene that would carry different information on sections/segments of the drillhole (picture 1). The drillhole itself is a polyline but I would like the user to be able to visualize it based on any shape (tube, cylinder, polygone, etc.)

This is what I tried :

Option 1 : create a spline (new THREE.CatmullRomCurve3) using the coordinates for each point making the segments and use the extrude functionality. The problem with this method is that If I want to color code the segments based on some attribute (N-index or R-index - Picture 2), it’s almost impossible because the drillhole is considered as 1 object

Option 2: create multiple lines that could be extruded and visualize the data (color coding) based on the attributes associated with the lines.
I don’t like this option because it doesn’t consider the drillhole as one 3D object

Any thoughts on how to build this, What would be the best option to use ?

Thank you

Picture 1

Picture 2

Could anybody help on this ?

Would InstancedMesh work for this ? Would I be able to have several lines (representing segments) with userData for each line ?

Thank you very much

Hi Everybody,

I would really appreciate it if someone could help provide some insights into this.

I’m not asking for the whole code. I’m only asking for the methodology and the tools that ThreeJS can offer to model this.

I really appreciate any help I can get


As I see it, you just need a cylinder and a texture.

You have to make an off-screen canvas, at a high-aspect ratio rectangular shape, and then draw the background color, and straight lines vertically to the longer dimension.
In fact canvas lines are inappropriate, because their apparent position is affected by their width. The way to do it is via fillRect(), because the ring width isn’t affected by any other factor than the coordinates.

Then wrap it on a cylinder/catmulrom3/etc, and have your perfect tube-like shape with all your information.

Every time you want to update your info-tube, you’ll just have to draw on the offscreen canvas, create an image, assign it to a texture, update the texture, assign it to a material as map, update the material and your changes will be apparent to that tube.

I was in the mood, so here is a rough cylinder-based example (the rings are auto-stacked based on their width) - I made it thick to have a better view of the (few) lines.

const geo = new THREE.CylinderGeometry( 32, 32, 512, 64, 64, false);
const cmat = new THREE.MeshBasicMaterial( );
// cmat.transparent = true; 
cmat.side = THREE.DoubleSide;
const m = new THREE.Mesh( geo, cmat );
scene.add( m );

//_________ CANVAS _______________
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
const w = 64;
const h = 4096;
ctx.canvas.width = w;
ctx.canvas.height = h;
var img, tex;
var startpos = 0.0; 
var defwidth = 0.01;//default width


function drawtext(){
	ctx.clearRect(0, 0, w, h);//just clear without fill to make the plain's background transparent
	ctx.fillStyle = "#cccccc"; // ***
	ctx.fillRect(0, 0, w, h);  // ***

    // replace these lines with smarter code
	infoLineDraw(startpos, 2, "#ffff00");
	infoLineDraw(startpos, 1, "#ff0000");
	infoLineDraw(startpos, 2, "#ff8800");
	infoLineDraw(startpos, 1, "#0000ff");

	img = ctx.getImageData(0, 0, w, h);	
	tex = new THREE.Texture(img);
	tex.needsUpdate = true; = tex;
	m.material.needsUpdate = true;

// position, width, color
function infoLineDraw(rpos, rw, color){
	let wd = defwidth*rw;
	ctx.fillStyle = color;
	ctx.fillRect(0, h*rpos, w, h*wd);
	startpos += wd;

Note: If you omit the two lines marked as // *** and uncomment the third line from the top, your tube will become transparent and you’ll only have rings in the air. For that look, and if you leave space between the rings, you also need to make the material ‘THREE.DoubleSide’.

P.S I have also planned a few ambitious information-visualization projects - after a couple of lighter, gaming ones. :slightly_smiling_face:

I forgot to mention the number one advantage of using drawing functions instead of attaching eg cylinder rings with different colors, one on top of the other:
With pure geomerty-based composition you’ll get strong, ugly aliasing artifacts on the rings and then you’ll need the best (and slowest) anti-aliasing shader to filter them out, that ultimately will blur the thin rings and will defeat the purpose, while with drawing functions you get automatic, cheap antialiasing.

EDIT (correction):
For a 4096px resolution texture by 64 you have a memory footprint equivalent of just 512x512px and even if you double that, you only double the height’s resolution -just 1024*512px footprint (albeit I would avoid going higher than 4096 for possible compatibility issues with some mobile devices).

Hi dllb,

Thank you so much for your answer and for your help.

You have just made my week !

I will try it and give feedback !

Thank you for sharing your knowledge

A very imperfect option with two textures (data + color):

1 Like

This is Awesome !!
Thanks for sharing prisoner849 !

Could you please explain the functionality of sampler2D ?
uniform sampler2D texData;
uniform sampler2D texColor;
Is it a ramdom sampling method ? I would’ve thought that the colors would correspond to the values of texData, meaning blue for low and red for high values. When I read the randomly generated values of texData, they don’t correspond to the legend.