Browse Source

新渲染方式加载

zhiyuan-007 4 months ago
parent
commit
d30f5cea17

+ 11 - 26
src/components/mapJK.vue

@@ -496,12 +496,17 @@ export default {
         if(status == "hide"){
           return
         }
+        let animationEnabled = false;
+        if(params.animationEnabled){
+          animationEnabled = params.animationEnabled;
+        }
         addThreeGridEvent = new AddThreeGridEvent({
           view:m_view,
-          extent : {minX:-60000,maxX:60000,minY:-60000,maxY:60000},
+          extent : {minX:2176,maxX:6048,minY:-1024,maxY:1352},
           height : 1200,
-          size : 200,
-          layerHeight : 400
+          size : 50,
+          layerHeight : 50,
+          animationEnabled
         })
         addThreeGridEvent.start();
       }
@@ -519,29 +524,9 @@ export default {
           view:m_view,
           map:m_map,
           layerId:"WhiteMold",
-          rings:
-              [
-                [
-                  3593.510727444371,
-                  1477.9873809879282,
-                  0
-                ],
-                [
-                  2059.624729191924,
-                  657.1274997157789,
-                  0
-                ],
-                [
-                  2612.404454918337,
-                  -89.310007207348,
-                  0
-                ],
-                [
-                  3269.0228638724784,
-                  474.83225384561496,
-                  0
-                ]
-              ]
+          limitH:params.limitH,
+          maxLimitH:params.maxLimitH,
+          rings:params.rings,
         });
         limitHeightAnalysisEvent.start()
       }

+ 75 - 0
src/config/basicTool.json

@@ -154,6 +154,7 @@
           "ActionName": "ThreeGrid",
           "Parameters": {
             "status": "show",
+            "animationEnabled": true,
             "token": ""
           }
         }
@@ -165,6 +166,80 @@
           "ActionName": "LimitHeightAnalysis",
           "Parameters": {
             "status": "show",
+            "limitH":30,
+            "maxLimitH":50,
+            "rings": [
+              [
+                5247.157017153374,
+                1270.0023461957703,
+                0
+              ],
+              [
+                4336.760437624776,
+                1266.8009572542537,
+                0
+              ],
+              [
+                3491.5636610067518,
+                1259.1626394806458,
+                0
+              ],
+              [
+                2936.531521888444,
+                1110.645927011667,
+                0
+              ],
+              [
+                2374.838356876977,
+                813.8209338083046,
+                0
+              ],
+              [
+                2203.756572715624,
+                557.0385520252402,
+                0
+              ],
+              [
+                2236.8693873322263,
+                298.6578417857288,
+                0
+              ],
+              [
+                2623.475887507855,
+                -94.53847230161708,
+                -4.547473508864641e-13
+              ],
+              [
+                3050.6804353369535,
+                -481.69651302570674,
+                4.547473508864641e-13
+              ],
+              [
+                3479.696719634885,
+                -1045.8470428289725,
+                0
+              ],
+              [
+                4229.590273863496,
+                -700.3542445387985,
+                0
+              ],
+              [
+                5037.960178306457,
+                -386.92470877155085,
+                0
+              ],
+              [
+                5931.864847386253,
+                -46.32862144039693,
+                0
+              ],
+              [
+                5505.553990112907,
+                838.9373631601887,
+                0
+              ]
+            ],
             "token": ""
           }
         }

+ 19 - 13
src/units/map/LimitHeightAnalysis.js

