当前位置:   article > 正文

threejs加载人体模型,添加菲尼尔效果,并添加点击事件_vec3 finalcolor = vec3(0.455, 0.749, 0.890) 菲尼尔

vec3 finalcolor = vec3(0.455, 0.749, 0.890) 菲尼尔

threejs加载人体模型,添加菲尼尔效果,并添加点击事件

例图

在这里插入图片描述

注意事项

3D文件请放在public文件下,或者使用网络地址

代码

<template>
  <div>
    <div id="colorBar" style="display: none" ref="colorBar">
      {{ activeFloor }}
    </div>
    <div id="body" ref="body" style="position: relative"></div>
    <div id="showWindow" v-if="showWindow.name">
      <p>当前选中信息:</p>
      <p>类型:{{ showWindow.type }}</p>
      <p>名称:{{ showWindow.name }}</p>
      <p
        v-if="showWindow.type == 'Floor' && !showWindow.isShow"
        style="text-align: center"
      >
        <button @click="showFloor">查看</button>
      </p>
      <button v-if="showWindow.isShow" @click="showAll">返回</button>
    </div>
  </div>
</template>

<script>
// 方式 1: 导入整个 three.js核心库
import * as THREE from "three";
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";

import { OrbitControls } from "three/addons/controls/OrbitControls.js";

