angular中引入three.js并实现简易3d地球
项目地址
html中

1
<canvas #canvas></canvas>

ts文件中

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
import * as THREE from 'three';
import { OrbitControls } from 'three-orbitcontrols-ts';

private renderer: THREE.WebGLRenderer;
private camera: THREE.OrthographicCamera;
public scene: THREE.Scene;
public s = 200;//三维显示范围控制系数,系数越大,显示范围越大
public controls: OrbitControls;
public satellite: THREE.Points;

@ViewChild('canvas')
private canvasRef: ElementRef;

constructor() {
this.render = this.render.bind(this);
}
//获取canvas元素
private get canvas(): HTMLCanvasElement {
return this.canvasRef.nativeElement;
}
// 计算v1,v2 的中点
private getVCenter(v1, v2) {
let v = v1.add(v2);
return v.divideScalar(2);
}
// 计算V1,V2向量固定长度的点
private getLenVcetor(v1, v2, len) {
let v1v2Len = v1.distanceTo(v2);
return v1.lerp(v2, len / v1v2Len);
}
// 根据经纬度获得三位坐标点
lglt2xyz(lng, lat, radius) {
const theta = (90 + lng) * (Math.PI / 180)
const phi = (90 - lat) * (Math.PI / 180)
return (new THREE.Vector3()).setFromSpherical(new THREE.Spherical(radius, phi, theta))
}
// 添加飞线
private addLines(v0, v3) {
// 夹角
var angle = (v0.angleTo(v3) * 1.8) / Math.PI / 0.1; // 0 ~ Math.PI
var aLen = angle * 12,
hLen = angle * angle * 12;
var p0 = new THREE.Vector3(0, 0, 0);
var vtop = new THREE.Vector3(0, 0, 0);
// 法线向量
var rayLine = new THREE.Ray(p0, this.getVCenter(v0.clone(), v3.clone()));
// 顶点坐标
rayLine.at(hLen / rayLine.at(1, rayLine.origin).length(), vtop);
// 控制点坐标
var v1 = this.getLenVcetor(v0.clone(), vtop, aLen);
var v2 = this.getLenVcetor(v3.clone(), vtop, aLen);
// 绘制贝塞尔曲线
var curve = new THREE.CubicBezierCurve3(v0, v1, v2, v3);
var gLine = new THREE.BufferGeometry();
var gPoints = curve.getPoints(60);
gLine.setFromPoints(gPoints)
var mLine = new THREE.LineBasicMaterial({
color: 'violet',
});
return {
curve: curve,
lineMesh: new THREE.Line(gLine, mLine)
};
}

// 创建场景
private createScene() {
this.scene = new THREE.Scene();
var geometry = new THREE.SphereGeometry(130,40,40);//地球
//卫星
var p1 = new THREE.Vector3(200,0,0);
const points = [p1];
var satelliteGeometry = new THREE.BufferGeometry();
satelliteGeometry.setFromPoints(points);
// 贴图
var loader = new THREE.TextureLoader();
// 地球贴图
loader.load('../../assets/images/earth3.jpg', (texture)=>{
var material = new THREE.MeshLambertMaterial({
map:texture,//设置贴图属性值
})
var mesh = new THREE.Mesh(geometry,material)
this.scene.add(mesh)
});
// 卫星贴图
loader.load('../../assets/images/moon.png',(texture)=>{
var satelliteMaterial = new THREE.PointsMaterial({
map:texture,
transparent:true,
size:20,
depthWrite:false
})
this.satellite = new THREE.Points(satelliteGeometry,satelliteMaterial)
this.scene.add(this.satellite)
this.render();
})
// 飞线
var lGroup = new THREE.Group();
lGroup.add(this.addLines(this.lglt2xyz(116.20,39.56,130),this.lglt2xyz(-74.70,40.43,130)).lineMesh)
this.scene.add(lGroup)
}
// 创建光源
private createLight() {
var light = new THREE.AmbientLight(0xffffff)
this.scene.add(light);
}
// 创建相机
private createCamera() {
var k = window.innerWidth/window.innerHeight;//窗口宽高比
this.camera = new THREE.OrthographicCamera(-this.s*k,this.s*k,this.s,-this.s,1,10000);
this.camera.position.set(5,-20,200);
this.camera.lookAt(this.scene.position);
}
// 渲染器设置
private renderSetting() {
this.renderer = new THREE.WebGLRenderer({
canvas: this.canvas,
antialias: true
});
this.renderer.setSize(window.innerWidth, window.innerHeight);
this.renderer.setClearColor(0xb9d3ff, 1);

}
// 渲染函数
public render() {
this.renderer.render(this.scene, this.camera);
this.satellite.rotateY(0.01);
requestAnimationFrame(this.render);
}
// 鼠标控制
public addControls() {
this.controls = new OrbitControls(this.camera,this.renderer.domElement);
}

// 窗口自适应
@HostListener('window:resize', ['$event'])
public onResize(event: Event) {
this.canvas.style.width = "100%";
this.canvas.style.height = "100%";
this.renderer.setSize(this.canvas.offsetWidth, this.canvas.offsetHeight);
this.camera.updateProjectionMatrix();
}
ngOnInit() {
this.createScene();
this.createLight();
this.createCamera();
this.renderSetting();
this.addControls();
}