diff --git a/src/materials/point-cloud-material.ts b/src/materials/point-cloud-material.ts index a580d87b..2f368d36 100644 --- a/src/materials/point-cloud-material.ts +++ b/src/materials/point-cloud-material.ts @@ -3,6 +3,7 @@ import { BufferGeometry, Camera, Color, + DataTexture, LessEqualDepth, Material, NearestFilter, @@ -42,6 +43,7 @@ import { import { SPECTRAL } from './gradients'; import { generateClassificationTexture, + generateClipboxTexture, generateDataTexture, generateGradientTexture, } from './texture-generation'; @@ -61,7 +63,7 @@ export interface IPointCloudMaterialUniforms { blendHardness: IUniform; classificationLUT: IUniform; clipBoxCount: IUniform; - clipBoxes: IUniform; + clipBoxesTexture: IUniform; clipExtent: IUniform<[number, number, number, number]>; depthMap: IUniform; diffuse: IUniform<[number, number, number]>; @@ -174,8 +176,11 @@ export class PointCloudMaterial extends RawShaderMaterial { lights = false; fog = false; colorRgba = false; + numClipBoxes: number = 0; clipBoxes: IClipBox[] = []; + clipBoxesTexture: Texture | undefined; + visibleNodesTexture: Texture | undefined; private visibleNodeTextureOffsets = new Map(); @@ -193,7 +198,8 @@ export class PointCloudMaterial extends RawShaderMaterial { blendHardness: makeUniform('f', 2.0), classificationLUT: makeUniform('t', this.classificationTexture || new Texture()), clipBoxCount: makeUniform('f', 0), - clipBoxes: makeUniform('Matrix4fv', [] as any), + // @ts-ignore + clipBoxesTexture: makeUniform('t', this.clipBoxesTexture || new DataTexture()), clipExtent: makeUniform('fv', [0.0, 0.0, 1.0, 1.0] as [number, number, number, number]), depthMap: makeUniform('t', null), diffuse: makeUniform('fv', [1, 1, 1] as [number, number, number]), @@ -327,6 +333,9 @@ export class PointCloudMaterial extends RawShaderMaterial { tex.magFilter = NearestFilter; this.setUniform('visibleNodes', tex); + const clipTexture = (this.clipBoxesTexture = generateClipboxTexture()); + this.setUniform('clipBoxesTexture', clipTexture); + this.treeType = getValid(parameters.treeType, TreeType.OCTREE); this.size = getValid(parameters.size, 1.0); this.minSize = getValid(parameters.minSize, 2.0); @@ -373,6 +382,11 @@ export class PointCloudMaterial extends RawShaderMaterial { this.backgroundMap.dispose(); this.backgroundMap = undefined; } + + if (this.clipBoxesTexture) { + this.clipBoxesTexture.dispose(); + this.clipBoxesTexture = undefined; + } } clearVisibleNodeTextureOffsets(): void { @@ -497,10 +511,6 @@ export class PointCloudMaterial extends RawShaderMaterial { this.numClipBoxes = clipBoxes.length; this.setUniform('clipBoxCount', this.numClipBoxes); - if (doUpdate) { - this.updateShaderSource(); - } - const clipBoxesLength = this.numClipBoxes * 16; const clipBoxesArray = new Float32Array(clipBoxesLength); @@ -514,7 +524,15 @@ export class PointCloudMaterial extends RawShaderMaterial { } } - this.setUniform('clipBoxes', clipBoxesArray); + const texture = this.clipBoxesTexture; + if (texture) { + texture.image.data.set(clipBoxesArray); + texture.needsUpdate = true; + } + + if (doUpdate) { + this.updateShaderSource(); + } } get gradient(): IGradient { diff --git a/src/materials/shaders/pointcloud.vert b/src/materials/shaders/pointcloud.vert index 9b759799..74edd5d1 100644 --- a/src/materials/shaders/pointcloud.vert +++ b/src/materials/shaders/pointcloud.vert @@ -1,7 +1,7 @@ precision highp float; precision highp int; -#define max_clip_boxes 30 +#define max_clip_boxes 1000 attribute vec3 position; attribute vec3 color; @@ -32,10 +32,6 @@ uniform float screenHeight; uniform float fov; uniform float spacing; -#if defined use_clip_box - uniform mat4 clipBoxes[max_clip_boxes]; -#endif - uniform float heightMin; uniform float heightMax; uniform float size; // pixel size factor @@ -71,6 +67,7 @@ uniform sampler2D visibleNodes; uniform sampler2D gradient; uniform sampler2D classificationLUT; uniform sampler2D depthMap; +uniform highp sampler2D clipBoxesTexture; #ifdef use_texture_blending uniform sampler2D backgroundMap; @@ -570,7 +567,17 @@ void main() { break; } - vec4 clipPosition = clipBoxes[i] * modelMatrix * vec4(position, 1.0); + float tx = mod(float(i) * 4.0, 256.0); + float ty = floor(float(i) * 4.0 / 256.0); + + mat4 clipBox = mat4( + texture2D(clipBoxesTexture, vec2((tx + 0.0) / 256.0 , ty / 256.0)), + texture2D(clipBoxesTexture, vec2((tx + 1.0) / 256.0, ty / 256.0)), + texture2D(clipBoxesTexture, vec2((tx + 2.0) / 256.0, ty / 256.0)), + texture2D(clipBoxesTexture, vec2((tx + 3.0) / 256.0, ty / 256.0)) + ); + + vec4 clipPosition = clipBox * modelMatrix * vec4(position, 1.0); bool inside = -0.5 <= clipPosition.x && clipPosition.x <= 0.5; inside = inside && -0.5 <= clipPosition.y && clipPosition.y <= 0.5; inside = inside && -0.5 <= clipPosition.z && clipPosition.z <= 0.5; diff --git a/src/materials/texture-generation.ts b/src/materials/texture-generation.ts index ddaf6e24..1e8d080c 100644 --- a/src/materials/texture-generation.ts +++ b/src/materials/texture-generation.ts @@ -1,11 +1,14 @@ import { CanvasTexture, + ClampToEdgeWrapping, Color, DataTexture, + FloatType, LinearFilter, NearestFilter, RGBAFormat, Texture, + UVMapping, } from 'three'; import { IClassification, IGradient } from '../materials/types'; @@ -92,3 +95,16 @@ export function generateClassificationTexture(classification: IClassification): return texture; } + +export function generateClipboxTexture(): DataTexture { + const width = 256; + const height = 256; + const size = width * height; + + const data = new Float32Array(size * 4); + + const texture = new DataTexture(data, width, height, RGBAFormat, FloatType, UVMapping, ClampToEdgeWrapping, ClampToEdgeWrapping, NearestFilter, NearestFilter); + texture.needsUpdate = true; + + return texture; +}