最近給了個(gè)需求,要求學(xué)習(xí)react + three.js 以后要是實(shí)現(xiàn)相應(yīng)的3d制作內(nèi)容 (最開始是講解,在結(jié)尾會(huì)附上全部代碼)
第一步還是安裝three.js
npm i three -S
在three.js的官網(wǎng)中有相應(yīng)的內(nèi)容
引入three.js
import * as THREE from 'three'
當(dāng)我們使用的時(shí)候就可以寫成
const sence = new THREE.sence()
跟著官網(wǎng)的教程完成基礎(chǔ)的內(nèi)容實(shí)現(xiàn)還是很簡(jiǎn)單的。 但是要基于react 就還是要有一些修改。
首先獲取dom 的時(shí)候 可以使用 ref
<div
id= "canvas"
style={{ width: '600px', height: '600px',background:'#888' }}
ref={(mount) => { this.mount = mount }}
/>
看到官網(wǎng)我們知道 要想呈現(xiàn)一個(gè)three.js的內(nèi)容我們需要 場(chǎng)景,相機(jī),和渲染器,
我們通過一個(gè)init() 的方法來實(shí)現(xiàn)內(nèi)容的顯示,然后在 compomentDidMount方法中調(diào)用他
componentDidMount() {
this.init()
}
init = () => { //使用this是因?yàn)槲覀冃枰褂胻his.mount來渲染數(shù)據(jù)
const scene = new THREE.Scene() //創(chuàng)建場(chǎng)景
const camera = new THREE.PerspectiveCamera( 75, this.mount.clientWidth / this.mount.clientHeight, 0.1, 1000 );
//創(chuàng)建相機(jī) 這些參數(shù)在官網(wǎng)中都有指出 第一個(gè)參數(shù) 75 -> 視野角度(單位:度) 第二個(gè)參數(shù)是長(zhǎng)寬比 第三個(gè)是近截面 第四個(gè)是遠(yuǎn)截面
const renderer = new THREE.WebGLRenderer({ antialias: true });
//創(chuàng)建渲染器。講道理我還沒有看這個(gè)參數(shù)是什么意思。 但是官網(wǎng)中有一個(gè)測(cè)試瀏覽器是否可以使用WebGL的方法,需要用到的可看一下
this.scene = scene
this.camera = camera
this.renderer = renderer
//這三個(gè)賦值是為了方便我們把創(chuàng)建立方體或者其他元素的方法拆分出去,不讓代碼顯得太長(zhǎng)
renderer.setSize(this.mount.clientWidth, this.mount.clientHeight );
//將渲染器的長(zhǎng)寬 設(shè)置為我們要顯示的容器長(zhǎng)寬
this.mount.appendChild( renderer.domElement );
//將整個(gè)場(chǎng)景推入我們要顯示的元素中
camera.position.z = 5;
// 我們生成的元素默認(rèn)和相機(jī)的位置是重復(fù)的,我們需要將相機(jī)移開,這樣我們才可以看到渲染的內(nèi)容
this.createCube()
this.animate()
}
在場(chǎng)景創(chuàng)建好之后,我們需要在場(chǎng)景之中繪制我們需要的內(nèi)容 我們按照官網(wǎng)先繪制一個(gè)立方體 cube,在 init之中引用 creatCube
creatCube = () => {
const geometry = new THREE.BoxGeometry( 1, 2, 1, 4 );//繪制一個(gè)立方體,擦?xí)喈?dāng)于定點(diǎn)位置 (three自帶的對(duì)象)
const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
//定義材質(zhì) 我們這里用簡(jiǎn)單的顏色 , 其他的屬性可以寫入對(duì)象,就可以更改材質(zhì)
const cube = new THREE.Mesh( geometry, material );
//我們用到網(wǎng)格將 定義的材質(zhì)用到定義的立方題上生成cube
this.cube = cube //同樣 為了方便我們?cè)趯懛椒ǖ臅r(shí)候用到cube做此操作
this.scene.add( cube );//將我們生成的cube放到場(chǎng)景中
}
此時(shí)我們看到的場(chǎng)景是一片綠色的方塊,為了顯示出我們生成的是3d 的立方體 我們運(yùn)用animate讓他動(dòng)起來 在init中引用
animate = () => {
requestAnimationFrame( this.animate ); //像計(jì)時(shí)器一樣重復(fù)的渲染
this.cube.rotation.x += 0.01;
this.cube.rotation.y += 0.01; // 立方體進(jìn)行 的操作
this.renderer.render( this.scene, this.camera );
}
接下來是官網(wǎng)有一個(gè)繪制線的教程
我就不做講解了。 在全部代碼中有體現(xiàn)
所以全部的代碼如下
import React, { Component } from 'react';
import * as THREE from 'three';
import Orbitcontrols from 'three-orbitcontrols';
import './index.less'
class Three extends Component {
componentDidMount() {
this.init()
}
init = () => {
const scene = new THREE.Scene()
const camera = new THREE.PerspectiveCamera( 75, this.mount.clientWidth / this.mount.clientHeight, 0.1, 1000 );
const renderer = new THREE.WebGLRenderer({ antialias: true });
this.scene = scene
this.camera = camera
this.renderer = renderer
renderer.setSize(this.mount.clientWidth, this.mount.clientHeight );
this.mount.appendChild( renderer.domElement );
camera.position.z = 5;
this.createCube()
this.createLine()
this.animate();
}
createCube = () => {
const geometry = new THREE.BoxGeometry( 1, 2, 1, 4 );
const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
const cube = new THREE.Mesh( geometry, material );
this.cube = cube
this.scene.add( cube );
}
createLine = () => {
const material = new THREE.LineBasicMaterial({color: 0x0f00ff}) //定義線的材質(zhì)
const geometry = new THREE.Geometry()
geometry.vertices.push(new THREE.Vector3(-2, 0, 0))
geometry.vertices.push(new THREE.Vector3( 0, 2, 0) ); //相當(dāng)于是從 將前兩個(gè)坐標(biāo)連成一條線
// geometry.vertices.push(new THREE.Vector3( 2, 0, 0) );
const line = new THREE.Line(geometry, material)
this.line = line
line.position.x = -1
line.position.y = 2
this.scene.add(line)
}
animate =() => {
requestAnimationFrame( this.animate );
this.cube.rotation.x += 0.01;
this.cube.rotation.y += 0.01;
this.line.rotation.x += 0.02
this.renderer.render( this.scene, this.camera );
}
componentWillUnmount() {
this.mount.removeChild(this.renderer.domElement)
}
render() {
return (
<div
id= "canvas"
style={{ width: '600px', height: '600px',background:'#888' }}
ref={(mount) => { this.mount = mount }}
/>
);
}
}
// ReactDOM.render(<Scene />, document.getElementById('canvas'))
export default Three;