Hi @prisoner849 ok here you go:
so, I loaded a PCD file using PCDLoader class, which rendered me a scene with BufferGeometry and PointsMaterial, where initially all the points are colored in white hex 0xffffff. I applied the following code to set the initial color on the material obtained from the pcd:
material.color.setHex(this.defaults.hex);
And this is how I load my pcd file from a certain url and place the points on a grid.
const loader = new PCDLoader();
loader.load(
this.url,
(points: THREE.Points) => {
if (this.pcdLoaded) {
return;
}
const geometry: THREE.BufferGeometry = <THREE.BufferGeometry>(
points.geometry
);
const material: THREE.PointsMaterial = <THREE.PointsMaterial>(
points.material
);
geometry.center();
geometry.rotateX(Math.PI);
material.side = THREE.DoubleSide;
material.color.setHex(this.defaults.hex);
this.pointCloud = points;
const helper = this.setGridHelper();
this.grid = helper;
this.scene.add(this.grid);
this.scene.add(this.pointCloud);
this.render();
this.centerOfLidar = this.getVisualCenterOfPolygon(geometry); // this.getMeanCenter(geometry);
const count = geometry.attributes.position.count;
this.numberOfPointsLoaded = count;
this.numberOfPointsShowing = this.numberOfPointsLoaded;
this.orbitControls.saveState();
this.isLoading = false;
this.event.emit({
trigger: "lidar-data-loaded-trigger",
loaded: true,
});
this.pcdLoaded = true;
this.initStats();
this.evaluateDistanceFromOrigin(geometry);
},
(progress) => {
this.progress = Math.round((100 * progress.loaded) / progress.total);
},
(err) => {
console.log(err);
this.isLoading = false;
this.event.emit({
trigger: "lidar-data-loaded-trigger",
loaded: false,
});
this.loadingError = true;
}
);
Until this is simple, now on click of certain button and on certain business logic criteria met, I need to colorize/heatmap the points in the point cloud to 3 parts, such as
Red color gradient for some points
Orange or yellow color gradient for some points
Green color gradients for some points
To do this, I have done the following code taking idea from your lerpColors implementation:
const points: THREE.Points = <THREE.Points>(
this.getPointsWithBufferGeometry()
);
const material: THREE.PointsMaterial = <THREE.PointsMaterial>(
points.material
);
material.needsUpdate = true;
const geometry: THREE.BufferGeometry = <THREE.BufferGeometry>(
points.geometry
);
material.vertexColors = THREE.VertexColors;
const colors = [];
let color = new THREE.Color();
for (let i = 0; i < this.pointCloudSampler.length; i++) {
const zoneColorHex: string = this.pointCloudSampler[i].zone.color.hex;
color.setStyle(zoneColorHex)
colors.push(color.r, color.g, color.b);
}
geometry.setAttribute(
"color",
new THREE.Float32BufferAttribute(colors, 3,true)
);
geometry.computeBoundingSphere();
private getPointsWithBufferGeometry(): THREE.Object3D {
return <THREE.Mesh>this.scene.getObjectByProperty("type", "Points");
}
Here zoneColorHex is obtained by lerping two similar shades of red, orange and green respectively to produce respective gradients. But seems like the lerp is not working as expected to. Here is my lerp colors implementation for the GREEN shade:
export enum HEX {
GREEN = "#18cd1f",
RED = "#f4141f",
ORANGE = "#d78c00",
}
export enum RELATIVE_HEX {
GREEN = "#10e21f",
RED = "#dd0044",
ORANGE = "#e26410",
}
lerpColors(HEX.GREEN, RELATIVE_HEX.GREEN)
export const lerpColors = (colorStart: string, colorEnd: string): string => {
const gradient = generateColor(colorStart, colorEnd, 10);
let colorHex: string = "#" + gradient[9];
return colorHex;
};
export const hex = (c) => {
var s = "0123456789abcdef";
var i = parseInt(c);
if (i == 0 || isNaN(c)) return "00";
i = Math.round(Math.min(Math.max(0, i), 255));
return s.charAt((i - (i % 16)) / 16) + s.charAt(i % 16);
};
/* Convert an RGB triplet to a hex string */
export const convertToHex = (rgb) => {
return hex(rgb[0]) + hex(rgb[1]) + hex(rgb[2]);
};
/* Remove '#' in color hex string */
export const trim = (s: string) => {
if (typeof s === "string") return s.charAt(0) == "#" ? s.substring(1, 6) : s;
};
/* Convert a hex string to an RGB triplet */
const convertToRGB = (hex: string) => {
var color = [];
color[0] = parseInt(trim(hex).substring(0, 2), 16);
color[1] = parseInt(trim(hex).substring(2, 4), 16);
color[2] = parseInt(trim(hex).substring(4, 6), 16);
return color;
};
export const generateColor = (colorStart, colorEnd, colorCount) => {
// The beginning of your gradient
var start = convertToRGB(colorStart);
// The end of your gradient
var end = convertToRGB(colorEnd);
// The number of colors to compute
var len = colorCount;
//Alpha blending amount
var alpha = 0.0;
var grad = [];
for (var i = 0; i < len; i++) {
var c = [];
alpha += 1.0 / len;
c[0] = start[0] * alpha + (1 - alpha) * end[0];
c[1] = start[1] * alpha + (1 - alpha) * end[1];
c[2] = start[2] * alpha + (1 - alpha) * end[2];
grad.push(convertToHex(c));
}
return grad;
};
The reason why I made my own lerp color to make a gradient is that I am on Angular version 8.2 right now and using three js version 0.110.0 which perhaps does not support lerpColors, but I took the idea of lerping it myself seeing your implementation, but seems like something I missed here to convert the solid color to a gradient.
The output even after lerping two color shades I get is this:
Here you can see I get the colors as solid, they are not gradient-ified
But the desired color gradient should appear as this:
Is this explanation okay for you to help me, pls let me know, I will provide more detail if needed.