Skip to content

Commit

Permalink
feat(points): Add attenuated mode for points size rendering
Browse files Browse the repository at this point in the history
  • Loading branch information
ketourneau committed Sep 1, 2023
1 parent cefebce commit 6db3c5e
Show file tree
Hide file tree
Showing 10 changed files with 93 additions and 9 deletions.
4 changes: 4 additions & 0 deletions CONTRIBUTORS.md
Expand Up @@ -45,6 +45,10 @@ The following people have contributed to iTowns.
* [Diginove](http://diginove.com/index.php/fr/diginove-lexpertise-en-traitement-dimages/):
* [Michel Benet](https://github.com/mbenevole)

* [Sogelink](https://www.sogelink.com/)
* [Kévin ETOURNEAU](https://github.com/ketourneau)
* [Alexis DELFORGES](https://github.com/pourfex)

The following organizations are the current maintainers of iTowns:
* IGN (http://www.ign.fr)
* Ciril Group (https://www.cirilgroup.com/)
13 changes: 11 additions & 2 deletions src/Layer/C3DTilesLayer.js
Expand Up @@ -3,7 +3,7 @@ import GeometryLayer from 'Layer/GeometryLayer';
import { init3dTilesLayer, pre3dTilesUpdate, process3dTilesNode } from 'Process/3dTilesProcessing';
import C3DTileset from 'Core/3DTiles/C3DTileset';
import C3DTExtensions from 'Core/3DTiles/C3DTExtensions';
import { PNTS_MODE } from 'Renderer/PointsMaterial';
import { PNTS_MODE, PNTS_SIZE_MODE } from 'Renderer/PointsMaterial';
// eslint-disable-next-line no-unused-vars
import Style from 'Core/Style';
import C3DTFeature from 'Core/3DTiles/C3DTFeature';
Expand Down Expand Up @@ -70,6 +70,9 @@ class C3DTilesLayer extends GeometryLayer {
* removed from the scene.
* @param {C3DTExtensions} [config.registeredExtensions] 3D Tiles extensions managers registered for this tileset.
* @param {String} [config.pntsMode= PNTS_MODE.COLOR] {@link PointsMaterials} Point cloud coloring mode. Only 'COLOR' or 'CLASSIFICATION' are possible. COLOR uses RGB colors of the points, CLASSIFICATION uses a classification property of the batch table to color points.
* @param {String} [config.pntsSizeMode= PNTS_SIZE_MODE.VALUE] {@link PointsMaterials} Point cloud size mode. Only 'VALUE' or 'ATTENUATED' are possible. VALUE use constant size, ATTENUATED compute size depending on distance from point to camera.
* @param {Number} [config.pntsMinAttenuatedSize=3] Minimum scale used by 'ATTENUATED' size mode
* @param {Number} [config.pntsMaxAttenuatedSize=10] Maximum scale used by 'ATTENUATED' size mode
* @param {Style} [config.style=null] - style used for this layer
* @param {View} view The view
*/
Expand All @@ -84,13 +87,19 @@ class C3DTilesLayer extends GeometryLayer {

this.pntsMode = PNTS_MODE.COLOR;
this.classification = config.classification;

this.pntsSizeMode = PNTS_SIZE_MODE.VALUE;
this.pntsMinAttenuatedSize = config.pntsMinAttenuatedSize || 3;
this.pntsMaxAttenuatedSize = config.pntsMaxAttenuatedSize || 10;

if (config.pntsMode) {
const exists = Object.values(PNTS_MODE).includes(config.pntsMode);
if (!exists) { console.warn("The points cloud mode doesn't exist. Use 'COLOR' or 'CLASSIFICATION' instead."); } else { this.pntsMode = config.pntsMode; }
}

if (config.pntsSizeMode) {
const exists = Object.values(PNTS_SIZE_MODE).includes(config.pntsSizeMode);
if (!exists) { console.warn("The points cloud size mode doesn't exist. Use 'VALUE' or 'ATTENUATED' instead."); } else { this.pntsSizeMode = config.pntsSizeMode; }
}

/** @type {Style} */
this._style = config.style || null;
Expand Down
1 change: 1 addition & 0 deletions src/Layer/PointCloudLayer.js
Expand Up @@ -160,6 +160,7 @@ class PointCloudLayer extends GeometryLayer {
this.material.opacity = this.opacity;
this.material.transparent = this.opacity < 1;
this.material.size = this.pointSize;
this.material.preSSE = context.camera.preSSE;
if (this.material.updateUniforms) {
this.material.updateUniforms();
}
Expand Down
15 changes: 15 additions & 0 deletions src/Layer/ReferencingLayerProperties.js
Expand Up @@ -21,6 +21,21 @@ function ReferLayerProperties(material, layer) {
get: () => material.layer.pntsMode,
});
}
if (material.uniforms && material.uniforms.sizeMode != undefined) {
Object.defineProperty(material.uniforms.sizeMode, 'value', {
get: () => material.layer.pntsSizeMode,
});
}
if (material.uniforms && material.uniforms.minAttenuatedSize != undefined) {
Object.defineProperty(material.uniforms.minAttenuatedSize, 'value', {
get: () => material.layer.pntsMinAttenuatedSize,
});
}
if (material.uniforms && material.uniforms.maxAttenuatedSize != undefined) {
Object.defineProperty(material.uniforms.maxAttenuatedSize, 'value', {
get: () => material.layer.pntsMaxAttenuatedSize,
});
}

Object.defineProperty(material, 'wireframe', {
get: () => material.layer.wireframe,
Expand Down
2 changes: 1 addition & 1 deletion src/Main.js
Expand Up @@ -19,7 +19,7 @@ export { VIEW_EVENTS } from 'Core/View';
export { default as FeatureProcessing } from 'Process/FeatureProcessing';
export { updateLayeredMaterialNodeImagery, updateLayeredMaterialNodeElevation } from 'Process/LayeredMaterialNodeProcessing';
export { default as OrientedImageCamera } from 'Renderer/OrientedImageCamera';
export { default as PointsMaterial, PNTS_MODE, ClassificationScheme } from 'Renderer/PointsMaterial';
export { default as PointsMaterial, PNTS_MODE, PNTS_SIZE_MODE, ClassificationScheme } from 'Renderer/PointsMaterial';
export { default as GlobeControls } from 'Controls/GlobeControls';
export { default as FlyControls } from 'Controls/FlyControls';
export { default as FirstPersonControls } from 'Controls/FirstPersonControls';
Expand Down
9 changes: 8 additions & 1 deletion src/Provider/3dTilesProvider.js
Expand Up @@ -29,7 +29,14 @@ function pntsParse(data, layer) {
return PntsParser.parse(data, layer.registeredExtensions).then((result) => {
const material = layer.material ?
layer.material.clone() :
new PointsMaterial({ size: 0.05, mode: layer.pntsMode, classification: layer.classification });
new PointsMaterial({
size: 0.05,
mode: layer.pntsMode,
classification: layer.classification,
sizeMode: layer.pntsSizeMode,
minAttenuatedSize: layer.pntsMinAttenuatedSize,
maxAttenuatedSize: layer.pntsMaxAttenuatedSize,
});

// refer material properties in the layer so when layers opacity and visibility is updated, the material is
// automatically updated
Expand Down
22 changes: 22 additions & 0 deletions src/Renderer/PointsMaterial.js
Expand Up @@ -12,6 +12,11 @@ export const PNTS_MODE = {
NORMAL: 3,
};

export const PNTS_SIZE_MODE = {
VALUE: 0,
ATTENUATED: 1,
};

const white = new THREE.Color(1.0, 1.0, 1.0);

/**
Expand Down Expand Up @@ -59,6 +64,9 @@ class PointsMaterial extends THREE.RawShaderMaterial {
* @param {THREE.Vector2} [options.intensityRange=new THREE.Vector2(0, 1)] intensity range.
* @param {boolean} [options.applyOpacityClassication=false] apply opacity classification on all display mode.
* @param {Classification} [options.classification] - define points classification.
* @param {number} [options.sizeMode=PNTS_SIZE_MODE.VALUE] point cloud size mode. Only 'VALUE' or 'ATTENUATED' are possible. VALUE use constant size, ATTENUATED compute size depending on distance from point to camera.
* @param {number} [options.minAttenuatedSize=3] minimum scale used by 'ATTENUATED' size mode
* @param {number} [options.maxAttenuatedSize=10] maximum scale used by 'ATTENUATED' size mode
* @property {Classification} classification - points classification.
*
* @example
Expand All @@ -74,13 +82,19 @@ class PointsMaterial extends THREE.RawShaderMaterial {
const applyOpacityClassication = options.applyOpacityClassication == undefined ? false : options.applyOpacityClassication;
const size = options.size || 0;
const mode = options.mode || PNTS_MODE.COLOR;
const sizeMode = size === 0 ? PNTS_SIZE_MODE.ATTENUATED : (options.sizeMode || PNTS_SIZE_MODE.VALUE);
const minAttenuatedSize = options.minAttenuatedSize || 3;
const maxAttenuatedSize = options.maxAttenuatedSize || 10;

delete options.orientedImageMaterial;
delete options.intensityRange;
delete options.classification;
delete options.applyOpacityClassication;
delete options.size;
delete options.mode;
delete options.sizeMode;
delete options.minAttenuatedSize;
delete options.maxAttenuatedSize;

super(options);

Expand All @@ -89,6 +103,7 @@ class PointsMaterial extends THREE.RawShaderMaterial {
this.scale = options.scale || 0.05 * 0.5 / Math.tan(1.0 / 2.0); // autosizing scale

CommonMaterial.setDefineMapping(this, 'PNTS_MODE', PNTS_MODE);
CommonMaterial.setDefineMapping(this, 'PNTS_SIZE_MODE', PNTS_SIZE_MODE);

CommonMaterial.setUniformProperty(this, 'size', size);
CommonMaterial.setUniformProperty(this, 'mode', mode);
Expand All @@ -97,6 +112,10 @@ class PointsMaterial extends THREE.RawShaderMaterial {
CommonMaterial.setUniformProperty(this, 'overlayColor', options.overlayColor || new THREE.Vector4(0, 0, 0, 0));
CommonMaterial.setUniformProperty(this, 'intensityRange', intensityRange);
CommonMaterial.setUniformProperty(this, 'applyOpacityClassication', applyOpacityClassication);
CommonMaterial.setUniformProperty(this, 'sizeMode', sizeMode);
CommonMaterial.setUniformProperty(this, 'preSSE', 1.0);
CommonMaterial.setUniformProperty(this, 'minAttenuatedSize', minAttenuatedSize);
CommonMaterial.setUniformProperty(this, 'maxAttenuatedSize', maxAttenuatedSize);

// add classification texture to apply classification lut.
const data = new Uint8Array(256 * 4);
Expand Down Expand Up @@ -214,6 +233,9 @@ class PointsMaterial extends THREE.RawShaderMaterial {
this.transparent = source.transparent;
this.size = source.size;
this.mode = source.mode;
this.sizeMode = source.sizeMode;
this.minAttenuatedSize = source.minAttenuatedSize;
this.maxAttenuatedSize = source.maxAttenuatedSize;
this.picking = source.picking;
this.scale = source.scale;
this.overlayColor.copy(source.overlayColor);
Expand Down
14 changes: 10 additions & 4 deletions src/Renderer/Shader/PointsVS.glsl
Expand Up @@ -8,6 +8,7 @@
#include <logdepthbuf_pars_vertex>

uniform float size;
uniform float preSSE;

uniform bool picking;
uniform int mode;
Expand All @@ -20,6 +21,9 @@ attribute vec4 unique_id;
attribute float intensity;
attribute float classification;
uniform sampler2D classificationLUT;
uniform int sizeMode;
uniform float minAttenuatedSize;
uniform float maxAttenuatedSize;

#if defined(NORMAL_OCT16)
attribute vec2 oct16Normal;
Expand Down Expand Up @@ -90,7 +94,7 @@ void main() {
vColor.rgb = vec3(i, i, i);
} else if (mode == PNTS_MODE_NORMAL) {
vColor.rgb = abs(normal);
} else if (mode ==PNTS_MODE_COLOR) {
} else if (mode == PNTS_MODE_COLOR) {
// default to color mode
vColor.rgb = mix(color, overlayColor.rgb, overlayColor.a);
}
Expand All @@ -99,10 +103,12 @@ void main() {
#include <begin_vertex>
#include <project_vertex>

if (size > 0.) {
if (sizeMode == PNTS_SIZE_MODE_VALUE) {
gl_PointSize = size;
} else {
gl_PointSize = clamp(-size / gl_Position.w, 3.0, 10.0);
} else if (sizeMode == PNTS_SIZE_MODE_ATTENUATED) {
gl_PointSize = size;
gl_PointSize *= (preSSE / -mvPosition.z);
gl_PointSize = clamp(gl_PointSize, minAttenuatedSize, maxAttenuatedSize);
}

#if defined(USE_TEXTURES_PROJECTIVE)
Expand Down
13 changes: 13 additions & 0 deletions utils/debug/3dTilesDebug.js
@@ -1,6 +1,7 @@
import * as THREE from 'three';
import View from 'Core/View';
import GeometryLayer from 'Layer/GeometryLayer';
import { PNTS_SIZE_MODE } from 'Renderer/PointsMaterial';
import GeometryDebug from './GeometryDebug';
import OBBHelper from './OBBHelper';

Expand Down Expand Up @@ -112,4 +113,16 @@ export default function create3dTilesDebugUI(datDebugTool, view, _3dTileslayer)
gui.add(_3dTileslayer, 'sseThreshold', 0, 100).name('sseThreshold').onChange(() => {
view.notifyChange(view.camera.camera3D);
});

gui.add(_3dTileslayer, 'pntsSizeMode', PNTS_SIZE_MODE).name('Pnts size mode').onChange(() => {
view.notifyChange(view.camera.camera3D);
});

gui.add(_3dTileslayer, 'pntsMinAttenuatedSize', 0, 15).name('Min attenuated size').onChange(() => {
view.notifyChange(view.camera.camera3D);
});

gui.add(_3dTileslayer, 'pntsMaxAttenuatedSize', 0, 15).name('Max attenuated size').onChange(() => {
view.notifyChange(view.camera.camera3D);
});
}
9 changes: 8 additions & 1 deletion utils/debug/PotreeDebug.js
@@ -1,4 +1,4 @@
import { PNTS_MODE } from 'Renderer/PointsMaterial';
import { PNTS_MODE, PNTS_SIZE_MODE } from 'Renderer/PointsMaterial';

export default {
initTools(view, layer, datUi) {
Expand Down Expand Up @@ -26,6 +26,13 @@ export default {
}
styleUI.add(layer, 'opacity', 0, 1).name('Layer Opacity').onChange(update);
styleUI.add(layer, 'pointSize', 0, 15).name('Point Size').onChange(update);
if (layer.material.sizeMode != undefined) {
styleUI.add(layer.material, 'sizeMode', PNTS_SIZE_MODE).name('Point size mode').onChange(() => {
update();
});
}
styleUI.add(layer.material, 'minAttenuatedSize', 0, 15).name('Min attenuated size').onChange(update);
styleUI.add(layer.material, 'maxAttenuatedSize', 0, 15).name('Max attenuated size').onChange(update);
if (layer.material.picking != undefined) {
styleUI.add(layer.material, 'picking').name('Display picking id').onChange(update);
}
Expand Down

0 comments on commit 6db3c5e

Please sign in to comment.