读取别人网站代码自己做,WordPress小说模板国外,网站不备案 能打开吗,长沙 网站seo服务 网络服务在上篇博客中介绍了如何快速利用react搭建three.js平台#xff0c;并实现3D模型的可视化。本文将在上一篇的基础上强化坐标系的概念。引入AxesHelper辅助工具及文本绘制工具#xff0c;带你快速理解camer、坐标系、position、可视区域。 Three.js机器人与星系动态场景#x… 在上篇博客中介绍了如何快速利用react搭建three.js平台并实现3D模型的可视化。本文将在上一篇的基础上强化坐标系的概念。引入AxesHelper辅助工具及文本绘制工具带你快速理解camer、坐标系、position、可视区域。 Three.js机器人与星系动态场景实现3D渲染与交互式控制-CSDN博客 AxesHelper辅助坐标系
three.js提供了 AxesHelper方法在3D场景中建立一个x、y、z两两垂直的坐标系。由于在网页中通常用z-index表示高度或者层级在3D场景中z表示离屏幕的距离z越大物体离实现越近。所以在3D中的坐标系默认是y轴朝上。 辅助坐标系便于开发者或用户在视觉上识别和定位场景中的物体。坐标轴辅助器通常在开发阶段用于调试但在最终的产品中也可以保留以帮助用户理解3D空间 使用方法 const axesHelper new THREE.AxesHelper(150);scene.add(axesHelper); AxesHelper是Three.js库中的一个类用于创建一个可视化的坐标轴X轴、Y轴和Z轴。括号中的150是一个参数表示坐标轴的长度为150个单位。 通过THREE的AxesHelper方法创建并通过scene添加到场景中。 通过这个方法可以看到在3D中生成了坐标轴辅助线。 three.js坐标轴颜色红R、绿G、蓝B分别对应坐标系的x、y、z轴 绘制文本并让文字始终朝向用户 在旋转过程中坐标系可能会混乱虽然你强迫自己记住xyz对应红绿蓝但是用着用着就蒙了。可以借助文字辅助理解。然而在threeJS中文本也是当物体绘制出来。不是几行代码就能实现的。这里文字需要通过load进行加载并且文字有自己的position在循环动画时添加文本的lookAt为camera的position让文本始终看着相机即可实现文本朝向用户。 创建文本
import { TextGeometry } from three/examples/jsm/geometries/TextGeometry;//创建文本
function createText(content: string, font: any) {const textGeometry new TextGeometry(content, {font: font,size: 1,height: 0.1,curveSegments: 1,});textGeometry.center();const textMaterial new THREE.MeshPhongMaterial({ color: 0xffffff, flatShading: true }); // frontconst mesh new THREE.Mesh(textGeometry, textMaterial);return mesh;
} 解析字体的json文件 //坐标系添加文字const loader new FontLoader();let meshX new THREE.Mesh();let meshY new THREE.Mesh();let meshZ new THREE.Mesh();loader.load(fonts/optimer_regular.typeface.json, function (font) {meshX createText(X, font);meshY createText(Y, font);meshZ createText(Z, font);meshX.position.x 12;meshY.position.y 12;meshZ.position.z 12;scene.add(meshX);scene.add(meshY);scene.add(meshZ);});这个json后缀的文件是用来解析字体的load的第一个参数是json的url。json数据从哪获取 打卡node_modules或者你下的threejs源码找到examples/fonts将其复制到public文件夹。就可以引入了 在学习threeJS过程中我也是不断参考example示例找所需的资源 相机camera
camera相机 相机在3D场景的作用可以想象成是你手中的一个真实的相机或者你的眼睛。在现实生活中你站在某个地方你的位置就是相机的位置。比如说你站在一个公园的角落从这个位置你可以看到公园里的不同景物。在Three.js中camera代表了观察者可以是你的眼睛或者一个虚拟的摄像头在3D空间中的位置和视角。 PerspectiveCamera 相机 three.js 里有几种不同的相机在这里我们使用的是 PerspectiveCamera透视摄像机这个相机类型最接近我们现实生活中观察世界的方式因为它使用透视投影来渲染场景。透视投影的特点是近大远小这使得远处的物体看起来比实际小而近处的物体则显得更大。 关键参数
当你创建一个 PerspectiveCamera 时通常需要设置以下几个参数 视野Field of View, FOV这是相机视野的角度通常以度数表示。较大的 FOV 会使场景看起来更宽广而较小的 FOV 则会使场景看起来更狭窄。 长宽比Aspect Ratio这是相机视口的宽度与高度的比率。通常设置为渲染窗口的宽度除以高度。 近裁剪面Near Clipping Plane这是相机能够看到的最近的距离。任何比这个距离更近的物体都不会被渲染。 远裁剪面Far Clipping Plane这是相机能够看到的最远的距离。任何比这个距离更远的物体也不会被渲染。 想象一下你正在用眼睛看世界。PerspectiveCamera 就像你的眼睛它有一个视野范围FOV决定了你能看到多宽或多窄的场景。长宽比Aspect Ratio决定了你看到的画面是宽屏还是窄屏。近裁剪面和远裁剪面则决定了你能看到的最近和最远的物体。 在three.js中通常通过下面的方式创建透视相机通常设置宽高比就用视口可视区域的宽高比。 // 创建一个Three.js相机包括透视投影、宽高比、近裁剪面和远裁剪面const camera new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); position位置 position就是在3D场景中的物体的坐标信息在Three.js中设置camera.position就是确定你的“观察点”在哪里 可以对具有postion属性的物体通过set方法设置x,y,z坐标信息 camera.position.set(15, 12, 8); 也可以对Three.js的Object3D对象通过position.x和position.y单独设置坐标轴的值
lookAt方法 lookAt方法就像是你在决定你的相机或者你的眼睛要聚焦在哪个点上。当你调整相机对准某个特定对象时你实际上是在使用lookAt方法。在现实生活中即使你站在一个固定的位置你的头可以转向不同的方向去看向不同的物体。 lookAt看向的是3D空间中的具体点相机的位置和lookAt看向的点覆盖的区域就是网页渲染初始时的视野 举例继续上面的操场例子即使你站在同一个角落你可以选择看向操场的中心点也可以看向操场上的某个运动员或者某个特定的物体。当你看向某个点时你的注意力就集中在了那个方向上就像是在Three.js中调用lookAt方法让相机镜头指向那个点。
在本文中相机的位置position和lookAt坐标系 camera.position.set(15, 12, 8);camera.lookAt(0, 0, 0); 可以看到你的眼睛是能够看到x、y、z三个坐标的正向并且视线正对坐标原点。也就是第一个机器人。 robot2.position.x 6;robot2.position.z 6;
camera位置和lookAt对可视物体的影响
1.物体放在camera后面 示例的第一个机器人位于坐标原点第二个机器人x轴和z轴分别偏移了6个单位。因为camera的位置是x轴偏移15y轴偏移12因此能够看到两个机器人。如果我将第二个机器人的x和y都大于camera呢比如如下的设置 robot2.position.x 20;robot2.position.z 20; 可以看到默认页面加载是看不到第二个机器人的。但是相机位置和看向点不变我们旋转3D坐标系可以看到第二个机器人。说明此时机器人“站在了你的后面”因为你没看向它但它存在吗当然存在。 2.切换camera的lookAt
机器人2的位置信息 robot2.position.x 20;robot2.position.z 20;
切换相机的视角使其看到机器人2
camera.position.set(15, 12, 8);
camera.lookAt(20, 0, 20);可以看到页面初始时只能看到机器人2坐标原点在后面所以看不到原点上的机器人。但是旋转坐标系能够看到。 OrbitControls旋转坐标系 前面提了很多旋转坐标系。默认坐标系是不能旋转的在空间中位置信息确认了就是相对静止的。那我们怎么可以拖动屏幕实现立体观察的效果呢 在 Three.js 中如果你希望通过拖动屏幕来旋转场景中的坐标轴通常需要使用一些交互控制器例如 OrbitControls。OrbitControls 是一个控制器它允许用户通过拖动、滚动和按键来控制相机的位置和方向。 使用OrbitControls
import { OrbitControls } from three/examples/jsm/controls/OrbitControls;可以通过给controls对象添加一个事件监听当orbitControls改变了调用renderer重新渲染scene和camera // 设置相机控件轨道控制器OrbitControls
const controls new OrbitControls(camera, renderer.domElement);
// 如果OrbitControls改变了相机参数重新调用渲染器渲染三维场景
controls.addEventListener(change, function () {renderer.render(scene, camera); //执行渲染操作
});//监听鼠标、键盘事件
但在我们的代码中并没有显示的调用change的监听而是在设置循环动画的时候通过renderer.render方法重新渲染每一帧 const update () {requestAnimationFrame(update);camera.lookAt(20, 0, 20);robot.rotation.y - 0.005; //机器人旋转robot2.rotation.y - 0.005;// 粒子旋转starts.rotation.y - 0.001;starts.rotation.z 0.001;starts.rotation.x 0.001;renderer.render(scene, camera);};update(); //自动更新 虽然在 update 函数中没有显式调用 controls.update()但是 OrbitControls 在内部已经通过事件监听器在每次交互时更新了相机的位置和方向。当你移动鼠标或触摸屏幕时这些交互事件会被监听器捕获OrbitControls 会相应地调整相机然后 renderer.render(scene, camera) 会使用新的相机状态来渲染场景。 简而言之OrbitControls 的设计允许它不需要显式的 change 事件监听就能工作。它会在用户交互时自动更新相机然后在你的渲染函数中通过 renderer.render(scene, camera) 来反映这些更新。 如果你的场景中确实需要响应用户交互以外的事件来触发渲染或者你想要在特定条件下禁用某些控制行为那么监听 change 事件会很有用。但在大多数情况下对于基本的交互控制OrbitControls 已经提供了所需的功能。 OrbitControls本质 OrbitControls本质上就是改变相机的参数比如相机的位置属性改变相机位置也可以改变相机拍照场景中模型的角度实现模型的360度旋转预览效果 完整版代码
import { useEffect, useRef } from react;
import * as THREE from three;
import { OrbitControls } from three/examples/jsm/controls/OrbitControls;
import { FontLoader } from three/examples/jsm/loaders/FontLoader;
import { TextGeometry } from three/examples/jsm/geometries/TextGeometry;
//机器人脑袋
function createHead() {//SphereGeometry创建球形几何体const head new THREE.SphereGeometry(4, 32, 16, 0, Math.PI * 2, 0, Math.PI * 0.5);const headMaterial new THREE.MeshStandardMaterial({color: 0x43b988,roughness: 0.5,metalness: 1.0,});const headMesh new THREE.Mesh(head, headMaterial);return headMesh;
}
//触角
function generateHorn(y: number, z: number, angle: number) {//触角 CapsuleGeometry 创建胶囊形状的几何体。胶囊形状可以看作是一个圆柱体两端加上半球体const line new THREE.CapsuleGeometry(0.1, 2);const lineMaterial new THREE.MeshStandardMaterial({color: 0x43b988,roughness: 0.5,metalness: 1.0,});const lineMesh new THREE.Mesh(line, lineMaterial);lineMesh.position.y y;lineMesh.position.z z;lineMesh.rotation.x angle;return lineMesh;
}
//机器人眼睛
function generateEye(x: number, y: number, z: number) {//SphereGeometry创建球形几何体const eye new THREE.SphereGeometry(0.5, 32, 16, 0, Math.PI * 2, 0, Math.PI * 2);const eyeMaterial new THREE.MeshStandardMaterial({color: 0x212121,roughness: 0.5,metalness: 1.0,});const eyeMesh new THREE.Mesh(eye, eyeMaterial);eyeMesh.position.x x;eyeMesh.position.y y;eyeMesh.position.z z;return eyeMesh;
}
//机器人身体
function generateBody() {//CylinderGeometry第一个参数是上部分圆的半径第二个参数是下部分圆的半径第三个参数是高度材质使用的跟腿一样const body new THREE.CylinderGeometry(4, 4, 6);const bodyMaterial new THREE.MeshStandardMaterial({color: 0x43b988,roughness: 0.5,metalness: 1.0,});const bodyMesh new THREE.Mesh(body, bodyMaterial);return bodyMesh;
}
//胳膊、腿
function generateLegs(y: number, z: number) {const leg1 new THREE.CapsuleGeometry(1, 4);const legMaterial1 new THREE.MeshStandardMaterial({color: 0x43b988,roughness: 0.5,metalness: 1.0,});const leg1Mesh new THREE.Mesh(leg1, legMaterial1);leg1Mesh.position.y y;leg1Mesh.position.z z;return leg1Mesh;
}
//创建机器人
function generateRobot() {// 创建一个Three.js对象用于存放机器人const robot new THREE.Object3D();const headMesh createHead();headMesh.position.y 6.5;robot.add(headMesh);//眼睛const leftEye generateEye(3, 8, -2);const rightEye generateEye(3, 8, 2);robot.add(leftEye);robot.add(rightEye);const leftHorn generateHorn(11, -1, (-Math.PI * 30) / 180);const rightHorn generateHorn(11, 1, (Math.PI * 30) / 180);robot.add(leftHorn);robot.add(rightHorn);const body generateBody();body.position.y 4;robot.add(body);// 生成机器人左腿robot.add(generateLegs(0, -2));// 生成机器人右腿robot.add(generateLegs(0, 2));//胳膊robot.add(generateLegs(3, 5));robot.add(generateLegs(3, -5));//物体缩放robot.scale.x 0.3;robot.scale.y 0.3;robot.scale.z 0.3;return robot;
}
//创建粒子星星
function generateStarts(num: number) {//制作粒子特效const starts new THREE.Object3D();const obj new THREE.SphereGeometry(0.2, 3, 3);const material new THREE.MeshStandardMaterial({color: 0x43b988,roughness: 0.5,metalness: 5,});const mesh new THREE.Mesh(obj, material);for (let i 0; i num; i) {const target new THREE.Mesh();target.copy(mesh);target.position.x Math.floor(Math.random() * 18 Math.floor(Math.random() * -18));target.position.y Math.floor(Math.random() * 18 Math.floor(Math.random() * -18));target.position.z Math.floor(Math.random() * 18 Math.floor(Math.random() * -18));starts.add(target);}return starts;
}
//创建文本
function createText(content: string, font: any) {const textGeometry new TextGeometry(content, {font: font,size: 1,height: 0.1,curveSegments: 1,});textGeometry.center();const textMaterial new THREE.MeshPhongMaterial({ color: 0xffffff, flatShading: true }); // frontconst mesh new THREE.Mesh(textGeometry, textMaterial);return mesh;
}
/*** 创建一个Three.js场景包括相机和渲染器*/
function Robot() {// 创建一个div容器用于存放渲染的Three.js场景const containerRef useRefHTMLDivElement(null);const scene new THREE.Scene();// 创建一个Three.js相机包括透视投影、宽高比、近裁剪面和远裁剪面const camera new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);camera.position.set(15, 12, 8);camera.lookAt(0, 0, 0);// 创建一个Three.js渲染器包括抗锯齿const renderer new THREE.WebGLRenderer({ antialias: true });renderer.setSize(window.innerWidth, window.innerHeight);//添加坐标系const axisHelper new THREE.AxesHelper(150);scene.add(axisHelper);//坐标系添加文字const loader new FontLoader();let meshX new THREE.Mesh();let meshY new THREE.Mesh();let meshZ new THREE.Mesh();loader.load(fonts/optimer_regular.typeface.json, function (font) {meshX createText(X, font);meshY createText(Y, font);meshZ createText(Z, font);meshX.position.x 12;meshY.position.y 12;meshZ.position.z 12;scene.add(meshX);scene.add(meshY);scene.add(meshZ);});const robot generateRobot();const robot2 generateRobot();robot2.position.x 6;robot2.position.z 6;// 将机器人身体添加到场景中scene.add(robot);scene.add(robot2);// 创建一个Three.js方向光包括颜色、强度const straightLight new THREE.DirectionalLight(0xffffff, 5);// 设置方向光的位置straightLight.position.set(20, 20, 20);// 将方向光添加到场景中scene.add(straightLight);const starts generateStarts(200);scene.add(starts);//轨道控制器const controls new OrbitControls(camera, renderer.domElement);controls.update();const animate () {requestAnimationFrame(animate);robot.rotation.y - 0.005; //机器人旋转robot2.rotation.y - 0.005;// 粒子旋转starts.rotation.y - 0.001;starts.rotation.z 0.001;starts.rotation.x 0.001;//meshX.lookAt(camera.position);meshY.lookAt(camera.position);meshZ.lookAt(camera.position);renderer.render(scene, camera);};animate(); //添加动画// 监听组件挂载和卸载useEffect(() {// 如果div存在将渲染器dom元素添加到div中if (containerRef.current) {containerRef.current.appendChild(renderer.domElement);// 渲染场景renderer.render(scene, camera);}}, [containerRef]);// 返回div容器用于存放渲染的Three.js场景return div ref{containerRef} style{{ width: 100vw, height: 100vh }}/div;
}// 导出Robot组件
export default Robot;