angular10+threejs搭建3D

以前用纯js+threejs开发了3D。现在用angular试试。会展示部分代码。流程如下

 1.搭建项目环境
	ng new 项目名
	引入需要的3d包,并且要加类型的说明,否则无法调用,如下:
	cnpm i three --save
	cnpm i three-full --save
	cnpm i gsap --save
	cnpm i stats.js --save
	---------------------------
	cnpm i @types/three -s
	cnpm i @types/three-full -s
	cnpm i @types/gsap -s
	cnpm i @types/stats.js -s
	以上安装完成需要的3D支持和环境库。
2.展示代码
	在src目录下建立conf/modul.ts
		import {
  Scene,
  AmbientLight,
  PointLight,
  WebGLRenderer,
  PerspectiveCamera,
  GridHelper,
  Vector2,
  Raycaster,
  Color
} from 'three';

import {
   CSS2DRenderer
} from 'node_modules/three/examples/jsm/renderers/CSS2DRenderer';
// @ts-ignore
import * as Stats from 'node_modules/stats.js/build/stats.min.js';

import {
  FXAAShader, UnrealBloomPass, ShaderPass, FilmPass, OutlinePass, GeometryUtils, CopyShader, ColorifyShader, SepiaShader,
  OrbitControls, GLTFLoader, EffectComposer, RenderPass, SMAAShader, SMAAPass, ClearMaskPass, MaskPass,
} from 'three-full';

//  渲染器
export const RENDERER = new WebGLRenderer(); //  渲染器(去据此){ antialias: true }
// @ts-ignore
export const CSS2DRENDER = new CSS2DRenderer();

// tslint:disable-next-line:typedef
export function initRenderer(doc) {
  RENDERER.setSize(
    doc.clientWidth,
    doc.clientHeight
  );
  RENDERER.shadowMap.enabled = true; // 辅助线
  doc.appendChild(RENDERER.domElement);

  CSS2DRENDER.setSize(
    doc.clientWidth,
    doc.clientHeight
  );
  CSS2DRENDER.domElement.style.position = 'absolute';
  CSS2DRENDER.domElement.style.top = '0' ;
  CSS2DRENDER.domElement.className  = 'Css2DRenderDiv';
  doc.appendChild(CSS2DRENDER.domElement);

}


// 场景
export const SCENE = new Scene();

export const MOUSE = new Vector2();
export const raycaster = new Raycaster();

// tslint:disable-next-line:typedef
export function initScene() {
  SCENE.background = new Color(0xcccccc);
}

//  灯光
// tslint:disable-next-line:typedef
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;
// tslint:disable-next-line:typedef
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: 0,
    y: 600,
    z: 200,
  };
  CAMERA.position.set(p.x, p.y, p.z);
  CAMERA.lookAt(0, 0, 0);
  CONTROLS = new OrbitControls(CAMERA, CSS2DRENDER.domElement);  // 控制镜头
}


//  网格
// tslint:disable-next-line:typedef
export function initGrid() {
  const gridHelper = new GridHelper(100, 50);
  SCENE.add(gridHelper);
}


//  性能检测
export const STATS = new Stats();
// tslint:disable-next-line:typedef
export function initStats(doc) {
  STATS.setMode(0);
  STATS.domElement.style.position = 'absolute';
  STATS.domElement.left = '0px';
  STATS.domElement.top = '0px';
  doc.appendChild(STATS.domElement);
}

//  动画混合器组(把模型的动画混合器都push到这里面,在canvas.ts里面更新动画   )
export const MIXER = [];
3.在app-module.ts调用conf下配置的ts
	import { Component, OnInit, ViewChild, ElementRef } from '@angular/core';
import { EventManager } from '@angular/platform-browser';
import {
  initRenderer,
  initCamera,
  initScene, initLight,
  initGrid, initStats, MOUSE, raycaster, CSS2DRENDER,
  RENDERER, CAMERA, SCENE, CONTROLS, STATS, MIXER
} from '../../src/config/base';

// @ts-ignore
import {
  CSS2DObject
} from 'node_modules/three/examples/jsm/renderers/CSS2DRenderer';
import {
  FXAAShader, UnrealBloomPass, ShaderPass, FilmPass, OutlinePass, GeometryUtils, CopyShader, ColorifyShader, SepiaShader,
  OrbitControls, GLTFLoader, EffectComposer, RenderPass, SMAAShader, SMAAPass, ClearMaskPass, MaskPass,
} from 'three-full';
import { Vector2, Group, Scene, SphereGeometry, ImageUtils, AnimationMixer, MeshBasicMaterial, Mesh } from 'three';
import { fromEvent } from 'rxjs';
import {TweenMax} from 'gsap';
// import {ServerProcessService} from './share/server-process.service';


