I've been using Three.js to make a project that creates a point material object which can then be interacted with. I'm trying to map the pixels of an image to the vertexes of a buffer geometry so it shows the image as a set of points (point cloud like). The image in question being a map of the earth (downscaled to 106 x 53 pixels).
I'm doing this by drawing the image on a canvas, extracting the image data, setting the colour from the image data (based on pixel coordinates) and then setting the colour attribute of my geometry (in this case a sphere buffer geometry). Where am I going wrong with the mapping?
This is code for extracting colours and placing them in an array for the geometry:
let colors = [];
let color = new THREE.Color();
let positionAttribute = g.attributes.position; // g being geometry
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);
console.log("set");
colors.push(color.r, color.g, color.b);
}
}
g.setAttribute("color", new THREE.Float32BufferAttribute(colors, 3));
Which results in this happening:
Is there any way to make this look like earth as a globe? Am I just placing the coordinates of the pixels wrong?
The code for the geometry itself 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,
//blending: THREE.AdditiveBlending,
depthTest: false,
opacity: 1
});
And the HTML and JavaScript for the canvas looks like this:
function drawImageSource(source, canvas) {
img = new Image();
img.addEventListener("load", function () {
// The image can be drawn from any source
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>
The link to the code sandbox project is here: https://codesandbox.io/s/small-hill-mvhgc?file=/src/index.js:5956-6389 (I apologise for messy code. It's a prototype.)

I would go with a different approach: modify the existing
PointsMaterial, using.onBeforeCompile(), and pass a texture in a uniform.