export default {
  name: "HelloWorld",
  props: {
    names: { type: Array, default: () => ["肾", "足部", "大脑"] },
    sex: { type: Number, default: () => 1 }, //0 女  1 男
  },
  watch: {
    sex() {
      alert(1);
      this.loaderModel();
    },
  },
  data() {
    return {
      scene: null,
      camera: null,
      light: null,
      model1: null, //模型
      clock: null, //时钟
      loader: null, //加载器
      controls: null, //控制器
      // 渲染器
      renderer: null,
      // 动画数量
      animateLength: 0,
      // 相机轨迹动画
      nowCameraAnimation: null,
      cameraMixer: null,
      cameraAnimations: [],
      // 模型动画
      model1Animations: null,
      mixer: null,
      nowanimation: [], //当前动画
      floorAnimation: [], //楼层动画
      uuid: null, //当前选中楼层
      activeFloor: null,
      activeType: "",
      lastTime: 0,
      currentFrameRate: 0,
      //是否正在旋转
      isXuanzhuan: false,

      otherColor: [], //保存楼层历史颜色
      raycaster: null, //点击位置
      Vector2: null, //(二维向量)的类

      // 右侧窗口信息
      showWindow: {
        type: "",
        name: "",
        isShow: false,
      },
    };
  },
  filters: {
    formatName(name) {
      return name.split("_")[2];
    },
  },
  mounted() {
    //  相机
    this.setCamera();

    // 场景
    this.scene = new THREE.Scene();
    this.setScene();

    // 灯光
    this.setLoght();

    // // 渲染器
    this.renderer = new THREE.WebGLRenderer({
      alpha: true, //遣染器活明
      antialias: true, //抗据货
      precision: "highp",
    });
    this.renderer.shadowMap.enabled = true;
    // 设置渲染器尺寸
    this.renderer.setSize(
      this.$refs.body.offsetWidth,
      this.$refs.body.offsetHeight
    );
    this.renderer.shadowMap.enabled = true;
    this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
    this.$refs.body.appendChild(this.renderer.domElement);

    // 添加点击事件
    this.addJH();

    // 设置控制器
    this.setControls();

    this.loader = new GLTFLoader();
    // 加载模型
    this.loaderModel(1);

    // this.setLine(1, 0, 0, "#f00");
    // this.setLine(0, 1, 0, "green");
    // this.setLine(0, 0, 1, "#000");

    this.clock = new THREE.Clock();
    this.raycaster = new THREE.Raycaster();
    this.Vector2 = new THREE.Vector2();
    // 添加一个地板
    // this.addBackground();
    this.animate();
  },
  methods: {
    loaderModel(scale = 1) {
      let url = "";
      if (this.sex === 0) {
        url = "/Female_1.2.gltf";
      } else {
        url = "/Male_1.2.gltf";
      }
      this.loader.load(
        url,
        (gltf) => {
          console.log(gltf);
          gltf.scene.traverse((object) => {
            console.log(object.name);
            if (
              object.name != "血管" &&
              object.name != "血管2" &&
              object.name != "静脉" &&
              object.name != "动脉" &&
              object.name
            ) {
              console.log(object.name, this.names.includes(object.name));
              if (this.names.includes(object.name)) {
                var material = new THREE.MeshBasicMaterial({
                  color: "#f00",
                  transparent: true,
                  opacity: 0.5,
                });
                object.material = material;
                object.isIll = true;
              } else {
                // 创建一个透明的材质
                var customMaterial = new THREE.ShaderMaterial({
                  uniforms: {
                    // 在这里定义uniform变量,用于控制透明度、边缘和反光效果
                    edgeColor: { value: new THREE.Vector3(1.0, 1.0, 1.0) }, // 边缘颜色
                    edgeThickness: { value: 0.05 }, // 边缘厚度
                    reflectionStrength: { value: 0.9 }, // 反光强度
                  },
                  vertexShader: `
                      varying vec3 vNormal;

                      void main() {
                          vNormal = normal;
                          gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
                      }
                  `,
                  fragmentShader: `
                      varying vec3 vNormal;
                      uniform vec3 edgeColor;
                      uniform float edgeThickness;
                      uniform float reflectionStrength;

                      void main() {
                          // 计算透明度
                          float alpha = 0.5; // 透明度的基础值

                          // 计算边缘效果
                          float edge = fwidth(length(vNormal));
                          alpha *= smoothstep(0.0, edgeThickness, edge);

                          // 计算反光效果
                          vec3 reflection = reflect(normalize(-vNormal), vec3(0.455, 0.749, 0.890));
                          float reflectionIntensity = max(dot(reflection, normalize(-vNormal)), 0.0);
                          vec3 reflectionColor = reflectionStrength * reflectionIntensity * edgeColor;

                          // 最终颜色设置为"#74bfe3"
                          vec3 finalColor = vec3(0.455, 0.749, 0.890); // "#74bfe3"的RGB值
                          finalColor += reflectionColor; // 添加反光效果

                          // 设置透明度
                          gl_FragColor = vec4(finalColor, alpha);
                      }
                  `,
                  transparent: true,
                });
                object.material = customMaterial;
                object.isIll = false;
              }
            }
            if (object.name == "骨架") {
              object.visible = false;
            }
          });
          this.model1 = gltf.scene;

          this.scene.add(this.model1);
          this.model1.scale.set(scale, scale, scale);
          this.mixer = new THREE.AnimationMixer(this.model1);

          this.model1.position.set(0, 0, 0);
          this.model1Animations = gltf.animations;
          // 获取相机的动画剪辑数组
          this.cameraAnimations = gltf.animations;
          // 获取到楼层的动画
          this.floorAnimation = gltf.animations
            .filter((item) => item)
            .sort((a, b) => a.name.split("_")[1] - b.name.split("_")[1])
            .reverse();
        },
        undefined,
        function (e) {
          console.error(e);
        }
      );
    },
    setCamera() {
      // PerspectiveCamera 相机
      // fov — 摄像机视锥体垂直视野角度
      // aspect — 摄像机视锥体长宽比
      // near — 摄像机视锥体近端面
      // far — 摄像机视锥体远端面
      // Vector3 三维向量(标记为x、y和z)
      // this.camera.lookAt(new THREE.Vector3(0, 1, 0));
      // this.cameraMixer = new THREE.AnimationMixer(this.camera);
      this.camera = new THREE.PerspectiveCamera(
        75,
        this.$refs.body.offsetWidth / this.$refs.body.offsetHeight,
        0.1,
        1000
      );
      this.camera.position.set(0, 0, 2);
    },
    setScene() {
      this.scene.background = new THREE.Color("#000");
      // 一个fog实例定义了影响场景中的每个物体的雾的类型。默认值为null。
      // this.scene.fog = new THREE.Fog("#000", 20, 1000);
      // this.scene.position.x -= 2;
      this.scene.position.y -= 1;
    },
    setControls(type = false) {
      if (type) {
        this.controls.dispose();
        return;
      }
      this.controls = new OrbitControls(this.camera, this.renderer.domElement);
    },
    setLoght() {
      // 从上方照射的白色平行光,强度为 0.5。
      // 创建平行光源
      this.light = new THREE.DirectionalLight(0xffffff, 2);
      this.light.position.set(-10, 10, 20).normalize();
      // this.light.castShadow = true; // default false
      this.scene.add(this.light);

      const light = new THREE.AmbientLight(0x404040, 0.5); // 柔和的白光
      this.scene.add(light);
    },
    animate() {
      // currentTime
      // // 更新动画时间
      // var delta = this.clock.getDelta();

      // const deltaTime = currentTime - this.lastTime; // 计算距离上一帧的时间间隔,转换为秒
      // this.lastTime = currentTime; // 更新上一帧的时间戳
      // const currentFrameRate = 1 / deltaTime;

      // if (this.mixer) {
      //   this.nowanimation.forEach((item) => {
      //     // 检查动画是否已经结束
      //     let sumTime = item.getClip().duration;
      //     if (!item.paused && item.time >= sumTime - currentFrameRate) {
      //       // 暂停动画
      //       item.paused = true;
      //       item.time = sumTime;
      //       this.animateLength--;
      //     }
      //   });
      //   this.mixer.update(delta);
      // }
      // if (this.cameraMixer && this.nowCameraAnimation) {
      //   this.cameraMixer.update(delta);
      // }
      this.controls.update();
      // this.CSS2DRenderer.render(this.scene, this.camera);
      this.renderer.render(this.scene, this.camera);
      requestAnimationFrame(this.animate);
    },
    setLine(x, y, z, color) {
      const dir = new THREE.Vector3(x, y, z);
      //normalize the direction vector (convert to vector of length 1)
      dir.normalize();
      const origin = new THREE.Vector3(0, 0, 0);
      const length = 10;
      const arrowHelper = new THREE.ArrowHelper(dir, origin, length, color);
      this.scene.add(arrowHelper);
    },
    addJH() {
      this.renderer.domElement.addEventListener(
        "mousedown",
        this.onMouseDown,
        false
      );
      // this.renderer.domElement.addEventListener(
      //   "mousemove",
      //   this.onMouseMove,
      //   false
      // );
      // this.renderer.domElement.addEventListener(
      //   "mouseup",
      //   this.onMouseUp,
      //   false
      // );
    },
    onMouseDown(event) {
      // 在这里处理鼠标点击事件的逻辑
      this.Vector2.set(
        (event.clientX / this.$refs.body.clientWidth) * 2 - 1,
        -(event.clientY / this.$refs.body.clientHeight) * 2 + 1
      );
      // 射线投射
      this.raycaster.setFromCamera(this.Vector2, this.camera);
      // 获取与射线相交的对象列表
      const intersects = this.raycaster.intersectObjects(this.scene.children);
      // 遍历相交对象列表
      for (let i = 0; i < intersects.length; i++) {
        const intersect = intersects[i];
        if (intersect.object.isIll) {
          const name = intersect.object.name;
          this.$emit("organOnclick", name);
        }
      }
    },
    onMouseMove() {
      // 在这里处理鼠标点击事件的逻辑
      // console.log("点击了 Three.js 元素", event);
    },
    onMouseUp() {
      // 在这里处理鼠标点击事件的逻辑
    },
    // console.log("点击了 Three.js 元素", event);
    changeColor(name, type = "name") {
      this.model1.traverse((child) => {
        if (type == "name") {
          for (let index = 0; index < this.otherColor.length; index++) {
            const element = this.otherColor[index];
            if (element.name == child.name) {
              child.material = element.material;
              this.otherColor.splice(index, 1);
              index--;
            }
          }
          if (name && child.name == name) {
            this.otherColor.push({
              name: name,
              material: child.material.clone(),
            });
            child.material = new THREE.MeshBasicMaterial({
              color: "#f00",
              transparent: true,
              opacity: 0.5,
            });
          }
        }
      });
      this.renderer.render(this.scene, this.camera);
    },
    getRandomColor() {
      var letters = "0123456789ABCDEF";
      var color = "#";
      for (var i = 0; i < 6; i++) {
        color += letters[Math.floor(Math.random() * 16)];
      }
      console.log(color);
      return color;
    },

    addBackground() {
      // // 创建地面的几何体;
      var dgeometry = new THREE.PlaneGeometry(100, 100); // 根据需要指定地面的宽度和长度
      dgeometry.rotateX(-Math.PI / 2);
      // 创建地面的材质
      var dmaterial = new THREE.MeshBasicMaterial({ color: "#333" }); // 根据需要指定地面的颜色或纹理
      // 创建地面的网格对象
      var ground = new THREE.Mesh(dgeometry, dmaterial);
      ground.receiveShadow = true;
      // 将地面网格对象添加到场景中
      this.scene.add(ground);
    },
  },
};
</script>
<style scoped>
#body {
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  overflow: hidden;
}
#btns {
  position: fixed;
  right: 5px;
  top: 20px;
  width: 100px;
  display: flex;
  justify-content: center;
  flex-direction: column;
}
#colorBar {
  width: 50px;
  height: 10px;
  font-size: 16px;
  color: #f00;
}
#showWindow {
  position: absolute;
  z-index: 2;
  right: 5px;
  top: 5px;
  background-color: #fff;
  border-radius: 4px;
  padding: 5px;
}
#showWindow p {
  text-align: left;
}
</style>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378
  • 379
  • 380
  • 381
  • 382
  • 383
  • 384
  • 385
  • 386
  • 387
  • 388
  • 389
  • 390
  • 391
  • 392
  • 393
  • 394
  • 395
  • 396
  • 397
  • 398
  • 399
  • 400
  • 401
  • 402
  • 403
  • 404
  • 405
  • 406
  • 407
  • 408
  • 409
  • 410
  • 411
  • 412
  • 413
  • 414
  • 415
  • 416
  • 417
  • 418
  • 419
  • 420
  • 421
  • 422
  • 423
  • 424
  • 425
  • 426
  • 427
  • 428
  • 429
  • 430
  • 431
  • 432
  • 433
  • 434
  • 435
  • 436
  • 437
  • 438
  • 439
  • 440
  • 441
  • 442
  • 443
  • 444
  • 445
  • 446
  • 447
  • 448
  • 449
  • 450
  • 451
  • 452
  • 453
  • 454
声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号