|
@@ -34,56 +34,88 @@ class renderModel {
|
|
|
//模型平面
|
|
|
this.planeGeometry;
|
|
|
|
|
|
- this.outlineObjs = []
|
|
|
+ this.outlineObjs = [];
|
|
|
+ this.sharedComposer = null;
|
|
|
+ this.sharedOutlinePass = null;
|
|
|
+ this.sharedBloomPass = null;
|
|
|
+ this.isComposerInitialized = false;
|
|
|
+ this.raycaster = new THREE.Raycaster();
|
|
|
+ this.mouse = new THREE.Vector2();
|
|
|
}
|
|
|
|
|
|
- outlineObj(selectedObjects) {
|
|
|
- // 创建一个EffectComposer(效果组合器)对象,然后在该对象上添加后期处理通道。
|
|
|
- // 用于模型边缘高亮
|
|
|
- let composer = new EffectComposer(this.renderer);
|
|
|
- composer.renderTarget1.texture.outputColorSpace = THREE.sRGBEncoding;
|
|
|
- composer.renderTarget2.texture.outputColorSpace = THREE.sRGBEncoding;
|
|
|
- composer.renderTarget1.texture.encoding = THREE.sRGBEncoding;
|
|
|
- composer.renderTarget2.texture.encoding = THREE.sRGBEncoding;
|
|
|
-
|
|
|
- // 新建一个场景通道 为了覆盖到原来的场景上
|
|
|
- composer.addPass(new RenderPass(this.scene, this.camera));
|
|
|
- // 物体边缘发光通道
|
|
|
- let outlinePass = new OutlinePass(
|
|
|
+ // 初始化共享后处理系统
|
|
|
+ initSharedPostProcessing() {
|
|
|
+ if (this.isComposerInitialized) return;
|
|
|
+
|
|
|
+ // 创建共享的EffectComposer
|
|
|
+ this.sharedComposer = new EffectComposer(this.renderer);
|
|
|
+ this.sharedComposer.renderTarget1.texture.outputColorSpace = THREE.sRGBEncoding;
|
|
|
+ this.sharedComposer.renderTarget2.texture.outputColorSpace = THREE.sRGBEncoding;
|
|
|
+ this.sharedComposer.renderTarget1.texture.encoding = THREE.sRGBEncoding;
|
|
|
+ this.sharedComposer.renderTarget2.texture.encoding = THREE.sRGBEncoding;
|
|
|
+
|
|
|
+ // 添加基础渲染通道
|
|
|
+ const renderPass = new RenderPass(this.scene, this.camera);
|
|
|
+ this.sharedComposer.addPass(renderPass);
|
|
|
+
|
|
|
+ // 创建共享的OutlinePass
|
|
|
+ this.sharedOutlinePass = new OutlinePass(
|
|
|
new THREE.Vector2(window.innerWidth, window.innerHeight),
|
|
|
this.scene,
|
|
|
- this.camera,
|
|
|
- selectedObjects
|
|
|
+ this.camera
|
|
|
);
|
|
|
- outlinePass.selectedObjects = selectedObjects;
|
|
|
- outlinePass.edgeStrength = 10.0; // 边框的亮度
|
|
|
- outlinePass.edgeGlow = 0.5; // 光晕[0,1]
|
|
|
- outlinePass.usePatternTexture = false; // 是否使用父级的材质
|
|
|
- outlinePass.edgeThickness = 1.0; // 边框宽度
|
|
|
- outlinePass.downSampleRatio = 1; // 边框弯曲度
|
|
|
- outlinePass.pulsePeriod = 5; // 呼吸闪烁的速度
|
|
|
- outlinePass.visibleEdgeColor.set(parseInt(0x00ff00)); // 呼吸显示的颜色
|
|
|
- outlinePass.hiddenEdgeColor = new THREE.Color(0, 0, 0); // 呼吸消失的颜色
|
|
|
- outlinePass.clear = true;
|
|
|
- composer.addPass(outlinePass);
|
|
|
- // 自定义的着色器通道 作为参数
|
|
|
- // effectFXAA = new ShaderPass(FXAAShader);
|
|
|
- // effectFXAA.uniforms.resolution.value.set(
|
|
|
- // 1 / window.innerWidth,
|
|
|
- // 1 / window.innerHeight
|
|
|
- // );
|
|
|
- // effectFXAA.renderToScreen = true;
|
|
|
- // composer.addPass(effectFXAA);
|
|
|
-
|
|
|
- // // 发光效果
|
|
|
- let unrealBloomPass = new UnrealBloomPass();
|
|
|
- unrealBloomPass.strength = 0.1;
|
|
|
- unrealBloomPass.radius = 0;
|
|
|
- unrealBloomPass.threshold = 1;
|
|
|
- composer.addPass(unrealBloomPass);
|
|
|
- this.outlineObjs.push(composer)
|
|
|
- console.log(">>>>>>>>>>>>>>>>>>>>>")
|
|
|
+ // 设置轮廓效果参数
|
|
|
+ this.sharedOutlinePass.edgeStrength = 5.0; // 边框的亮度
|
|
|
+ this.sharedOutlinePass.edgeGlow = 0.3; // 光晕[0,1]
|
|
|
+ this.sharedOutlinePass.edgeThickness = 1.0; // 边框宽度
|
|
|
+ this.sharedOutlinePass.pulsePeriod = 3; // 呼吸闪烁的速度
|
|
|
+ this.sharedOutlinePass.visibleEdgeColor.set(0x00ff00); // 呼吸显示的颜色
|
|
|
+ this.sharedOutlinePass.hiddenEdgeColor.set(0x000000); // 呼吸消失的颜色
|
|
|
+ this.sharedOutlinePass.clear = true;
|
|
|
+ this.sharedComposer.addPass(this.sharedOutlinePass);
|
|
|
+
|
|
|
+ // 创建共享的UnrealBloomPass
|
|
|
+ this.sharedBloomPass = new UnrealBloomPass();
|
|
|
+ this.sharedBloomPass.strength = 0.1;
|
|
|
+ this.sharedBloomPass.radius = 0;
|
|
|
+ this.sharedBloomPass.threshold = 1;
|
|
|
+ this.sharedComposer.addPass(this.sharedBloomPass);
|
|
|
+
|
|
|
+ this.isComposerInitialized = true;
|
|
|
+
|
|
|
+ // 监听窗口大小变化,更新后处理分辨率
|
|
|
+ window.addEventListener('resize', () => {
|
|
|
+ if (this.sharedOutlinePass) {
|
|
|
+ this.sharedOutlinePass.resolution.set(window.innerWidth, window.innerHeight);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ // 优化后的模型高亮方法
|
|
|
+ outlineObj(selectedObjects) {
|
|
|
+ // 初始化共享后处理系统
|
|
|
+ this.initSharedPostProcessing();
|
|
|
|
|
|
+ // 更新选中对象
|
|
|
+ if (this.sharedOutlinePass) {
|
|
|
+ this.sharedOutlinePass.selectedObjects = selectedObjects;
|
|
|
+
|
|
|
+ // 如果之前有高亮对象,先清除
|
|
|
+ if (this.outlineObjs.length > 0) {
|
|
|
+ this.outlineObjs = [];
|
|
|
+ }
|
|
|
+
|
|
|
+ // 添加当前共享的composer到数组
|
|
|
+ this.outlineObjs.push(this.sharedComposer);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 清理高亮效果
|
|
|
+ clearHighlight() {
|
|
|
+ if (this.sharedOutlinePass) {
|
|
|
+ this.sharedOutlinePass.selectedObjects = [];
|
|
|
+ this.outlineObjs = [];
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
// 初始化加载模型方法
|
|
@@ -100,13 +132,14 @@ class renderModel {
|
|
|
this.initControls();
|
|
|
this.setFBXModel();
|
|
|
//监听场景大小改变,跳转渲染尺寸
|
|
|
- window.addEventListener('resize', this.onWindowResizes);
|
|
|
+ window.addEventListener('resize', this.onWindowResizes.bind(this));
|
|
|
//场景渲染
|
|
|
this.sceneAnimation();
|
|
|
+ // 添加鼠标点击事件
|
|
|
+ window.addEventListener('click', this.onMouseClick.bind(this));
|
|
|
}
|
|
|
|
|
|
initGltfModel() {
|
|
|
-
|
|
|
//初始化场景
|
|
|
this.initScene();
|
|
|
//初始化相机
|
|
@@ -119,9 +152,32 @@ class renderModel {
|
|
|
this.initControls();
|
|
|
this.setGlbModel();
|
|
|
//监听场景大小改变,跳转渲染尺寸
|
|
|
- window.addEventListener('resize', this.onWindowResizes);
|
|
|
+ window.addEventListener('resize', this.onWindowResizes.bind(this));
|
|
|
//场景渲染
|
|
|
this.sceneAnimation();
|
|
|
+ // 添加鼠标点击事件
|
|
|
+ window.addEventListener('click', this.onMouseClick.bind(this));
|
|
|
+ }
|
|
|
+
|
|
|
+ onMouseClick(event) {
|
|
|
+ // 计算鼠标在标准化设备坐标中的位置 (-1 to +1)
|
|
|
+ this.mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
|
|
|
+ this.mouse.y = - (event.clientY / window.innerHeight) * 2 + 1;
|
|
|
+
|
|
|
+ // 更新射线
|
|
|
+ this.raycaster.setFromCamera(this.mouse, this.camera);
|
|
|
+
|
|
|
+ // 计算射线与场景中物体的交点
|
|
|
+ const intersects = this.raycaster.intersectObjects(this.scene.children, true);
|
|
|
+
|
|
|
+ if (intersects.length > 0) {
|
|
|
+ const point = intersects[0].point;
|
|
|
+ const object = intersects[0].object;
|
|
|
+ console.log(`Clicked on object: ${object.name} at (${point.x}, ${point.y}, ${point.z})`);
|
|
|
+
|
|
|
+ // 示例:点击时高亮对象
|
|
|
+ // this.outlineObj([object]);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
//创建场景
|
|
@@ -220,15 +276,11 @@ class renderModel {
|
|
|
this.controls.update();
|
|
|
this.css3DRenderer.render(this.scene, this.camera);
|
|
|
TWEEN.update();
|
|
|
- // this.outlineObjs.forEach(item => {
|
|
|
- // item.render(this.scene, this.camera)
|
|
|
- // })
|
|
|
- // // 检查模型位置是否发生变化
|
|
|
- // if (this.model) {
|
|
|
- // console.log('Model Position:', this.model.position);
|
|
|
- // console.log('Camera Position:', this.camera.position);
|
|
|
- // console.log('Controls Target:', this.controls.target);
|
|
|
- // }
|
|
|
+
|
|
|
+ // 使用共享的composer进行后处理渲染
|
|
|
+ if (this.isComposerInitialized && this.sharedComposer) {
|
|
|
+ this.sharedComposer.render();
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
// 使用动画器不断更新场景
|
|
@@ -314,12 +366,17 @@ class renderModel {
|
|
|
fbxLoader.load('/models/model-road-pv.glb', object => {
|
|
|
this.calcMeshCenter(object.scene);
|
|
|
this.model = object.scene;
|
|
|
+ const selectedObjects = [];
|
|
|
object.scene.traverse(function (child) {
|
|
|
if (child.isMesh) {
|
|
|
child.material.emissive = child.material.color;
|
|
|
child.material.emissiveMap = child.material.map;
|
|
|
}
|
|
|
+ if (["solar_cell097001", "solar_cell097002", "solar_cell097003", "solar_cell097004"].includes(child.name)) {
|
|
|
+ selectedObjects.push(child);
|
|
|
+ }
|
|
|
});
|
|
|
+
|
|
|
// 设置相机位置
|
|
|
this.camera.position.set(-20, -652, 500);
|
|
|
this.controls.target.set(-20, -20, 0);
|
|
@@ -328,39 +385,10 @@ class renderModel {
|
|
|
this.camera.lookAt(0, 0, 0);
|
|
|
// 将模型添加到场景中去
|
|
|
this.scene.add(this.model);
|
|
|
- if (object.scene.type === 'Group') {
|
|
|
- console.log('这是一个Group');
|
|
|
- // 遍历Group中的子对象
|
|
|
- object.scene.children.forEach(child => {
|
|
|
- if (child.type === 'Mesh') {
|
|
|
- console.log('这是一个Mesh', child.name); // 检查并记录Mesh的名称
|
|
|
- if (["solar_cell097.001", "solar_cell097.002", "solar_cell097.003", "solar_cell097.004","Line007"].includes(child.name)) {
|
|
|
- let selectedObjects = [child];
|
|
|
- // this.outlineObj(selectedObjects);
|
|
|
- }
|
|
|
- }
|
|
|
- });
|
|
|
- } else if (object.scene.type === 'Mesh') {
|
|
|
- console.log('这是一个单独的Mesh', object.scene.name); // 单独的Mesh对象
|
|
|
- } else {
|
|
|
- console.log('未知类型的对象', object.scene.type);
|
|
|
+ // 高亮收集的对象
|
|
|
+ if (selectedObjects.length > 0) {
|
|
|
+ this.outlineObj(selectedObjects);
|
|
|
}
|
|
|
- window.addEventListener('click', event => {
|
|
|
-
|
|
|
- // raycaster.setFromCamera(mouse, this.camera);
|
|
|
-
|
|
|
- // const intersects = raycaster.intersectObjects(this.scene.children);
|
|
|
-
|
|
|
- const intersects = this.raycaster.intersectObjects(this.scene.children);
|
|
|
-
|
|
|
- if (intersects.length > 0) {
|
|
|
- const point = intersects[0].point;
|
|
|
- console.log(`Clicked at: (${point.x}, ${point.y}, ${point.z})`);
|
|
|
- }
|
|
|
- });
|
|
|
- console.log('load')
|
|
|
- // this.initGUI();
|
|
|
-
|
|
|
});
|
|
|
}
|
|
|
|
|
@@ -383,37 +411,6 @@ class renderModel {
|
|
|
this.camera.lookAt(0, 0, 0);
|
|
|
// 将模型添加到场景中去
|
|
|
this.scene.add(this.model);
|
|
|
- if (object.type === 'Group') {
|
|
|
- console.log('这是一个Group');
|
|
|
- // 遍历Group中的子对象
|
|
|
- object.children.forEach(child => {
|
|
|
- if (child.type === 'Mesh') {
|
|
|
- console.log('这是一个Mesh', child.name); // 检查并记录Mesh的名称
|
|
|
- if (child.name === 'Line007') {
|
|
|
- let selectedObjects = [child];
|
|
|
- this.outlineObj(selectedObjects);
|
|
|
- }
|
|
|
- }
|
|
|
- });
|
|
|
- } else if (object.type === 'Mesh') {
|
|
|
- console.log('这是一个单独的Mesh', object.name); // 单独的Mesh对象
|
|
|
- } else {
|
|
|
- console.log('未知类型的对象', object.type);
|
|
|
- }
|
|
|
- window.addEventListener('click', event => {
|
|
|
-
|
|
|
- // raycaster.setFromCamera(mouse, this.camera);
|
|
|
-
|
|
|
- // const intersects = raycaster.intersectObjects(this.scene.children);
|
|
|
-
|
|
|
- const intersects = this.raycaster.intersectObjects(this.scene.children);
|
|
|
-
|
|
|
- if (intersects.length > 0) {
|
|
|
- const point = intersects[0].point;
|
|
|
- console.log(`Clicked at: (${point.x}, ${point.y}, ${point.z})`);
|
|
|
- }
|
|
|
- });
|
|
|
-
|
|
|
});
|
|
|
}
|
|
|
|
|
@@ -424,6 +421,7 @@ class renderModel {
|
|
|
this.camera.aspect = clientWidth / clientHeight; // 摄像机宽高比例
|
|
|
this.camera.updateProjectionMatrix(); //相机更新矩阵,将3d内容投射到2d面上转换
|
|
|
this.renderer.setSize(clientWidth, clientHeight);
|
|
|
+ this.css3DRenderer.setSize(clientWidth, clientHeight);
|
|
|
}
|
|
|
|
|
|
calcMeshCenter(group) {
|
|
@@ -443,7 +441,6 @@ class renderModel {
|
|
|
group.position.z = 17;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
addDialog(html, labelName, position) {
|
|
|
const {x, y, z} = position
|
|
|
const label3D = this.tag3D(labelName);
|