threejs导入gltf文件加载模型,点击模型操作

最近公司要做一个桥梁的模型,前端加载模型并操作模型,中间遇到了一些问题,在这里写一个demo记录一下:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>threejs</title>
    <style>
      body,html{
        margin: 0px;
        width: 100%;
        height: 100%;
      }
      #model{
          width: calc(100% - 200px);
          height: 500px;
      }
    </style>
  </head>
  <body>
    <div style="width: 100%;height: 100%;display: flex;">
      <div style="width: 200px;height: 100%;background-color: pink;"></div>
       <div id="model"></div>
    </div>
   
    <script type="importmap">
      {
        "imports": {
          "three": "https://unpkg.com/three@v0.162.0/build/three.module.js",
          "three/addons/": "https://unpkg.com/three@v0.162.0/examples/jsm/"
        }
      }
    </script>
    <script src="./js/threeModel.js" type="module"></script>
  </body>
</html>

注意:当加载模型的标签是100%宽时,three.js中的raycaster用法是canvas是整个页面窗口的,所以它的代码是:

mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;

但是由于我的模型展示标签没有占满整个页面,所以用上述方法获取模型老是不对,但实际上我的项目中渲染模型的区域只有页面中的一块区域,所以这么些写获取到的部位总是不准确,终于在一个博主那找到了解决方案,在此记录一下:

let getClientRect = threeModel.getBoundingClientRect();
mouse.x = ((event.clientX - getClientRect .left) /  width) * 2 - 1;
mouse.y = -((event.clientY - getClientRect .top) /  height) * 2 + 1;

点击加轮廓颜色时发现模型场景颜色变了,选要加几行代码:

import { GammaCorrectionShader } from 'three/addons/shaders/GammaCorrectionShader.js';
import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js'


// 要加在EffectComposer之后
const gammaCorrectionShader = new ShaderPass( GammaCorrectionShader );
composer.addPass( gammaCorrectionShader );

  完整的threeModel.js文件

import * as THREE from "three";
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
import { EffectComposer } from "three/addons/postprocessing/EffectComposer.js";
import { RenderPass } from "three/addons/postprocessing/RenderPass.js";
import { OutlinePass } from "three/addons/postprocessing/OutlinePass.js";
import { GammaCorrectionShader } from 'three/addons/shaders/GammaCorrectionShader.js';
import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js'

const scene = new THREE.Scene();

const threeModel = document.getElementById("model");
const width = threeModel.offsetWidth;
const height = threeModel.offsetHeight;
// 创建相机
const camera = new THREE.PerspectiveCamera(30,width / height,1,3000);
camera.position.set(-69, 137, 153);
camera.lookAt(0,0,0); // 坐标原点

// 创建渲染器
const renderer = new THREE.WebGLRenderer();
renderer.toneMappingExposure = 5; // 增加曝光度
renderer.setSize(width, height);
this.renderer.setClearColor(0xffffff, 1);
threeModel.appendChild(renderer.domElement);

// 添加灯光
 const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8); // 平行光
 directionalLight.position.set(480,200,300);
 scene.add(directionalLight);
 const ambient = new THREE.AmbientLight(0xffffff, 1); // 环境光
 scene.add(ambient);


loadModel();
function loadModel() {
    const loader = new GLTFLoader();
    loader.load(
        "../model/梁式桥.gltf",
        (gltf) => {
            gltf.scene.rotation.y = -Math.PI / 8; // y轴旋转
            scene.add(gltf.scene);
            animate();
        },
        (xhr) => {
            // 计算模型加载进度条
            console.log((xhr.loaded / xhr.total) * 100 + "% loaded");
        },
        (error) => {
            console.error("An error happened while loading the model", error);
        }
    );
   
}

const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true; // 添加惯性
// 设置垂直旋转范围,从而只允许左右旋转
controls.minPolarAngle = Math.PI / 4; // 最小垂直角度为0度
controls.maxPolarAngle = Math.PI / 2; // 最大垂直角度为180度

// 禁用缩放和平移功能(可选)
controls.enableZoom = true;
controls.enablePan = false;


var highlightedObject = null;

// 监听鼠标点击事件
renderer.domElement.addEventListener('click', onClick, false);
const composer = new EffectComposer(renderer);
const renderPass = new RenderPass(scene,camera);
composer.addPass(renderPass);

// 使用OutlinePass场景会变暗
const gammaCorrectionShader = new ShaderPass( GammaCorrectionShader );
composer.addPass( gammaCorrectionShader );

const v2 = new THREE.Vector2(width,height);

const outlinePass = new OutlinePass(v2,scene,camera);
function onClick(event) {
    let getBoundingClientRect = threeModel.getBoundingClientRect()
    let mouse = new THREE.Vector2();
    // 计算鼠标点击位置的归一化设备坐标
    mouse.x = ((event.clientX - getBoundingClientRect .left) /  width) * 2 - 1;
    mouse.y = -((event.clientY - getBoundingClientRect .top) /  height) * 2 + 1;
    let raycaster = new THREE.Raycaster();
    // 通过射线投射来获取鼠标点击位置的对象
    raycaster.setFromCamera(mouse, camera);
    let intersects = raycaster.intersectObjects(scene.children, true);
    if (intersects.length > 0) {
        outlinePass.selectedObjects = [intersects[0].object];
        outlinePass.visibleEdgeColor.set(0xffff00); 
        outlinePass.edgeThickness = 4; 
        outlinePass.edgeStrength = 6; 
        composer.addPass(outlinePass);
    }
}

function animate() {
    composer.render();
    requestAnimationFrame(animate);
}
  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值