绘制多个立方体

1.搭建react+ts 项目

npx create-react-app basics-demo --template typescript

react+ts 的用法可参考此链接: https://react-typescript-cheatsheet.netlify.app/docs/basic/setup

2.安装three依赖

npm install three @types/three --save

3.安装路由

npm install react-router@6 react-router-dom@6

react-router-v6 的用法可参考此链接:https://juejin.cn/post/7088526716049555492

4.用路由组件包裹APP。

index.tsx

import { BrowserRouter } from "react-router-dom";

import { createRoot } from "react-dom/client";

import App from "./App";

const container = document.getElementById("root") as HTMLElement;

const root = createRoot(container);

root.render(

);

5.构建项目页面

src/view/Basics.tsx

import React from "react";

const Basics: React.FC = (): JSX.Element => {

return (

);

};

export default Basics;

src/view/RenderStructure.tsx

import React from "react";

const RenderStructure: React.FC = (): JSX.Element => {

return

RenderStructure 渲染结构
;

};

export default RenderStructure;

6.用useRoutes hook 搭建路由。

App.tsx

import React from "react";

import { useRoutes } from "react-router-dom";

import "./App.css";

import Basics from "./view/Basics";

import RenderStructure from "./view/RenderStructure";

const App: React.FC = (): JSX.Element => {

const routing = useRoutes([

{

path: "/",

element: ,

},

{

path: "RenderStructure",

element: ,

]);

return <>{routing};

};

export default App;

7.建立导航栏

src/view/Basics.tsx

import React from "react";

import { Link } from "react-router-dom";

const Basics: React.FC = (): JSX.Element => {

return (

);

};

export default Basics;

8.在RenderStructure.tsx 页面导入立方体

src/view/RenderStructure.tsx

import React, { useRef, useEffect } from "react";

import { BoxGeometry, DirectionalLight, Mesh, MeshNormalMaterial, MeshPhongMaterial, PerspectiveCamera, Scene, WebGLRenderer } from "three";

const { innerWidth, innerHeight } = window;

const scene = new Scene();

const camera = new PerspectiveCamera(75, innerWidth / innerHeight, 0.1, 1000);

camera.position.z = 5;

const renderer = new WebGLRenderer();

renderer.setSize(innerWidth, innerHeight);

const geometry = new BoxGeometry();

const material = new MeshNormalMaterial();

const cube = new Mesh(geometry, material);

scene.add(cube);

function animate() {

requestAnimationFrame(animate);

cube.rotation.x += 0.01;

cube.rotation.y += 0.01;

renderer.render(scene, camera);

}

const RenderStructure: React.FC = (): JSX.Element => {

const divRef = useRef(null);

useEffect(() => {

const { current } = divRef;

if (current) {

current.innerHTML = "";

current.append(renderer.domElement);

animate();

}

}, []);

return

;

};

export default RenderStructure;

在上面的代码中,没有直接建立 ,而是在WebGLRenderer 对象的实例化方法里建立的,在其源码可以找到相关逻辑:

function WebGLRenderer( parameters = {} ) {

const _canvas = parameters.canvas !== undefined ? parameters.canvas : createCanvasElement()

……

this.domElement = _canvas;

……

}

通过WebGLRenderer 对象建立了canvas后,再在react的函数组件的useEffect hook 中,将canvas 添加到div 中。

const RenderStructure: React.FC = (): JSX.Element => {

const divRef = useRef(null);

useEffect(() => {

const { current } = divRef;

current && current.append(renderer.domElement);

animate();

}, []);

return

;

};

当前这个立方体的材质是MeshNormalMaterial,并不受光照影响

9.给立方体换个MeshPhongMaterial 材质,再添加光源

const geometry = new BoxGeometry();

const material = new MeshPhongMaterial({ color: 0x44aa88 });

const cube = new Mesh(geometry, material);

scene.add(cube);

const color = 0xffffff;

const intensity = 1;

const light = new DirectionalLight(color, intensity);

light.position.set(-1, 2, 4);

scene.add(light);

当前的渲染结构如下: 效果如下:

10. 添加两个立方体,几何体和材质可被多个Mesh 对象共享

const geometry = new BoxGeometry();

const material = new MeshPhongMaterial({ color: 0x44aa88 });

const cubes = [-2, 0, 2].map((num) => makeInstance(num));

scene.add(...cubes);

function makeInstance(x: number) {

const cube = new Mesh(geometry, material);

cube.position.x = x;

return cube;

}

function animate() {

requestAnimationFrame(animate);

cubes.forEach((cube) => {

cube.rotation.x += 0.01;

cube.rotation.y += 0.01;

});

renderer.render(scene, camera);

}

当前的渲染结构如下: 效果如下:

精彩链接

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: