123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303 |
- import * as THREE from 'three';
- import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer.js';
- import { OutlinePass } from 'three/examples/jsm/postprocessing/OutlinePass.js';
- import { setModalCenter, setTag3D, gradientColors } from '/@/utils/threejs/util';
- import { CSS3DObject } from 'three/examples/jsm/renderers/CSS3DRenderer.js';
- import { green, yellow } from '@ant-design/colors';
- // import * as dat from 'dat.gui';
- // const gui = new dat.GUI();
- // gui.domElement.style = 'position:absolute;top:100px;left:10px;z-index:99999999999999';
- class GasAssessmen {
- model;
- modelName = 'workFace';
- group: THREE.Object3D = new THREE.Object3D();
- planeGroup: THREE.Group = new THREE.Group();
- bloomComposer: EffectComposer | null = null;
- finalComposer: EffectComposer | null = null;
- outlinePass: OutlinePass | null = null;
- positions: THREE.Vector3[][] = [];
- bloomLayer = new THREE.Layers();
- darkMaterial = new THREE.MeshBasicMaterial({ color: 'black', transparent: true, side: THREE.DoubleSide });
- materials = {};
- glob = {
- ENTIRE_SCENE: 0,
- BLOOM_SCENE: 10,
- N: 100,
- };
- locationTexture: THREE.Texture | null = null;
- warningLocationTexture: THREE.Texture | null = null;
- errorLocationTexture: THREE.Texture | null = null;
- playerStartClickTime1 = new Date().getTime();
- playerStartClickTime2 = new Date().getTime();
- planeNum = 0;
- constructor(model) {
- this.model = model;
- this.group.name = this.modelName;
- }
- addLight() {
- // const _this = this;
- const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
- directionalLight.position.set(-196, 150, 258);
- this.group.add(directionalLight);
- directionalLight.target = this.group;
- }
- render() {
- this.model.renderer?.render(this.model.scene as THREE.Scene, this.model.camera as THREE.PerspectiveCamera);
- }
- // 绘制抽采单元
- setPlanes1 = (n, colors = new Array(n).fill(new THREE.Color('rgb(100%, 0%, 0%)'))) => {
- const sizeList = [0.2, 0.3, 0.1, 0.4];
- // width = 7.713 height =3.717
- colors = gradientColors('#00FF2C', '#FF0000', n, 2);
- this.planeNum = n;
- const lenScale = 0.77 / n;
- const planeGeo = new THREE.PlaneGeometry();
- planeGeo.applyMatrix4(new THREE.Matrix4().makeTranslation(-1, 0, 0));
- for (let i = 0; i < n; i++) {
- const material = new THREE.MeshBasicMaterial({ color: colors[i], transparent: true, opacity: 0.6, depthTest: false, depthWrite: false });
- const plane = new THREE.Mesh(planeGeo, material);
- plane.name = 'unit' + i;
- plane.rotation.x = -Math.PI / 2;
- plane.scale.set(lenScale - 0.001, 0.375, 1.0);
- plane.position.set(0.282 - lenScale * (i - 0.5), 0.015, 0.142);
- this.planeGroup.add(plane);
- }
- this.group.add(this.planeGroup);
- };
- setPlanes = (n) => {
- // const sizeList = [0.2, 0.3, 0.1, 0.2, 0.2];
- const colors = {
- c1: new THREE.Color(0x00fe00), // >90
- c2: new THREE.Color(0xf9b866), // >75 <90 249,184,102
- c3: new THREE.Color(0xfefe00), // 50-75 254,254,0
- c4: new THREE.Color(0xfe6600), // 25-50 254,102,0
- c5: new THREE.Color(0xb00101), // <25 176,1,1
- };
- const sizeList = [
- {
- ratio: 0.2,
- color: colors.c1,
- },
- {
- ratio: 0.3,
- color: colors.c2,
- },
- {
- ratio: 0.1,
- color: colors.c4,
- },
- {
- ratio: 0.2,
- color: colors.c5,
- },
- {
- ratio: 0.2,
- color: colors.c3,
- },
- ];
- // width = 7.713 height =3.717
- const geometry = new THREE.PlaneGeometry(7.723, 3.72, 1, 1);
- // 初始化累积比例数组和颜色数组
- const accumulatedRatios = [];
- const colorsArray = new Float32Array(3 * sizeList.length);
- // 计算累积比例和颜色数组
- function updateShaderData(sizeList) {
- let accRatio = 0;
- for (let i = 0; i < sizeList.length; i++) {
- const item = sizeList[i];
- accRatio += item.ratio;
- accumulatedRatios.push(accRatio);
- colorsArray[i * 3] = item.color.r;
- colorsArray[i * 3 + 1] = item.color.g;
- colorsArray[i * 3 + 2] = item.color.b;
- }
- }
- updateShaderData(sizeList); // 初始调用
- // 定义着色器代码
- const vertexShader = `
- varying vec2 vUv;
- void main() {
- vUv = uv;
- gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
- }
- `;
- const fragmentShader = `
- varying vec2 vUv;
- uniform float ratios[${sizeList.length}];
- uniform vec3 colors[${sizeList.length}];
-
- void main() {
- for(int i = 0; i < ${sizeList.length}; i++) {
- if(vUv.x < ratios[i]) {
- gl_FragColor = vec4(colors[i], 1.0);
- return;
- }
- }
- gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
- }
- `;
- // const fragmentShader = `
- // varying vec2 vUv;
- // uniform float ratios[${sizeList.length + 1}]; // 加入了起始点 0
- // uniform vec3 colors[${sizeList.length}];
- // vec3 lerp(vec3 a, vec3 b, float t) {
- // return a + t * (b - a);
- // }
- // void main() {
- // int index = 0;
- // for(int i = 1; i <= ${sizeList.length}; i++) {
- // if(vUv.x >= ratios[i-1] && vUv.x < ratios[i]) {
- // index = i - 1;
- // break;
- // }
- // }
- // // 如果是最后一个颜色块,直接使用其颜色
- // if (index == ${sizeList.length - 1}) {
- // gl_FragColor = vec4(colors[index], 1.0);
- // } else {
- // // 计算该像素在当前颜色块内的相对位置
- // float t = (vUv.x - ratios[index]) / (ratios[index + 1] - ratios[index]);
- // // 在相邻颜色间进行线性插值
- // vec3 color = lerp(colors[index], colors[index + 1], t);
- // gl_FragColor = vec4(color, 1.0);
- // }
- // }
- // `;
- // 创建着色器材质
- const material = new THREE.ShaderMaterial({
- uniforms: {
- ratios: { value: accumulatedRatios },
- colors: { value: colorsArray },
- },
- vertexShader: vertexShader,
- fragmentShader: fragmentShader,
- depthTest: false,
- depthWrite: false,
- });
- // // 当 sizeList 数据变化时调用此函数
- // function updateSizeList(newSizeList) {
- // accumulatedRatios.length = 0; // 清空累积比例数组
- // updateShaderData(newSizeList);
- // material.uniforms.ratios.value = accumulatedRatios;
- // material.uniforms.colors.value = colorsArray;
- // material.needsUpdate = true;
- // }
- // 创建网格并添加到场景中
- const plane = new THREE.Mesh(geometry, material);
- plane.rotation.x = -Math.PI / 2;
- plane.position.set(-0.2, 0.15, -0.03);
- this.group.add(plane);
- };
- // 清除抽采单元绘制面
- clearPlanes = () => {
- for (let i = 0; i < this.planeNum; i++) {
- const plane = this.planeGroup.getObjectByName(`unit${i}`);
- const label = this.planeGroup.getObjectByName(`planeText${i}`);
- if (plane) this.planeGroup.remove(plane);
- if (label) this.planeGroup.remove(label);
- }
- };
- // 抽采单元内容显示
- setCss3D = () => {
- // width = 7.713 height =3.717
- const obj = this.group.getObjectByName(`unitText`);
- if (!obj) {
- const element = document.getElementById(`gasUnitBox`) as HTMLElement;
- if (element) {
- const gasUnitCSS3D = new CSS3DObject(element);
- gasUnitCSS3D.name = `unitText`;
- gasUnitCSS3D.scale.set(0.0009, 0.0009, 0.0009);
- gasUnitCSS3D.position.set(-0.1, 0.11, 0.05);
- gasUnitCSS3D.lookAt(-0.1, 0.5, 1);
- this.planeGroup.add(gasUnitCSS3D);
- }
- }
- for (let i = 0; i < this.planeNum; i++) {
- const lenScale = 0.77 / this.planeNum;
- const label = setTag3D(`抽采单元${i + 1}`, 'gas_unit_text');
- label.scale.set(0.0018, 0.0018, 1); //根据相机渲染范围控制HTML 3D标签尺寸
- label.position.set(0.282 - lenScale * (i + 0.5), 0.015, 0.142);
- label.name = 'planeText' + i;
- this.planeGroup.add(label);
- }
- };
- // 显示或隐藏抽采单元显示内容
- changeCss3D = (isHide) => {
- for (let i = 0; i < this.planeNum; i++) {
- const obj = this.group.getObjectByName(`unitText${i}`);
- if (obj) {
- obj.visible = isHide;
- }
- }
- };
- // 清除抽采单元显示内容
- clearCss3D = () => {
- const obj = this.group.getObjectByName(`unitText`);
- if (obj) this.group.remove(obj);
- const element = document.getElementById(`gasUnitBox`) as HTMLElement;
- if (element) {
- element.remove();
- }
- for (let i = 0; i < this.planeNum; i++) {
- const label = this.planeGroup.getObjectByName(`planeText${i}`);
- if (label) this.planeGroup.remove(label);
- }
- };
- /* 点击 */
- mousedownModel(rayCaster: THREE.Raycaster) {
- this.render();
- }
- mouseUpModel() {
- //
- }
- mountedThree() {
- return new Promise(async (resolve) => {
- this.model.renderer.sortObjects = true;
- this.model.orbitControls.update();
- this.model.setGLTFModel(['workFace1'], this.group).then(async () => {
- this.group.children.forEach((object: THREE.Object3D) => {
- if (object.name.startsWith('workFace')) {
- setModalCenter(object);
- }
- });
- this.group.name = this.modelName;
- this.addLight();
- resolve(null);
- });
- });
- }
- destroy() {
- this.model.clearGroup(this.group);
- this.model = null;
- this.group = null;
- this.bloomComposer?.dispose();
- this.finalComposer?.dispose();
- }
- }
- export default GasAssessmen;
|