angular8+threejs 入坑

作者: 候鸟_ywh | 来源:发表于2019-07-09 12:02 被阅读206次

    项目情况:仿优诺的机房3d可视化管理系统
    我的demo效果传送门

    项目技术angular8(架构)threejs(3d场景操作)tweenjs(交互)

    建模工具:blender(我用这个2.8)、3dsMax、maya

    我用的模型格式:GLTF

    用到的两个threejs库:three、three-full 、@tweenjs/tween.js(注意名字,tweenjs后面再说)

    其实当有模型提供的前提下做3d场景并不是一个很难的事情,有了模型之后就是如何用threejs调用api来操作而已,所以不用太恐惧,模型网上有好多。

    下面直接上代码吧

    1、新建ng项目(不多说了);

    2、安装库

    npm i three //  用来调用threejs的docs的api
    npm i three-full    //  用来调用threejs的examples的api
    npm i @tweenjs/tween.js //  用来交互
    

    注意:examples里面的api就等于别人封装好的组件然后官方拿来展示,所以这些api都不会存在three里面的,因此有人把他们集成到three-full这个库里面进行调用。

    以下是我的使用例子 base.ts

    import {
       Scene,
       AmbientLight,
       PointLight,
       WebGLRenderer,
       PerspectiveCamera,
       GridHelper,
       Color
    } from 'three';
    import {
       OrbitControls,
    } from 'three-full';
    import * as Stats from 'stats.js';
    import * as TWEEN from '@tweenjs/tween.js';
    import {
     FXAAShader, UnrealBloomPass, ShaderPass, FilmPass, OutlinePass, GeometryUtils, CopyShader, ColorifyShader, SepiaShader,
     OrbitControls, GLTFLoader, EffectComposer, RenderPass, SMAAShader, SMAAPass, ClearMaskPass, MaskPass,
    } from 'three-full';
    
    // three-full和tween以下代码没调用,先展示下调用方式
    
    
    //  渲染器
    export const RENDERER = new WebGLRenderer(); //  渲染器(去据此){ antialias: true }
    export function initRenderer(doc) {
       RENDERER.setSize(
           doc.clientWidth,
           doc.clientHeight
       );
       RENDERER.shadowMap.enabled = true; // 辅助线
       doc.appendChild(RENDERER.domElement);
    
    
    }
    
    
    // 场景
    export const SCENE = new Scene();
    export function initScene() {
       SCENE.background = new Color(0xcccccc);
    }
    
    //  灯光
    export function initLight() {
       const ambientLight = new AmbientLight(0xffffff, 0.2);    // 全局光
       ambientLight.position.set(10, 20, 55);   // 灯光
       SCENE.add(ambientLight);
    
       // 点光源
       const pointLight = new PointLight(0xffffff);
       pointLight.distance = 0;
       CAMERA.add(pointLight);
       SCENE.add(CAMERA);
    }
    
    //  相机
    export let CAMERA;
    export let CONTROLS;
    export function initCamera(doc) {
       const d = {
           fov: 30, // 拍摄距离  视野角值越大,场景中的物体越小
           near: 1, //  最小范围
           far: 1000, //  最大范围
       };
       CAMERA = new PerspectiveCamera(
           d.fov,
           doc.clientWidth / doc.clientHeight,
           d.near,
           d.far)
           ;
       const p = {
           x: -20,
           y: 10,
           z: -10,
       };
       CAMERA.position.set(p.x, p.y, p.z);
       CAMERA.lookAt(0, 0, 0);
       CONTROLS = new OrbitControls(CAMERA, RENDERER.domElement);  // 控制镜头
    }
    
    
    //  网格
    export function initGrid() {
       const gridHelper = new GridHelper(100, 50);
       SCENE.add(gridHelper);
    }
    
    
    //  性能检测
    export const STATS = new Stats();
    export function initStats(doc) {
       STATS.setMode(0);
       STATS.domElement.style.position = 'absolute';
       STATS.domElement.left = '0px';
       STATS.domElement.top = '0px';
       doc.appendChild(STATS.domElement);
    }
    

    以上的代码是一个场景的基本属性,如果你看过threejs就知道了。

    3、新建一个canva component ( ng g component canva )

    html

    <div id="canvas" #canvasFrame></div>
    

    scss

    #canvas {
          width: 100%;
          display: block;
          height: 100%;
          position: relative;
    }
    

    ts

    import { Component, OnInit, ViewChild, ElementRef } from '@angular/core';
    import {
      initRenderer,
      initCamera,
      initScene, initLight,
      initGrid, initStats,
      RENDERER, CAMERA, SCENE, CONTROLS, STATS
    } from '../../config/base';
    import { ChassisService, LineService } from '../../importModels';
    import {
      FXAAShader, UnrealBloomPass, ShaderPass, FilmPass, OutlinePass, GeometryUtils, CopyShader, ColorifyShader, SepiaShader,
      OrbitControls, GLTFLoader, EffectComposer, RenderPass, SMAAShader, SMAAPass, ClearMaskPass, MaskPass,
    } from 'three-full';
    import * as  TWEEN from '@tweenjs/tween.js';
    import { Vector2, Group, Scene, SphereGeometry, ImageUtils, AnimationMixer } from 'three';
    import { fromEvent } from 'rxjs';
    import { PickupService } from '../../service/pickup.service';
    
    @Component({
      selector: 'app-canva',
      templateUrl: './canva.component.html',
      styleUrls: ['./canva.component.scss']
    })
    export class CanvaComponent implements OnInit {
      @ViewChild('canvasFrame', { static: true }) canvasContainer: ElementRef;
      
       thing;
      constructor( ) { }
     
    
      ngOnInit() {
        this.init();
      }
    
    
      init() {
    
        initRenderer(this.canvasContainer.nativeElement);
        initCamera(this.canvasContainer.nativeElement);
        initScene();
        initLight();
        initGrid();
        initStats(this.canvasContainer.nativeElement);
       
        //  加载模型-star
        this.importantModel();
        //  加载模型-end
    
        //  渲染场景
        const rendererOut = () => {
          
            requestAnimationFrame(rendererOut);
          RENDERER.render(SCENE, CAMERA);
          CONTROLS.update();
          STATS.update();
    
        };
    
        rendererOut();
    
      }
    
      
    
    // 这个模型可以使用blender2.8(正处于beta版) 直接导出gltf
      importantModel() {
        const loader = new GLTFLoader();
        loader.load('assets/model/1.gltf', (gltf) => {
          console.log(gltf);
        
          gltf.scene.traverse((child) => {  // 遍历判断Mesh
            if (child.isMesh) {
              console.log(child);
              child.material.color = { r: 1, g: 2, b: 3 };    //  颜色
              child.material.metalness = 0.8;   //  金属度
              gltf.scene.background = 'rgba(0,0,0, 0.5)';
              gltf.scene.translateX(5);
              this.thing = gltf.scene;
              SCENE.add(this.thing);
            }
          });
    
        },
          undefined,
          (error) => {
            console.error(error);
          });
      }
    
    }
    

    因为不能上传文件所以你们自己导出一个或者随便下一个吧。

    相关文章

      网友评论

        本文标题:angular8+threejs 入坑

        本文链接:https://www.haomeiwen.com/subject/znptgqtx.html