Skip to content

Commit 6db3c5e

Browse files
authored
feat(points): Add attenuated mode for points size rendering
1 parent cefebce commit 6db3c5e

10 files changed

+93
-9
lines changed

CONTRIBUTORS.md

+4
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ The following people have contributed to iTowns.
4545
* [Diginove](http://diginove.com/index.php/fr/diginove-lexpertise-en-traitement-dimages/):
4646
* [Michel Benet](https://github.com/mbenevole)
4747

48+
* [Sogelink](https://www.sogelink.com/)
49+
* [Kévin ETOURNEAU](https://github.com/ketourneau)
50+
* [Alexis DELFORGES](https://github.com/pourfex)
51+
4852
The following organizations are the current maintainers of iTowns:
4953
* IGN (http://www.ign.fr)
5054
* Ciril Group (https://www.cirilgroup.com/)

src/Layer/C3DTilesLayer.js

+11-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import GeometryLayer from 'Layer/GeometryLayer';
33
import { init3dTilesLayer, pre3dTilesUpdate, process3dTilesNode } from 'Process/3dTilesProcessing';
44
import C3DTileset from 'Core/3DTiles/C3DTileset';
55
import C3DTExtensions from 'Core/3DTiles/C3DTExtensions';
6-
import { PNTS_MODE } from 'Renderer/PointsMaterial';
6+
import { PNTS_MODE, PNTS_SIZE_MODE } from 'Renderer/PointsMaterial';
77
// eslint-disable-next-line no-unused-vars
88
import Style from 'Core/Style';
99
import C3DTFeature from 'Core/3DTiles/C3DTFeature';
@@ -70,6 +70,9 @@ class C3DTilesLayer extends GeometryLayer {
7070
* removed from the scene.
7171
* @param {C3DTExtensions} [config.registeredExtensions] 3D Tiles extensions managers registered for this tileset.
7272
* @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.
73+
* @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.
74+
* @param {Number} [config.pntsMinAttenuatedSize=3] Minimum scale used by 'ATTENUATED' size mode
75+
* @param {Number} [config.pntsMaxAttenuatedSize=10] Maximum scale used by 'ATTENUATED' size mode
7376
* @param {Style} [config.style=null] - style used for this layer
7477
* @param {View} view The view
7578
*/
@@ -84,13 +87,19 @@ class C3DTilesLayer extends GeometryLayer {
8487

8588
this.pntsMode = PNTS_MODE.COLOR;
8689
this.classification = config.classification;
87-
90+
this.pntsSizeMode = PNTS_SIZE_MODE.VALUE;
91+
this.pntsMinAttenuatedSize = config.pntsMinAttenuatedSize || 3;
92+
this.pntsMaxAttenuatedSize = config.pntsMaxAttenuatedSize || 10;
8893

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

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

95104
/** @type {Style} */
96105
this._style = config.style || null;

src/Layer/PointCloudLayer.js

+1
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ class PointCloudLayer extends GeometryLayer {
160160
this.material.opacity = this.opacity;
161161
this.material.transparent = this.opacity < 1;
162162
this.material.size = this.pointSize;
163+
this.material.preSSE = context.camera.preSSE;
163164
if (this.material.updateUniforms) {
164165
this.material.updateUniforms();
165166
}

src/Layer/ReferencingLayerProperties.js

+15
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,21 @@ function ReferLayerProperties(material, layer) {
2121
get: () => material.layer.pntsMode,
2222
});
2323
}
24+
if (material.uniforms && material.uniforms.sizeMode != undefined) {
25+
Object.defineProperty(material.uniforms.sizeMode, 'value', {
26+
get: () => material.layer.pntsSizeMode,
27+
});
28+
}
29+
if (material.uniforms && material.uniforms.minAttenuatedSize != undefined) {
30+
Object.defineProperty(material.uniforms.minAttenuatedSize, 'value', {
31+
get: () => material.layer.pntsMinAttenuatedSize,
32+
});
33+
}
34+
if (material.uniforms && material.uniforms.maxAttenuatedSize != undefined) {
35+
Object.defineProperty(material.uniforms.maxAttenuatedSize, 'value', {
36+
get: () => material.layer.pntsMaxAttenuatedSize,
37+
});
38+
}
2439

2540
Object.defineProperty(material, 'wireframe', {
2641
get: () => material.layer.wireframe,

src/Main.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export { VIEW_EVENTS } from 'Core/View';
1919
export { default as FeatureProcessing } from 'Process/FeatureProcessing';
2020
export { updateLayeredMaterialNodeImagery, updateLayeredMaterialNodeElevation } from 'Process/LayeredMaterialNodeProcessing';
2121
export { default as OrientedImageCamera } from 'Renderer/OrientedImageCamera';
22-
export { default as PointsMaterial, PNTS_MODE, ClassificationScheme } from 'Renderer/PointsMaterial';
22+
export { default as PointsMaterial, PNTS_MODE, PNTS_SIZE_MODE, ClassificationScheme } from 'Renderer/PointsMaterial';
2323
export { default as GlobeControls } from 'Controls/GlobeControls';
2424
export { default as FlyControls } from 'Controls/FlyControls';
2525
export { default as FirstPersonControls } from 'Controls/FirstPersonControls';

src/Provider/3dTilesProvider.js

+8-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,14 @@ function pntsParse(data, layer) {
2929
return PntsParser.parse(data, layer.registeredExtensions).then((result) => {
3030
const material = layer.material ?
3131
layer.material.clone() :
32-
new PointsMaterial({ size: 0.05, mode: layer.pntsMode, classification: layer.classification });
32+
new PointsMaterial({
33+
size: 0.05,
34+
mode: layer.pntsMode,
35+
classification: layer.classification,
36+
sizeMode: layer.pntsSizeMode,
37+
minAttenuatedSize: layer.pntsMinAttenuatedSize,
38+
maxAttenuatedSize: layer.pntsMaxAttenuatedSize,
39+
});
3340

3441
// refer material properties in the layer so when layers opacity and visibility is updated, the material is
3542
// automatically updated

src/Renderer/PointsMaterial.js

+22
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ export const PNTS_MODE = {
1212
NORMAL: 3,
1313
};
1414

15+
export const PNTS_SIZE_MODE = {
16+
VALUE: 0,
17+
ATTENUATED: 1,
18+
};
19+
1520
const white = new THREE.Color(1.0, 1.0, 1.0);
1621

1722
/**
@@ -59,6 +64,9 @@ class PointsMaterial extends THREE.RawShaderMaterial {
5964
* @param {THREE.Vector2} [options.intensityRange=new THREE.Vector2(0, 1)] intensity range.
6065
* @param {boolean} [options.applyOpacityClassication=false] apply opacity classification on all display mode.
6166
* @param {Classification} [options.classification] - define points classification.
67+
* @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.
68+
* @param {number} [options.minAttenuatedSize=3] minimum scale used by 'ATTENUATED' size mode
69+
* @param {number} [options.maxAttenuatedSize=10] maximum scale used by 'ATTENUATED' size mode
6270
* @property {Classification} classification - points classification.
6371
*
6472
* @example
@@ -74,13 +82,19 @@ class PointsMaterial extends THREE.RawShaderMaterial {
7482
const applyOpacityClassication = options.applyOpacityClassication == undefined ? false : options.applyOpacityClassication;
7583
const size = options.size || 0;
7684
const mode = options.mode || PNTS_MODE.COLOR;
85+
const sizeMode = size === 0 ? PNTS_SIZE_MODE.ATTENUATED : (options.sizeMode || PNTS_SIZE_MODE.VALUE);
86+
const minAttenuatedSize = options.minAttenuatedSize || 3;
87+
const maxAttenuatedSize = options.maxAttenuatedSize || 10;
7788

7889
delete options.orientedImageMaterial;
7990
delete options.intensityRange;
8091
delete options.classification;
8192
delete options.applyOpacityClassication;
8293
delete options.size;
8394
delete options.mode;
95+
delete options.sizeMode;
96+
delete options.minAttenuatedSize;
97+
delete options.maxAttenuatedSize;
8498

8599
super(options);
86100

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

91105
CommonMaterial.setDefineMapping(this, 'PNTS_MODE', PNTS_MODE);
106+
CommonMaterial.setDefineMapping(this, 'PNTS_SIZE_MODE', PNTS_SIZE_MODE);
92107

93108
CommonMaterial.setUniformProperty(this, 'size', size);
94109
CommonMaterial.setUniformProperty(this, 'mode', mode);
@@ -97,6 +112,10 @@ class PointsMaterial extends THREE.RawShaderMaterial {
97112
CommonMaterial.setUniformProperty(this, 'overlayColor', options.overlayColor || new THREE.Vector4(0, 0, 0, 0));
98113
CommonMaterial.setUniformProperty(this, 'intensityRange', intensityRange);
99114
CommonMaterial.setUniformProperty(this, 'applyOpacityClassication', applyOpacityClassication);
115+
CommonMaterial.setUniformProperty(this, 'sizeMode', sizeMode);
116+
CommonMaterial.setUniformProperty(this, 'preSSE', 1.0);
117+
CommonMaterial.setUniformProperty(this, 'minAttenuatedSize', minAttenuatedSize);
118+
CommonMaterial.setUniformProperty(this, 'maxAttenuatedSize', maxAttenuatedSize);
100119

101120
// add classification texture to apply classification lut.
102121
const data = new Uint8Array(256 * 4);
@@ -214,6 +233,9 @@ class PointsMaterial extends THREE.RawShaderMaterial {
214233
this.transparent = source.transparent;
215234
this.size = source.size;
216235
this.mode = source.mode;
236+
this.sizeMode = source.sizeMode;
237+
this.minAttenuatedSize = source.minAttenuatedSize;
238+
this.maxAttenuatedSize = source.maxAttenuatedSize;
217239
this.picking = source.picking;
218240
this.scale = source.scale;
219241
this.overlayColor.copy(source.overlayColor);

src/Renderer/Shader/PointsVS.glsl

+10-4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <logdepthbuf_pars_vertex>
99

1010
uniform float size;
11+
uniform float preSSE;
1112

1213
uniform bool picking;
1314
uniform int mode;
@@ -20,6 +21,9 @@ attribute vec4 unique_id;
2021
attribute float intensity;
2122
attribute float classification;
2223
uniform sampler2D classificationLUT;
24+
uniform int sizeMode;
25+
uniform float minAttenuatedSize;
26+
uniform float maxAttenuatedSize;
2327

2428
#if defined(NORMAL_OCT16)
2529
attribute vec2 oct16Normal;
@@ -90,7 +94,7 @@ void main() {
9094
vColor.rgb = vec3(i, i, i);
9195
} else if (mode == PNTS_MODE_NORMAL) {
9296
vColor.rgb = abs(normal);
93-
} else if (mode ==PNTS_MODE_COLOR) {
97+
} else if (mode == PNTS_MODE_COLOR) {
9498
// default to color mode
9599
vColor.rgb = mix(color, overlayColor.rgb, overlayColor.a);
96100
}
@@ -99,10 +103,12 @@ void main() {
99103
#include <begin_vertex>
100104
#include <project_vertex>
101105

102-
if (size > 0.) {
106+
if (sizeMode == PNTS_SIZE_MODE_VALUE) {
103107
gl_PointSize = size;
104-
} else {
105-
gl_PointSize = clamp(-size / gl_Position.w, 3.0, 10.0);
108+
} else if (sizeMode == PNTS_SIZE_MODE_ATTENUATED) {
109+
gl_PointSize = size;
110+
gl_PointSize *= (preSSE / -mvPosition.z);
111+
gl_PointSize = clamp(gl_PointSize, minAttenuatedSize, maxAttenuatedSize);
106112
}
107113

108114
#if defined(USE_TEXTURES_PROJECTIVE)

utils/debug/3dTilesDebug.js

+13
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as THREE from 'three';
22
import View from 'Core/View';
33
import GeometryLayer from 'Layer/GeometryLayer';
4+
import { PNTS_SIZE_MODE } from 'Renderer/PointsMaterial';
45
import GeometryDebug from './GeometryDebug';
56
import OBBHelper from './OBBHelper';
67

@@ -112,4 +113,16 @@ export default function create3dTilesDebugUI(datDebugTool, view, _3dTileslayer)
112113
gui.add(_3dTileslayer, 'sseThreshold', 0, 100).name('sseThreshold').onChange(() => {
113114
view.notifyChange(view.camera.camera3D);
114115
});
116+
117+
gui.add(_3dTileslayer, 'pntsSizeMode', PNTS_SIZE_MODE).name('Pnts size mode').onChange(() => {
118+
view.notifyChange(view.camera.camera3D);
119+
});
120+
121+
gui.add(_3dTileslayer, 'pntsMinAttenuatedSize', 0, 15).name('Min attenuated size').onChange(() => {
122+
view.notifyChange(view.camera.camera3D);
123+
});
124+
125+
gui.add(_3dTileslayer, 'pntsMaxAttenuatedSize', 0, 15).name('Max attenuated size').onChange(() => {
126+
view.notifyChange(view.camera.camera3D);
127+
});
115128
}

utils/debug/PotreeDebug.js

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { PNTS_MODE } from 'Renderer/PointsMaterial';
1+
import { PNTS_MODE, PNTS_SIZE_MODE } from 'Renderer/PointsMaterial';
22

33
export default {
44
initTools(view, layer, datUi) {
@@ -26,6 +26,13 @@ export default {
2626
}
2727
styleUI.add(layer, 'opacity', 0, 1).name('Layer Opacity').onChange(update);
2828
styleUI.add(layer, 'pointSize', 0, 15).name('Point Size').onChange(update);
29+
if (layer.material.sizeMode != undefined) {
30+
styleUI.add(layer.material, 'sizeMode', PNTS_SIZE_MODE).name('Point size mode').onChange(() => {
31+
update();
32+
});
33+
}
34+
styleUI.add(layer.material, 'minAttenuatedSize', 0, 15).name('Min attenuated size').onChange(update);
35+
styleUI.add(layer.material, 'maxAttenuatedSize', 0, 15).name('Max attenuated size').onChange(update);
2936
if (layer.material.picking != undefined) {
3037
styleUI.add(layer.material, 'picking').name('Display picking id').onChange(update);
3138
}

0 commit comments

Comments
 (0)