@@ -1,6 +1,5 @@
-import RenderNode from '@arcgis/core/views/3d/webgl/RenderNode.js'
-import * as webgl from "@arcgis/core/views/3d/webgl.js";
-import {LimitHeightClass} from "../threejs/limitHeight.js";
+import * as externalRenderers from '@arcgis/core/views/3d/externalRenderers'
+import {limitForHeight} from "../threejs/limitForHeight.js";
 
 class LimitHeightAnalysis{
     constructor(options) {
@@ -8,6 +7,8 @@ class LimitHeightAnalysis{
         this.m_map = options.map;
         this.layerId = options.layerId || "WhiteMold";
         this.rings = options.rings;
+        this.limitH = options.limitH;
+        this.maxLimitH = options.maxLimitH;
         this.limitHeightAnalysis = null;
     }
     start(){
@@ -15,24 +16,29 @@ class LimitHeightAnalysis{
         if(this.limitHeightAnalysis){
             this.clear()
         };
-        let subRenderClass =  RenderNode.createSubclass(LimitHeightClass);
         let sceneLayer = this.m_map.layers.find(item => item.id === this.layerId);
 
         this.view.when(()=>{
+            debugger
             that.view.whenLayerView(sceneLayer).then((layerView) => {
-                that.limitHeightAnalysis = new subRenderClass({
-                    view: that.view,
-                    webgl,
-                    analyseLayerView : layerView,
-                    analyseLayer : sceneLayer,
-                    drawVertices:that.rings
-                })
-
+                debugger
+                limitForHeight.view = that.view
+                limitForHeight.limitH = that.limitH
+                limitForHeight.maxLimitH = that.maxLimitH
+                limitForHeight.analyseLayerView = layerView
+                limitForHeight.analyseLayer = sceneLayer
+                limitForHeight.externalRenderers = externalRenderers
+                limitForHeight.drawVertices = that.rings;
+                this.limitHeightAnalysis = limitForHeight;
+                externalRenderers.add(that.view, that.limitHeightAnalysis)
             });
         })
     }
     clear(){
-
+        if(this.limitHeightAnalysis){
+            externalRenderers.remove(this.view, this.limitHeightAnalysis)
+            this.limitHeightAnalysis = null
+        }
     }
 
 }

+ 3 - 2
src/units/map/addThreeGridEvent.js

@@ -10,7 +10,7 @@ class AddThreeGridEvent{
         this.height = options.height;
         this.size = options.size;
         this.layerHeight = options.layerHeight;
-        this.layerColors = options.layerColors;
+        this.animationEnabled = options.animationEnabled;
     }
     start(){
         let that = this;
@@ -31,7 +31,8 @@ class AddThreeGridEvent{
                 height:that.height,
                 size:that.size,
                 layerHeight:that.layerHeight,
-            })
+                animationEnabled:that.animationEnabled
+            });
         })
     }
     clear(){

+ 255 - 0
src/units/threejs/limitForHeight.js

@@ -0,0 +1,255 @@
+import * as THREE from 'three'
+
+export const limitForHeight = {
+    view: null,
+    limitH: null,
+    maxLimitH:null,
+    analyseLayerView: null,
+    analyseLayer: null,
+    externalRenderers:null,
+    drawVertices: [],
+    setup(context) {
+        this.renderer = new THREE.WebGLRenderer({
+            context: context.gl,
+            //premultipliedAlpha: false,
+            //antialias: true,
+            //logarithmicDepthBuffer: true,
+            //polygonOffset: true,
+            //polygonoffset 是一个比较常见的消除 z-fighting 的设置项。
+            // 在 threejs 中我们可以设置 material 的 polygonoffset 属性来达到启用的目的。
+            // 其原理是在渲染的时候,将模型的订单稍微向靠近或远离相机的方向做一定的偏移,从而错开两个靠近的面的目的。
+            alpha: true
+        })
+        this.renderer.shadowMap.enabled = true
+        this.renderer.shadowMap.type = THREE.PCFSoftShadowMap
+        //设置设备像素比,可以避免HiDPI设备上绘图模糊
+        this.renderer.setPixelRatio(window.devicePixelRatio)
+        //设置视口大小和三维场景的大小一样
+        this.renderer.setViewport(0, 0, this.view.width, this.view.height)
+        // 防止Three.js清除ArcGIS JS API提供的缓冲区
+        this.renderer.autoClearDepth = false // 定义renderer是否清除深度缓存
+        this.renderer.autoClearStencil = false // 定义renderer是否清除模板缓存
+        this.renderer.autoClearColor = false // 定义renderer是否清除颜色缓存
+        //ArcGIS JS API渲染自定义离屏缓冲区,而不是默认的帧缓冲区。
+        //我们必须将这段代码注入到Three.js运行时中,以便绑定这些缓冲区而不是默认的缓冲区。
+        var originalSetRenderTarget = this.renderer.setRenderTarget.bind(this.renderer)
+        this.renderer.setRenderTarget = function (target) {
+            originalSetRenderTarget(target)
+            this.state.viewport(new THREE.Vector4(0, 0, this.view.width, this.view.height))
+            if (target == null) {
+                context.bindRenderTarget()
+            }
+        }.bind(this.renderer)
+
+        //支持裁切
+        this.renderer.localClippingEnabled = true
+
+        this.scene = new THREE.Scene()
+        this.camera = new THREE.PerspectiveCamera()
+        this.camera.far = 10000000
+        this.ambient = new THREE.AmbientLight(0xffffff, 1)
+        this.scene.add(this.ambient)
+        this.sun = new THREE.DirectionalLight(0xffffff, 0.5)
+        this.scene.add(this.sun)
+
+        this.start(context)
+        context.resetWebGLState()
+    },
+    render(context) {
+        var cam = context.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)
+
+        //更新操作
+        let that = this
+        if (
+            this.meshGroup &&
+            this.meshGroup.children.length > 0 &&
+            this.meshGroup.children[0].material.uniforms
+        ) {
+            this.meshGroup.children.forEach(function (mesh) {
+                mesh.material.uniforms.limit.value = that.limitH
+                mesh.material.uniforms.maxLimit.value = that.maxLimitH
+            })
+        }
+
+        this.renderer.state.reset()
+        //threejs 127版本后 需要加上
+        context.bindRenderTarget()
+        this.renderer.render(this.scene, this.camera)
+        this.externalRenderers.requestRender(this.view)
+        context.resetWebGLState()
+    },
+    async start(context) {
+        if (this.analyseLayerView) {
+            let clipPanels = this.createClipPlane()
+            let meshMaterial = this.analysisRender()
+            meshMaterial.clippingPlanes = clipPanels
+            this.meshGroup = new THREE.Group()
+            debugger
+            let posGroup = await this.analyseLayerView.getFeatureInfo()
+            this.createGeometry(posGroup)
+            this.meshGroup &&
+            this.meshGroup.children.forEach(function (mesh) {
+                mesh.material = meshMaterial
+            })
+            this.scene.add(this.meshGroup)
+        }
+    },
+    createGeometry(posGroup) {
+        posGroup.forEach((object_pos) => {
+            var geometry = new THREE.BufferGeometry()
+            geometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array(object_pos), 3))
+            geometry.computeBoundingBox()
+            geometry.computeBoundingSphere()
+            geometry.computeVertexNormals()
+
+            const positions = geometry.attributes.position
+            const normals = geometry.attributes.normal
+            let uvs = []
+            // 计算UV坐标
+            for (let i = 0; i < positions.count; i++) {
+                const normal = new THREE.Vector3(
+                    normals.getX(i),
+                    normals.getY(i),
+                    normals.getZ(i)
+                ).normalize()
+
+                const position = new THREE.Vector3(positions.getX(i), positions.getY(i), positions.getZ(i))
+                uvs.push((normal.x + 1) / 2, (normal.y + 1) / 2)
+            }
+            geometry.setAttribute('uv', new THREE.BufferAttribute(Float32Array.from(uvs), 2, false))
+            var material = new THREE.MeshPhongMaterial({
+                color: 'red',
+                transparent: false,
+                // opacity: 0.3,
+                polygonOffset: true,
+                polygonOffsetFactor: -0.5,
+                polygonOffsetUnits: -0.5
+            })
+            var mesh = new THREE.Mesh(geometry, material)
+            mesh.updateMatrix()
+            this.meshGroup.add(mesh)
+        })
+    },
+    //根据多边形点创建裁切面
+    createClipPlane() {
+        let clipPanels = []
+        debugger
+        this.drawVertices.push(this.drawVertices[0])
+        for (let k = 0; k < this.drawVertices.length - 1; k++) {
+            let point1 = this.drawVertices[k]
+            let point2 = this.drawVertices[k + 1]
+            let base1 = []
+            let base2 = []
+            let top1 = []
+            this.externalRenderers.toRenderCoordinates(
+                this.view,
+                [point1[0], point1[1], 0],
+                0,
+                this.view.spatialReference,
+                base1,
+                0,
+                1
+            )
+            this.externalRenderers.toRenderCoordinates(
+                this.view,
+                [point2[0], point2[1], 0],
+                0,
+                this.view.spatialReference,
+                base2,
+                0,
+                1
+            )
+            this.externalRenderers.toRenderCoordinates(
+                this.view,
+                [point1[0], point1[1], point1[2] + 1000],
+                0,
+                this.view.spatialReference,
+                top1,
+                0,
+                1
+            )
+            let plane = new THREE.Plane()
+            let p1_1 = new THREE.Vector3(base1[0], base1[1], base1[2])
+            let p2_1 = new THREE.Vector3(top1[0], top1[1], top1[2])
+            let p3_1 = new THREE.Vector3(base2[0], base2[1], base2[2])
+            plane.setFromCoplanarPoints(p1_1, p2_1, p3_1)
+            clipPanels.push(plane)
+        }
+        return clipPanels
+    },
+    analysisRender() {
+        //let texture = new THREE.TextureLoader().load('images/view.png');
+        let material = new THREE.MeshBasicMaterial({
+            //map: texture,
+            color: '#FF0000',
+            opacity: 0.8,
+            transparent: true,
+            side: THREE.DoubleSide,
+            depthTest: false
+        })
+        material.onBeforeCompile = function (shader, renderer) {
+            debugger
+            //声明用到的变量和常量
+            const getFoot = `
+          uniform mat4 cameraMatrix;
+          uniform mat4 projectionMatrixInverse;
+          varying float depth;
+          varying vec2 depthUv;
+          //varying vec2 vUv;
+          varying vec4 vPosition;
+          #include <common>
+          `
+            const begin_vertex = `
+          #include <worldpos_vertex>
+          vPosition= modelMatrix * vec4(transformed, 1.0 );
+          `
+            const height_vary = `
+          uniform float opacity;
+          uniform float limit;
+          uniform float maxLimit;
+          uniform float baseHeight;
+          varying vec4 vPosition;
+          float getHeight(vec3 point){
+            float distR = length(point);
+            float height=distR-6378137.0;
+            return height-0.1;
+          }
+          `
+            const height_frag = `
+                    vec3 outgoingLight = reflectedLight.indirectDiffuse;
+          float ph=getHeight(vPosition.xyz);
+          if(ph>=limit&&ph<=maxLimit){
+            //gl_FragColor = vec4( outgoingLight, diffuseColor.a );
+          }else{
+            diffuseColor.a=0.0;
+          }
+          `
+            shader.vertexShader = shader.vertexShader.replace('#include <common>', getFoot)
+            shader.vertexShader = shader.vertexShader.replace('#include <worldpos_vertex>', begin_vertex)
+            shader.fragmentShader = shader.fragmentShader.replace('uniform float opacity;', height_vary)
+
+            shader.fragmentShader = shader.fragmentShader.replace(
+                'vec3 outgoingLight = reflectedLight.indirectDiffuse;',
+                height_frag
+            )
+            //shader.fragmentShader = shader.fragmentShader.replace('gl_FragColor = vec4( outgoingLight, diffuseColor.a );', height_frag)
+            shader.uniforms.limit = {
+                value: this.limitH
+            }
+            shader.uniforms.maxLimit = {
+                value: this.maxLimitH
+            }
+            shader.uniforms.baseHeight = {
+                value: 0.0
+            }
+            material.uniforms = shader.uniforms
+        }
+        material.needsUpdate = true
+        return material
+    }
+}