@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit{

  @ViewChild('canvasFrame', { static: true }) canvasContainer: ElementRef;
  thing;
  constructor(private eventManager: EventManager) { }
  title = 'datacenter';

  ngOnInit(): void {
    console.log('数据库获取值');
    // console.log(this.serverDataSource.getdata());
    this.init();
    // @ts-ignore
    this.eventManager.addGlobalEventListener('window', 'click', (e) => {
      this.checkisModelsection( e );

    });
    this.eventManager.addGlobalEventListener('window', 'resize', (e) => {
      const width = window.innerWidth;
      const height = window.innerHeight;

      CAMERA.aspect = width / height;
      CAMERA.updateProjectionMatrix();

      RENDERER.setSize( width, height );

      RENDERER.setPixelRatio(window.devicePixelRatio);
      RENDERER.setSize(window.innerWidth, window.innerHeight);

      CSS2DRENDER.setSize(window.innerWidth, window.innerHeight);
    });
    this.eventManager.addGlobalEventListener('window', 'touchend', (e) => {
      console.log(e);
    });

  }
  // tslint:disable-next-line:typedef
  onResize(){
    console.log('888');
  }
  // tslint:disable-next-line:typedef
  checkisModelsection( event ) {
    // tslint:disable-next-line:one-variable-per-declaration prefer-const
    let x, y, z, selectedObj ;
    if ( event.changedTouches ) {
      x = event.changedTouches[ 0 ].pageX;
      y = event.changedTouches[ 0 ].pageY;

    } else {
      x = event.clientX;
      y = event.clientY;
    }
    MOUSE.x = ( x / window.innerWidth ) * 2 - 1;
    MOUSE.y = - ( y / window.innerHeight ) * 2 + 1;

    raycaster.setFromCamera( MOUSE, CAMERA );
    const inter = raycaster.intersectObjects( [ SCENE ], true );
    if (inter.length > 0){
      selectedObj = inter[ 0 ].object;
      console.log(selectedObj);

      const parentDiv = document.createElement('div');

      parentDiv.className = 'modelLabel';

      const asName = '55';
      const sonDiv = document.createElement('div');
      sonDiv.className =  'power-child';
      sonDiv.innerText = asName;
      parentDiv.appendChild(sonDiv);


      // @ts-ignore
      const parentLabel = new CSS2DObject( parentDiv );
      parentLabel.visible = true;
      parentLabel.name = 'biaoqian';
      parentLabel.position.set( 0, 0, 0 );
      selectedObj.add(parentLabel);

      TweenMax.to(selectedObj.position, 1.5, {
        y: '60',
        x: '10',
        z: '60',
        delay: 1
      });
      TweenMax.to(selectedObj.scale, 1.5, {
        y: '5',
        x: '5',
        z: '5',
        delay: 2
      });
    }
  }
  // tslint:disable-next-line:typedef
  init() {
    initRenderer(this.canvasContainer.nativeElement);
    initCamera(this.canvasContainer.nativeElement);
    initScene();
    initLight();
    initGrid();
    initStats(this.canvasContainer.nativeElement);
    //  加载模型-star
    this.importantModel();
    //  加载模型-end

    // const delta = new Clock();
    const rendererOut = () => {
      requestAnimationFrame(rendererOut);
      RENDERER.render(SCENE, CAMERA);
      CSS2DRENDER.render(SCENE, CAMERA);
      CONTROLS.update();
      STATS.update();
      if (MIXER) {
        MIXER.map(r => {
          // r.update(delta.getDelta());
        });
      }
    };

    rendererOut();

  }
  // tslint:disable-next-line:typedef
  importantModel() {
    const rollOverGeo = new SphereGeometry( 5, 5, 5 );
    const rollOverMaterial = new MeshBasicMaterial( { color: 0xff0000, opacity: 0.5, transparent: true } );
    const rollOverMesh = new Mesh( rollOverGeo, rollOverMaterial );
    rollOverMesh.visible = true;
    rollOverMesh.position.set(20, 10, 0);
    rollOverMesh.name = 'robotMesh';
    SCENE.add( rollOverMesh );
  }
}

	
 不出意外肯定是可以跑起来了。案例里面也实现了部分的模型交互,动画以及对接数据库,剩下的就看你们想怎么弄。总直。重点还是模型,代码难度不大。到这里吧
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值