123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321 |
- import * as THREE from 'three';
- import texture1 from "../../assets/tex_white_8.png";
- import texture2 from "../../assets/max_texture1.png";
- export const ThreeCubeDetailClass = {
- constructor(options) {
- this.webgl = options.webgl;
- this.view = options.view;
- this.points = options.points;
- this.mesh = options.mesh;
- this.edgesReferences = options.edgesReferences;
- this._camera = options._camera;
- this.lastSelectedIndex = options.lastSelectedIndex;
- this.selectedIndex = options.selectedIndex;
- this.raycaster = options.raycaster; // 射线投射器
- this.mouse = options.mouse; // 鼠标位置
- this.callBackFunction = options.callBackFunction; // 回调函数
- this.mouseClickEvent = null;
- this.depthTest = options.depthTest; //false是优先级低,true是优先级高
- this.deepOpacity = options.deepOpacity;
- },
- initialize() {
- this.renderer = new THREE.WebGLRenderer({
- context: this.gl,
- premultipliedAlpha: false
- });
- this.renderer.setPixelRatio(window.devicePixelRatio);
- this.renderer.setViewport(0, 0, this.view.width, this.view.height);
- this.renderer.autoClear = false;
- this.renderer.autoClearDepth = false;
- this.renderer.autoClearColor = false;
- let originalSetRenderTarget = this.renderer.setRenderTarget.bind(this.renderer);
- this.renderer.setRenderTarget = function (target) {
- originalSetRenderTarget(target);
- if (target == null) {
- context.bindRenderTarget();
- }
- };
- // 创建场景和相机
- this.scene = new THREE.Scene();
- let cam = this.camera;
- this._camera = new THREE.PerspectiveCamera(cam.fovY, cam.aspect, 0.1, 1000000000);
- // 创建坐标轴和网格辅助工具
- const axesHelper = new THREE.AxesHelper(1);
- axesHelper.position.copy(1000000, 100000, 100000);
- this.scene.add(axesHelper);
- let grid = new THREE.GridHelper(30, 10, 0xf0f0f0, 0xffffff);
- this.scene.add(grid);
- this.createInstancedMesh();
- this.addPoints([]);
- // 灯光
- const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
- this.scene.add(ambientLight);
- const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
- directionalLight.position.set(10, 10, 10);
- this.scene.add(directionalLight);
- this.mouseClickEvent = this.view.on("click", this.onMouseClick.bind(this));
- },
- createInstancedMesh() {
- this.points = [];
- this.currentCount = 0; // 已绘制点的数量
- const boxGeometry = new THREE.BoxGeometry(this.size.z, this.size.x, this.size.y);
- boxGeometry.computeVertexNormals();
- let texture;
- if(this.deepOpacity){ //深度贴图
- texture = new THREE.TextureLoader().load(texture2);
- }else{
- texture = new THREE.TextureLoader().load(texture1);
- }
- //const texture = new THREE.TextureLoader().load(texture1);
- // texture.wrapS = THREE.RepeatWrapping; // 设置U轴的重复模式
- // texture.wrapT = THREE.RepeatWrapping; // 设置V轴的重复模式
- // texture.repeat.set(1, 1); // 设置重复次数
- const material = new THREE.MeshPhongMaterial({
- map: texture,
- transparent: true,
- opacity: 0.5,
- depthTest: this.depthTest,
- side: THREE.DoubleSide,
- depthWrite: false,
- });
- material.onBeforeCompile = (shader) => {
- shader.vertexShader = `
- attribute vec3 instanceColor;
- varying vec3 vColor;
- ` + shader.vertexShader;
- shader.vertexShader = shader.vertexShader.replace(
- `#include <begin_vertex>`,
- `
- #include <begin_vertex>
- vColor = instanceColor;
- `
- );
- shader.fragmentShader = `
- varying vec3 vColor;
- ` + shader.fragmentShader;
- shader.fragmentShader = shader.fragmentShader.replace(
- `#include <dithering_fragment>`,
- `
- #include <dithering_fragment>
- gl_FragColor.rgb = vColor;
- `
- );
- };
- this.mesh = new THREE.InstancedMesh(boxGeometry, material, 500000); // 预设容量
- const instanceColors = new Float32Array(500000 * 3);
- boxGeometry.setAttribute('instanceColor', new THREE.InstancedBufferAttribute(instanceColors, 3));
- this.scene.add(this.mesh);
- this.edgesReferences = [];
- },
- addPoints(newPoints) {
- // 更新 this.points 数据
- this.points.push(...newPoints);
- // 如果实例容量不足,扩展 InstancedMesh
- const totalPoints = this.points.length;
- if (totalPoints > this.mesh.count) {
- const oldMesh = this.mesh;
- const newMesh = new THREE.InstancedMesh(
- oldMesh.geometry,
- oldMesh.material,
- totalPoints
- );
- newMesh.instanceMatrix.copy(oldMesh.instanceMatrix); // 复制已有矩阵数据
- newMesh.geometry.setAttribute(
- 'instanceColor',
- oldMesh.geometry.attributes.instanceColor.clone()
- );
- this.scene.remove(oldMesh);
- this.mesh = newMesh;
- this.scene.add(this.mesh);
- }
- const dummy = new THREE.Object3D();
- const instanceColors = this.mesh.geometry.attributes.instanceColor.array;
- for (let i = this.currentCount; i < totalPoints; i++) {
- const { x, y, z, color } = this.points[i];
- const renderPos = [];
- this.webgl.toRenderCoordinates(
- this.view,
- [x, y, z],
- 0,
- this.view.spatialReference,
- renderPos,
- 0,
- 1
- );
- dummy.position.set(renderPos[0], renderPos[1], renderPos[2]);
- dummy.updateMatrix();
- this.mesh.setMatrixAt(i, dummy.matrix);
- instanceColors[i * 3] = color[0];
- instanceColors[i * 3 + 1] = color[1];
- instanceColors[i * 3 + 2] = color[2];
- // 创建新增点的边框
- const edgesGeometry = new THREE.EdgesGeometry(this.mesh.geometry);
- const glowMaterial = new THREE.LineBasicMaterial({
- color: new THREE.Color(color[0], color[1], color[2]),
- opacity: 0.2,
- linewidth: 1,
- transparent: true,
- side: THREE.DoubleSide,
- });
- const edgeLine = new THREE.LineSegments(edgesGeometry, glowMaterial);
- edgeLine.position.copy(dummy.position);
- // this.scene.add(edgeLine);
- // this.edgesReferences.push(edgeLine);
- }
- // 更新实例属性
- this.mesh.instanceMatrix.needsUpdate = true;
- this.mesh.geometry.attributes.instanceColor.needsUpdate = true;
- // 更新当前点位数
- this.currentCount = totalPoints;
- },
- // 点击事件处理函数
- onMouseClick(event) {
- // 获取点击位置的屏幕坐标
- let mouse = []
- this.webgl.toRenderCoordinates(
- this.view,
- [event.mapPoint.x, event.mapPoint.y, event.mapPoint.z],
- 0,
- this.view.spatialReference,
- mouse,
- 0,
- 1
- );
- const mousePoint = new THREE.Vector3(mouse[0], mouse[1], mouse[2]);
- // 获取摄像机位置
- const cameraPosition = new THREE.Vector3().setFromMatrixPosition(this._camera.matrixWorld);
- // 计算射线方向
- const rayDirection = new THREE.Vector3().subVectors(mousePoint, cameraPosition).normalize();
- // 设置射线起点和方向
- this.raycaster.set(cameraPosition, rayDirection);
- //this.visualizeRay()
- // 检测射线与网格的相交
- const intersects = this.raycaster.intersectObject(this.mesh);
- if (this.lastSelectedIndex !== null && this.lastSelectedIndex !== undefined) {
- this.unHighlightCube(this.lastSelectedIndex);
- }
- if (intersects.length > 0) {
- const instanceIndex = intersects[0].instanceId;
- const selectedCube = this.points[instanceIndex];
- this.callBackFunction(selectedCube);
- // 高亮选中格子
- this.highlightCube(instanceIndex);
- } else {
- console.log("未选中任何格子");
- }
- },
- visualizeRay() {
- // 清理上次绘制的射线(避免重复绘制)
- if (this.rayHelper) {
- this.scene.remove(this.rayHelper);
- }
- // 获取射线的起点和方向
- const rayOrigin = this.raycaster.ray.origin;
- const rayDirection = this.raycaster.ray.direction.clone().multiplyScalar(10000000); // 射线长度为10
- // 创建射线的几何体
- const rayGeometry = new THREE.BufferGeometry().setFromPoints([
- rayOrigin,
- rayOrigin.clone().add(rayDirection),
- ]);
- // 创建射线的材质
- const rayMaterial = new THREE.LineBasicMaterial({
- color: 0xff0000, // 红色射线
- linewidth: 2, // 线宽
- });
- // 创建射线的线条对象
- this.rayHelper = new THREE.Line(rayGeometry, rayMaterial);
- // 将射线添加到场景
- this.scene.add(this.rayHelper);
- console.log("Ray Origin:", rayOrigin);
- console.log("Ray Direction:", rayDirection);
- },
- highlightCube(instanceIndex) {
- const color = new THREE.Color(0xffff); // 红色高亮
- this.setCubeStatus(instanceIndex,color);
- this.lastSelectedIndex = instanceIndex;
- },
- unHighlightCube(instanceIndex){
- const color = new THREE.Color(); // 红色高亮
- color.r = this.points[instanceIndex].color[0];
- color.g = this.points[instanceIndex].color[1];
- color.b = this.points[instanceIndex].color[2];
- this.setCubeStatus(instanceIndex,color);
- },
- setCubeStatus(instanceIndex,color){
- const instanceColors = this.mesh.geometry.attributes.instanceColor.array;
- instanceColors[instanceIndex * 3] = color.r;
- instanceColors[instanceIndex * 3 + 1] = color.g;
- instanceColors[instanceIndex * 3 + 2] = color.b;
- this.mesh.geometry.attributes.instanceColor.needsUpdate = true;
- // 修改边框颜色
- const selectedEdge = this.edgesReferences[instanceIndex];
- if (selectedEdge) {
- selectedEdge.material.color.set(color);
- selectedEdge.material.needsUpdate = true;
- }
- },
- render() {
- let cam = this.camera;
- this._camera.position.set(cam.eye[0], cam.eye[1], cam.eye[2]);
- this._camera.up.set(cam.up[0], cam.up[1], cam.up[2]);
- this._camera.lookAt(new THREE.Vector3(cam.center[0], cam.center[1], cam.center[2]));
- this._camera.projectionMatrix.fromArray(cam.projectionMatrix);
- this.renderer.state.reset();
- this.bindRenderTarget();
- this.renderer.render(this.scene, this._camera);
- this.requestRender();
- this.resetWebGLState();
- }
- };
|