- a slicing volume layers

- slicing all layers with same uniform parameter from src/js/clip/uniforms.js
- main.js: add backStencil and frontStencil
- npm updates
This commit is contained in:
Arno Kaimbacher 2021-05-04 10:12:10 +02:00
parent 9f78d77c39
commit 0ebd32c79d
8 changed files with 465 additions and 344 deletions

View File

@ -6,6 +6,7 @@
"plugins": [
["@babel/plugin-proposal-decorators", { "legacy": true }],
["@babel/plugin-proposal-class-properties", { "loose": true }],
["@babel/plugin-proposal-private-methods", { "loose": true }],
["@babel/plugin-transform-runtime", { "regenerator": true }],
"@babel/proposal-object-rest-spread"
]

538
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -9,6 +9,10 @@ import { Layer } from '../layer/Layer';
import { Group } from 'three/src/objects/Group';
export class Selection extends Layer {
visible;
opacity;
type;
limit;
limitLow;
limitHigh;
box;
@ -18,6 +22,7 @@ export class Selection extends Layer {
faces;
map;
scale;
boxLines;
constructor(parameters, low, high) {
super();
@ -92,6 +97,12 @@ export class Selection extends Layer {
this.emit('add');
}
onRemove(map) {
map.scene.remove(this.displayMeshes);
map.scene.remove(this.touchMeshes);
}
build(app_scene) {
// app_scene.add(this.boxMesh);
app_scene.add(this.displayMeshes);
@ -99,7 +110,7 @@ export class Selection extends Layer {
}
setWireframeMode(wireframe) {
return;
return wireframe;
}
setVisible(visible) {
@ -175,17 +186,18 @@ export class Selection extends Layer {
let unif = uniforms.clipping;
unif.clippingLow.value.copy(this.limitLow);
unif.clippingHigh.value.copy(this.limitHigh);
unif.clippingScale.value = this.scale;
if (this.map.layers) {
for (const [key, layer] of Object.entries(this.map.layers)) {
if (layer.uniforms ) {
let scale = Number(this.scale);
layer.uniforms.clipping.clippingLow.value.copy(this.limitLow);
layer.uniforms.clipping.clippingHigh.value.copy(this.limitHigh);
layer.uniforms.clipping.clippingScale.value = scale;
}
}
}
// if (this.map.layers) {
// for (const [key, layer] of Object.entries(this.map.layers)) {
// if (layer.uniforms ) {
// let scale = Number(this.scale);
// layer.uniforms.clipping.clippingLow.value.copy(this.limitLow);
// layer.uniforms.clipping.clippingHigh.value.copy(this.limitHigh);
// layer.uniforms.clipping.clippingScale.value = scale;
// }
// }
// }
}
setValue(axis, value) {

View File

@ -9,7 +9,6 @@ export class SelectionBoxFace {
let frontFaceGeometry = this.fontFaceGeometry = new PlaneGeometry(v0, v1, v2, v3);
// frontFaceGeometry.dynamic = true;
selection.meshGeometries.push(frontFaceGeometry);
let frontFaceMesh = new Mesh(frontFaceGeometry, material.Invisible);
frontFaceMesh.axis = axis;
frontFaceMesh.guardian = this;
@ -19,7 +18,6 @@ export class SelectionBoxFace {
let backFaceGeometry = this.backFaceGeometry = new PlaneGeometry(v3, v2, v1, v0);
// backFaceGeometry.dynamic = true;
selection.meshGeometries.push(backFaceGeometry);
let backFaceMesh = new Mesh(backFaceGeometry, material.BoxBackFace);
selection.displayMeshes.add(backFaceMesh);

View File

@ -3,7 +3,7 @@ import { LineBasicMaterial } from 'three/src/materials/LineBasicMaterial';
import { ShaderMaterial } from 'three/src/materials/ShaderMaterial';
import { uniforms } from "./uniforms";
import { shader } from './shader';
import { DoubleSide } from 'three/src/constants';
import { DoubleSide, BackSide } from 'three/src/constants';
let capMaterial = new ShaderMaterial({
uniforms: uniforms.caps,
@ -11,18 +11,27 @@ let capMaterial = new ShaderMaterial({
fragmentShader: shader.fragment
});
let frontStencilMaterial = new ShaderMaterial( {
uniforms: uniforms.clipping,
vertexShader: shader.vertexClipping,
let frontStencilMaterial = new ShaderMaterial({
uniforms: uniforms.clipping,
vertexShader: shader.vertexClipping,
fragmentShader: shader.fragmentClippingFront,
// colorWrite: false,
// depthWrite: false,
} );
colorWrite: false,
depthWrite: false,
});
let backStencilMaterial = new ShaderMaterial({
uniforms: uniforms.clipping,
vertexShader: shader.vertexClipping,
fragmentShader: shader.fragmentClippingFront,
colorWrite: false,
depthWrite: false,
side: BackSide
});
// beige:
// let BoxBackFace = new MeshBasicMaterial({ color: 0xEEDDCC, transparent: true });
let BoxBackFace = new MeshBasicMaterial({ color: 0xf8f8ff, transparent: true, opacity: 0.5 });
// black box grid:
// black box grid: mouse grey:
// let BoxWireframe = new LineBasicMaterial({ color: 0x000000, linewidth: 2 });
let BoxWireframe = new LineBasicMaterial({ color: 0x6f6f6f, linewidth: 3 });
@ -38,6 +47,7 @@ let Invisible = new ShaderMaterial({
export {
capMaterial,
frontStencilMaterial,
backStencilMaterial,
BoxBackFace,
BoxWireframe,
BoxWireActive,

View File

@ -4,12 +4,19 @@ import { Color } from 'three/src/math/Color';
let uniforms = {
clipping: {
// light blue:
color: { type: "c", value: new Color(0x3d9ecb) },
clippingLow: { type: "v3", value: new Vector3(0, 0, 0) },
clippingHigh: { type: "v3", value: new Vector3(0, 0, 0) }
clippingHigh: { type: "v3", value: new Vector3(0, 0, 0) },
// additional parameter for scaling
clippingScale: { type: "f", value: 1.0 },
// topography
map: { type: 't', value: null },
percent: { type: "f", value: 1 }
},
caps: {
// red
color: { type: "c", value: new Color(0xf83610) }
}

View File

@ -18,6 +18,7 @@ import { Vector2 } from 'three/src/math/Vector2';
import { Matrix4 } from 'three/src/math/Matrix4';
import { Box3 } from 'three/src/math/Box3';
import { PlaneGeometry } from 'three/src/geometries/PlaneGeometry';
import { uniforms } from '../clip/uniforms';
const POINTURL = 'https://geusegdi01.geus.dk/geom3d/data/nodes/';
const EDGEURL = 'https://geusegdi01.geus.dk/geom3d/data/triangles/';
@ -38,16 +39,18 @@ class TinLayer extends Layer {
featuregeom_id: number;
color: string;
mainMesh;
uniforms = {
clipping: {
clippingScale: { type: "f", value: 1.0 },
color: { type: "c", value: null },
clippingLow: { type: "v3", value: new Vector3(0, 0, 0) },
clippingHigh: { type: "v3", value: new Vector3(0, 0, 0) },
map: { type: 't', value: null },
percent: { type: "f", value: 1 }
}
};
geometry: BufferGeometry;
uniforms;
// uniforms = {
// clipping: {
// clippingScale: { type: "f", value: 1.0 },
// color: { type: "c", value: null },
// clippingLow: { type: "v3", value: new Vector3(0, 0, 0) },
// clippingHigh: { type: "v3", value: new Vector3(0, 0, 0) },
// map: { type: 't', value: null },
// percent: { type: "f", value: 1 }
// }
// };
public baseExtent = {
min: { x: 0, y: 0 },
max: { x: 0, y: 0 }
@ -89,6 +92,7 @@ class TinLayer extends Layer {
this.scale = 1;
this.objectGroup = new Group();
this.q = true;
this.uniforms = uniforms;
}
setWireframeMode(wireframe) {
@ -298,7 +302,7 @@ class TinLayer extends Layer {
}
async build(app_scene) {
let geometry = new BufferGeometry();
let geometry = this.geometry = new BufferGeometry();
let vertices = await (this.points(this.featuregeom_id));
let positions = new Float32BufferAttribute(vertices, 3);
@ -344,17 +348,18 @@ class TinLayer extends Layer {
let color = parseInt(this.color, 16);
if (this.name == "Topography") {
let width = this.baseExtent.max.x - this.baseExtent.min.x;
let height = this.baseExtent.max.y - this.baseExtent.min.y;
let planeGeometry = new PlaneGeometry(width, height, 298, 134)
let planeMaterial = new MeshLambertMaterial({ color: 0xecf0f1, side: DoubleSide });
let planeMesh = new Mesh(planeGeometry, planeMaterial);
let center = new Vector3((this.baseExtent.min.x + this.baseExtent.max.x) / 2, (this.baseExtent.min.y + this.baseExtent.max.y) / 2, 0);
planeMesh.position.x = center.x;
planeMesh.position.y = center.y;
this._addObject(planeMesh, false);
// //add bounding box of layer:
// let width = this.baseExtent.max.x - this.baseExtent.min.x;
// let height = this.baseExtent.max.y - this.baseExtent.min.y;
// let planeGeometry = new PlaneGeometry(width, height, 298, 134)
// let planeMaterial = new MeshLambertMaterial({ color: 0xecf0f1, side: DoubleSide });
// let planeMesh = new Mesh(planeGeometry, planeMaterial);
// let center = new Vector3((this.baseExtent.min.x + this.baseExtent.max.x) / 2, (this.baseExtent.min.y + this.baseExtent.max.y) / 2, 0);
// planeMesh.position.x = center.x;
// planeMesh.position.y = center.y;
// this._addObject(planeMesh, false);
// load image:
let image = this.images[0];
if (image.texture === undefined) {
@ -368,16 +373,15 @@ class TinLayer extends Layer {
if (image.type == "wms") {
image.texture = await this.loadTextureWms(image.url, image);
}
}
this.uniforms.clipping.clippingScale = { type: "f", value: 1.0 };
this.uniforms.clipping.clippingLow = { type: "v3", value: new Vector3(0, 0, 0) };
this.uniforms.clipping.clippingHigh = { type: "v3", value: new Vector3(0, 0, 0) };
// this.uniforms.clipping.clippingScale = { type: "f", value: 1.0 };
// this.uniforms.clipping.clippingLow = { type: "v3", value: new Vector3(0, 0, 0) };
// this.uniforms.clipping.clippingHigh = { type: "v3", value: new Vector3(0, 0, 0) };
this.uniforms.clipping.map = { type: 't', value: image.texture };
this.uniforms.clipping.percent = { type: "f", value: 0.7 };
//calculate UV coordinates, if uv attribute is not present, it will be added
//calculate UV coordinates for projecting image, if uv attribute is not present, it will be added
// https://jsfiddle.net/mmalex/pcjbysn1/
// https://stackoverflow.com/questions/20774648/three-js-generate-uv-coordinate
this.applyBoxUV(geometry, new Matrix4());
@ -392,24 +396,17 @@ class TinLayer extends Layer {
// });
this.material = new ShaderMaterial({
transparent: true,
side: DoubleSide,
uniforms: this.uniforms.clipping,
// side: DoubleSide,
uniforms: this.uniforms.clipping,
vertexShader: shader.vertexClipping,
fragmentShader: shader.fragmentClippingFront,
});
} else {
// let uniforms = this.uniforms.clipping = {
// clippingScale: { type: "f", value: 1.0 },
// color: { type: "c", value: new Color(color) },
// clippingLow: { type: "v3", value: new Vector3(0, 0, 0) },
// clippingHigh: { type: "v3", value: new Vector3(0, 0, 0) }
// }
// };
this.uniforms.clipping.clippingScale = { type: "f", value: 1.0 };
this.uniforms.clipping.color = { type: "c", value: new Color(color) };
this.uniforms.clipping.clippingLow = { type: "v3", value: new Vector3(0, 0, 0) };
this.uniforms.clipping.clippingHigh = { type: "v3", value: new Vector3(0, 0, 0) };
} else {
// this.uniforms.clipping.clippingScale = { type: "f", value: 1.0 };
// this.uniforms.clipping.color = { type: "c", value: new Color(color) };
// this.uniforms.clipping.clippingLow = { type: "v3", value: new Vector3(0, 0, 0) };
// this.uniforms.clipping.clippingHigh = { type: "v3", value: new Vector3(0, 0, 0) };
this.material = new MyMeshStandardMaterial({
color: color,
@ -418,6 +415,7 @@ class TinLayer extends Layer {
flatShading: true,
side: DoubleSide
}, this.uniforms.clipping);
// }, this.uniforms.clipping);
}
this.materialsArray.push(this.material);

View File

@ -4,7 +4,7 @@ import { WebGLRenderer } from 'three/src/renderers/WebGLRenderer';
import { Scene } from 'three/src/scenes/Scene';
import { Vector3 } from 'three/src/math/Vector3';
import { GridLayer } from './layer/GridLayer';
import { DemLayer } from './layer/DemLayer';
// import { DemLayer } from './layer/DemLayer';
import { Map } from './core/Map';
import * as domEvent from './core/domEvent';
import { Coordinates } from './controls/Coordinates';
@ -20,11 +20,14 @@ import * as browser from './core/browser';
import * as domUtil from './core/domUtil';
import { PickingTool } from './clip/PickingTool';
import { ShowModal } from './components/ShowModal';
import * as material from './clip/material';
import { Group } from 'three/src/objects/Group';
import { Selection } from './clip/Selection';
import _ from "lodash";
import '../css/page_bulma.scss'; /* style loader will import it */
import { TinLayer } from './layer/TinLayer';
class Application {
@ -56,15 +59,12 @@ class Application {
this.downloadButton = document.querySelector('#menu-dowload-button');
this.menuIcon = document.querySelector('#menu-icon');
this.navigation = document.getElementsByClassName('navigation')[0];
// this.addEventListeners();
let parentContainer = document.getElementById("app");
this.dialog = new ShowModal("Help", parentContainer, { klass: "fm_about" });
// this.dialog = new MobileDialog("Help", container, { klass: "fm_about" });
this.aboutIcon = document.querySelector('#menu-about-icon');
// this.createScene();
// this.addEventListeners();
}
@ -97,6 +97,7 @@ class Application {
this.renderer.setSize(this.width, this.height);
this.renderer.autoClear = false;
this.renderer.setClearColor(0x000000, 0.0); // second param is opacity, 0 => transparent
// this.renderer.setClearColor( 0xffffff );
// enable clipping
// let Empty = Object.freeze([]);
@ -107,8 +108,8 @@ class Application {
/* Scene: that will hold all our elements such as objects, cameras and lights. */
this.scene = new Scene();
this.capsScene = new Scene();
// this.backStencil = new Scene();
// this.frontStencil = new Scene();
this.backStencil = new Scene();
this.frontStencil = new Scene();
this._buildDefaultLights(this.scene);
//app.scene.autoUpdate = false;
//// show axes in the screen
@ -163,18 +164,46 @@ class Application {
this.mapTitle.innerHTML += map.title;
map.on('ready', () => {
this.selectionBox.setUniforms();
this.capsScene.add(this.selectionBox.boxMesh);
// this.scene.add(this.selection.displayMeshes);
// this.scene.add(this.selection.touchMeshes);
this.map.addLayer(this.selectionBox);
let frontGroup = new Group();
for (var i in map.layers) {
let layer = map.layers[i];
if (layer instanceof TinLayer && layer.name != "Topography") {
let mesh = new Mesh(layer.geometry.clone(), material.frontStencilMaterial);
frontGroup.add(mesh);
}
}
frontGroup.updateMatrix();
// let frontMesh = new Mesh(frontGroup, material.frontStencilMaterial);
this.frontStencil.add(frontGroup);
let backGroup = new Group();
for (var i in map.layers) {
let layer = map.layers[i];
if (layer instanceof TinLayer && layer.name != "Topography") {
let mesh = new Mesh(layer.geometry.clone(), material.backStencilMaterial);
backGroup.add(mesh);
}
}
backGroup.updateMatrix();
// let frontMesh = new Mesh(frontGroup, material.frontStencilMaterial);
this.backStencil.add(backGroup);
this.animate();
}, this);
this.selectionBox = new Selection(
// new Vector3(-7, -14, -14),
// new Vector3(14, 9, 3)
{ name: 'Slicing Box' },
new Vector3(this.map.x.min, this.map.y.min, this.map.z.min),
new Vector3(this.map.x.max, this.map.y.max, this.map.z.max)
);
this.map.addLayer(this.selectionBox);
// this.map.addLayer(this.selectionBox);
this.map.picking = new PickingTool(this.map.size, this.map.center, this);
@ -185,7 +214,7 @@ class Application {
//add map controls:
if (util.hasTouch() == false) {
let coordinates = new Coordinates({ camera: this.map.camera, crs: "EPSG:3034" }).addTo(this.map);
new Coordinates({ camera: this.map.camera, crs: "EPSG:3034" }).addTo(this.map);
// coordinates.addListener('onPoint', (args) => {
// let vector = args[0];
// this.queryMarker.position.set(vector.x, vector.y, vector.z);
@ -195,7 +224,7 @@ class Application {
}
this.northArrow = new NorthArrow({ headLength: 1, headWidth: 1 }).addTo(this.map);
this.gridlayer = new GridLayer({ center: this.map.center, name: "coordinate grid", appWidth: this.width, appHeight: this.height });
this.map.addLayer(this.gridlayer);
@ -212,14 +241,6 @@ class Application {
//slider for scaling z value
this.slider = new SliderControl({ layers: this.map.layers }).addTo(this.map);
//slice on x and y axes:
// this.slicer = new SlicerControl({ parentDiv: 'slicer-control' }).addTo(this.map);
this.capsScene.add(this.selectionBox.boxMesh);
// this.scene.add(this.selection.displayMeshes);
// this.scene.add(this.selection.touchMeshes);
this.start();
}
@ -242,7 +263,6 @@ class Application {
let layer = this.map._layers[key];
layer.setWireframeMode(wireframe);
}
this.wireframeMode = wireframe;
this.animate();
}
@ -308,36 +328,36 @@ class Application {
this.renderer.clear();
// The HTML5 Canvas's 'webgl' context obtained from the canvas where the renderer will draw.
let gl = this.renderer.context;
let gl = this.renderer.getContext();
if (this.showCaps && gl != undefined) {
// enable stencil test
gl.enable(gl.STENCIL_TEST);
gl.enable(gl.STENCIL_TEST);
// this.renderer.state.setStencilFunc( true );
// gl.stencilFunc( gl.ALWAYS, 1, 0xff );
// gl.stencilOp( gl.REPLACE, gl.REPLACE, gl.REPLACE );
this.renderer.state.setStencilTest(true);
gl.StencilFunc(gl.ALWAYS, 1, 0xff);
gl.StencilOp(gl.KEEP, gl.KEEP, gl.INCR);
// this.renderer.render(this.backStencil, this.camera);
gl.stencilFunc(gl.ALWAYS, 1, 0xff);
gl.stencilOp(gl.KEEP, gl.KEEP, gl.INCR);
this.renderer.render(this.backStencil, this.map.camera);
gl.stencilFunc(gl.ALWAYS, 1, 0xff);
gl.StencilOp(gl.KEEP, gl.KEEP, gl.DECR);
// this.renderer.render(this.frontStencil, this.camera);
gl.stencilOp(gl.KEEP, gl.KEEP, gl.DECR);
this.renderer.render(this.frontStencil, this.map.camera);
gl.StencilFunc(gl.EQUAL, 1, 0xff);
gl.StencilOp(gl.KEEP, gl.KEEP, gl.KEEP);
this.renderer.render(this.capsScene, this.camera);
this.renderer.state.setStencilTest(false);
gl.stencilFunc(gl.EQUAL, 1, 0xff);
gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP);
this.renderer.render(this.capsScene, this.map.camera);
// disable stencil test
gl.disable(gl.STENCIL_TEST);
// gl.stencilMask(0);
// this.renderer.state.setStencilFunc( false );
}
this.renderer.render(this.scene, this.map.camera);
this.northArrow.animate();
this.gridlayer.animate();
}
@ -358,11 +378,6 @@ class Application {
this.dialog.show();
}, this);
// domEvent.on(this.menuIcon, 'click', function (e) {
// e.preventDefault();
// this.navigation.classList.toggle("active");
// }, this);
const $navbarBurgers = Array.prototype.slice.call(document.querySelectorAll('.navbar-burger'), 0);
// Check if there are any navbar burgers
if ($navbarBurgers.length > 0) {
@ -409,24 +424,6 @@ class Application {
}
downloadMapImage() {
// if(!this.$imageInput.files[0]) {
// this.$imageInput.parentElement.classList.add('has-error');
// return;
// }
// if(this.$bottomTextInput.value === '') {
// this.$imageInput.parentElement.classList.remove('has-error');
// this.$bottomTextInput.parentElement.classList.add('has-error');
// return;
// }
// this.$imageInput.parentElement.classList.remove('has-error');
// this.$bottomTextInput.parentElement.classList.remove('has-error');
// const imageSource = this.renderer.domElement.toDataURL('image/png');
// const att = document.createAttribute('href');
// att.value = imageSource.replace(/^data:image\/[^;]/, 'data:application/octet-stream');
// this.downloadButton.setAttributeNode(att);
// this.renderer.preserveDrawingBuffer = true;
// this.renderer.render(this.scene, this.camera);
this.saveCanvasImage(this.renderer.domElement);
}
@ -437,14 +434,10 @@ class Application {
var binStr = atob(canvas.toDataURL("image/png").split(',')[1]);
var len = binStr.length;
var arr = new Uint8Array(len);
for (var i = 0; i < len; i++) {
arr[i] = binStr.charCodeAt(i);
}
this.saveBlob(new Blob([arr], { type: "image/png" }));
}
saveBlob(blob) {