Reputation: 464
I am using threejs to create and render a point cloud. What I would like to do is give each point a specific color based on its Z coordinate. This color should be mapped from some color like green having the smallest Z coordinate, throughout blue, yellow and red having the largest Z values. What is the simplest way to give each point a specific color that follows this gradient approach?
My script is quite long, so I have simplified it to only these few lines of code:
function drawCloud(){
for(i = 0; i < totalPoints * 3; i = i + 3){
//Setting the new Z value of each point
//Each third value is the Z value, therefore using i+2
points.geometry.attributes.position.array[i+2] = theNewZValueForThisPoint;
//Now setting the color of each point
// i, i+1 AND i+2 is the R,G, B value of each point
//here each point is set to a green color
points.geometry.attributes.color.array[i] = 0;
points.geometry.attributes.color.array[i+1] = 1;
points.geometry.attributes.color.array[i+2] = 0;
}
}
function animate() {
requestAnimationFrame( animate );
drawCloud();
render();
}
function render() {
renderer.render( scene, camera );
}
I have already created a kind of segmentation approach where each point gets a fixed color within a range. Something like this:
function getColor() {
if(ZValue > 0 && ZValue < 100){
color = green;
}
if(ZValue > 100 && ZValue < 200){
color = blue;
}
}
This is not what I want, as there would be a region where the color is drastically changed. I would like it to have a more gradient approach that changes slowly as the Z value increases.
Keep in mind that this code has been simplified to a great extent to keep it simple and only show the basic idea. Any recommendations on other improvements would also be appreciated.
Upvotes: 1
Views: 644
Reputation: 468
Given that you have the minimum z-value and maximum z-value of your point cloud, you can use this function to get the color of each point. You can customize the colors and breakpoints of your gradient in the gradient-array accordingly:
function getColor(z, zMin, zMax) {
// normalize v in the range of vMin and vMax
function normalize(v, vMin, vMax) {
return ((v - vMin) / (vMax - vMin));
}
// clamp a value between min and max inclusive
function clamp(value, min, max) {
if (value >= max) return max;
if (value <= min) return min;
return value;
}
// calculates the linear interpolation of two numbers
function lerp(a, b, alpha) {
return a + (b - a) * clamp(alpha, 0, 1);
}
const zNorm = normalize(z, zMin, zMax);
// gradient definition. Each element defines a breakpoint within the normalized z-range (0 - 1) and color
// important: has to be sorted ascendingly by bp
const gradient = [
{bp: 0, r: 0, g: 1, b: 0},
{bp: 1/3, r: 0, g: 0, b: 1},
{bp: 2/3, r: 1, g: 1, b: 0},
{bp: 1, r: 1, g: 0, b: 0}
];
let red, green, blue;
// find the color segment (between breakpoints), interpolate the color between breakpoints
for(let i = 0, g = gradient.length; i < g; i++) {
if(zNorm < gradient[i].bp || gradient[i].bp === 1) {
red = lerp(gradient[i-1].r, gradient[i].r, normalize(zNorm, gradient[i-1].bp, gradient[i].bp));
green = lerp(gradient[i-1].g, gradient[i].g, normalize(zNorm, gradient[i-1].bp, gradient[i].bp));
blue = lerp(gradient[i-1].b, gradient[i].b, normalize(zNorm, gradient[i-1].bp, gradient[i].bp));
break;
}
}
return {r: red, g: green, b: blue};
}
Upvotes: 4