+ 74 - 20
src/units/threejs/threeGrid.js

@@ -11,11 +11,16 @@ export const ThreeGridClass = {
         this.layerColors = this.layerColors || [new THREE.Color(0xff0000), new THREE.Color(0x00ff00), new THREE.Color(0x0000ff)] // 自定义每层颜色
         this.mesh = null;
         this._camera = null;
+        this.currentLayer = 0;
+        this.mergedLineMesh = null;
+        this.animationEnabled =this.animationEnabled || false;
+        this.edgeMaterial = null;
     },
 
 
     initialize() {
         this.layerColors = [new THREE.Color(0xff0000), new THREE.Color(0x00ff00), new THREE.Color(0x0000ff)];
+        this.currentLayer = 0;
         this.renderer = new THREE.WebGLRenderer({
             context: this.gl,
             premultipliedAlpha: false,
@@ -37,7 +42,7 @@ export const ThreeGridClass = {
         // 场景和相机
         this.scene = new THREE.Scene();
         let cam = this.camera;
-        this._camera = new THREE.PerspectiveCamera(cam.fovY, cam.aspect, cam.near, cam.far);
+        this._camera = new THREE.PerspectiveCamera(cam.fovY, cam.aspect, 0.1, 1000000000);
         // 添加坐标轴辅助工具
         const axesHelper = new THREE.AxesHelper(1);
         axesHelper.position.copy(1000000, 100000, 100000);
@@ -62,16 +67,21 @@ export const ThreeGridClass = {
 
         // 每秒更新一次网格颜色
         setInterval(() => {
-            this.updateColors();
-        }, 1000);
+            if (this.animationEnabled) {
+                // 恢复显示所有内容
+                this.updateColors();
+            }
+        }, 100);
     },
 
     createInstancedMesh() {
         const geometry = new THREE.BoxGeometry(this.layerHeight, this.size, this.size);
-
+        geometry.computeVertexNormals();  // 计算并更新顶点法线
         const material = new THREE.MeshPhongMaterial({
             transparent: true,
             opacity: 0.5,
+            depthTest:true,
+            side:THREE.DoubleSide
         });
 
         // 修改材质支持 instanceColor
@@ -120,10 +130,10 @@ export const ThreeGridClass = {
 
         // 创建边框线的几何体 (LineSegments)
         const edges = new THREE.EdgesGeometry(geometry);
-        const edgeMaterial = new THREE.LineBasicMaterial({
+        this.edgeMaterial = new THREE.LineBasicMaterial({
             color: 0xffffff,
             opacity: 0.8,
-            linewidth:8,
+            linewidth:1,
             transparent: true
         });
 
@@ -171,11 +181,11 @@ export const ThreeGridClass = {
         // 创建合并后的线段几何体
         const mergedLineGeometry = new THREE.BufferGeometry();
         mergedLineGeometry.setAttribute('position', new THREE.Float32BufferAttribute(mergedLines, 3));
-        const mergedLineMesh = new THREE.LineSegments(mergedLineGeometry, edgeMaterial);
+        this.mergedLineMesh = new THREE.LineSegments(mergedLineGeometry, this.edgeMaterial);
 
         // 将网格和边框分别添加到场景中
         this.scene.add(this.mesh);
-        this.scene.add(mergedLineMesh);  // 添加边框线
+        this.scene.add(this.mergedLineMesh);  // 添加边框线
 
         // 网格的光照
         const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
@@ -188,23 +198,67 @@ export const ThreeGridClass = {
 
 
 
+
     updateColors() {
-        const instanceColors = this.mesh.geometry.attributes.instanceColor.array;
-        const color = new THREE.Color();
+        // 更新当前显示的层
+        this.currentLayer = (this.currentLayer + 1) % Math.floor(this.height / this.layerHeight); // 递增层数并循环
 
-        // for (let i = 0; i < this.mesh.count; i++) {
-        //     color.setHSL(Math.random(), 0.8, 0.5);
-        //     instanceColors[i * 3] = color.r;
-        //     instanceColors[i * 3 + 1] = color.g;
-        //     instanceColors[i * 3 + 2] = color.b;
-        // }
+        const dummy = new THREE.Object3D();
+        const xCount = Math.floor((this.extent.maxX - this.extent.minX) / this.size);
+        const yCount = Math.floor((this.extent.maxY - this.extent.minY) / this.size);
+        const zCount = Math.floor(this.height / this.layerHeight);
 
-        // 标记颜色属性需要更新
-        this.mesh.geometry.attributes.instanceColor.needsUpdate = true;
+        let index = 0;
+        const linePositions = []; // 用于存储当前层级的边框线段
 
-        // 触发重新渲染
-        this.requestRender();
+        for (let i = 0; i < xCount; i++) {
+            for (let j = 0; j < yCount; j++) {
+                for (let k = 0; k < zCount; k++) {
+                    const worldX = this.extent.minX + i * this.size + this.size / 2;
+                    const worldY = this.extent.minY + j * this.size + this.size / 2;
+                    const worldZ = k * this.layerHeight + this.layerHeight / 2;
+
+                    if (k === this.currentLayer) {
+                        // 更新当前层级实例的位置
+                        let renderPos = [];
+                        this.webgl.toRenderCoordinates(this.view, [worldX, worldY, worldZ], 0, this.view.spatialReference, renderPos, 0, 1);
+                        dummy.position.set(renderPos[0], renderPos[1], renderPos[2]);
+                        dummy.updateMatrix();
+                        this.mesh.setMatrixAt(index, dummy.matrix);
+
+                        // 将当前实例的边框线添加到 `linePositions`
+                        const edges = new THREE.EdgesGeometry(new THREE.BoxGeometry(this.layerHeight, this.size, this.size));
+                        const edgesArr = edges.attributes.position.array;
+
+                        for (let e = 0; e < edgesArr.length; e += 3) {
+                            linePositions.push(
+                                edgesArr[e] + dummy.position.x,
+                                edgesArr[e + 1] + dummy.position.y,
+                                edgesArr[e + 2] + dummy.position.z
+                            );
+                        }
+                    } else {
+                        // 移出渲染范围
+                        dummy.position.set(1e6, 1e6, 1e6); // 使用一个很大的数值将物体移出视野
+                        dummy.updateMatrix();
+                        this.mesh.setMatrixAt(index, dummy.matrix);
+                    }
+                    index++;
+                }
+            }
+        }
+
+        // 更新实例矩阵
+        this.mesh.instanceMatrix.needsUpdate = true;
+
+        // 更新边框线
+        const lineGeometry = new THREE.BufferGeometry();
+        lineGeometry.setAttribute('position', new THREE.Float32BufferAttribute(linePositions, 3));
+        this.mergedLineMesh.geometry.dispose(); // 释放旧几何体资源
+        this.mergedLineMesh.geometry = lineGeometry; // 替换为新几何体
     },
+
+
     render(context) {
         let cam = this.camera;
         //需要调整相机的视角