For a recent project, I have been utilizing Three.js to create a unique point material object that users can interact with. My goal is to map the pixels of an image onto the vertices of a buffer geometry so that the image appears as a cluster of points resembling a point cloud. Specifically, I am working with a downscaled map of the Earth consisting of 106 x 53 pixels.
To achieve this effect, I start by drawing the image on a canvas, extracting the image data, determining the color based on the pixel coordinates, and then applying these colors to my geometry (a sphere buffer geometry in this case). However, it seems like something is off in my mapping process.
The snippet below illustrates how I extract colors and populate them in an array for the geometry:
let colors = [];
let color = new THREE.Color();
let positionAttribute = g.attributes.position;
for (let x = 0; x < img.width; x++) {
for (let y = 0; y < img.height; y++) {
let c = earthCanvas.getContext("2d");
let p = c.getImageData(x, y, 1, 1).data;
let hex = "#" + ("000000" + rgbToHex(p[0], p[1], p[2])).slice(-6);
color.set(hex);
colors.push(color.r, color.g, color.b);
}
}
g.setAttribute("color", new THREE.Float32BufferAttribute(colors, 3));
This method results in the following output: https://i.sstatic.net/Ki7fK.png
I wonder if there's a way to make this representation resemble the Earth as a globe. Could it be a matter of incorrectly assigning the pixel coordinates?
The code snippet responsible for the geometry setup looks like this:
g = new THREE.SphereBufferGeometry(3, 104, 52);
count = g.attributes.position.count;
console.log(count);
g.center();
let pointShape = new THREE.TextureLoader().load("./models/particle.png");
m = new THREE.PointsMaterial({
size: pointSize,
map: pointShape,
vertexColors: true,
depthTest: false,
opacity: 1
});
Here's the HTML and JavaScript snippet for the canvas:
function drawImageSource(source, canvas) {
img = new Image();
img.addEventListener("load", function () {
canvas
.getContext("2d")
.drawImage(
img,
0,
0,
img.width,
img.height,
0,
0,
canvas.width,
canvas.height
);
});
img.crossOrigin = "Anonymous";
img.setAttribute("src", source);
}
<div id="canvasDiv">
<canvas id="earthCanvas", width="106", height="53" hidden />
</body>
You can access the code sandbox project through this link: https://codesandbox.io/s/small-hill-mvhgc?file=/src/index.js:5956-6389 (Please excuse any messy code—it's still a prototype.)