前言
ThreeJS是一个用JavaScript写的开源3D图形库,它有个简单但是功能强大的3D渲染引擎,可以在网页浏览器里快速创建和展示3D图形。ThreeJS是一个功能强大、使用简单的3D图形库,提供了一个强大的3D渲染工具,大大降低了创建3D应用程序的难度。
效果图
解析
安装
代码包可以到网上去找一些迷你版本的包,先放在本地用一下,然后跑终端可以从终端运行:npx vite
插件
Three.js 开箱即用,包含 3D 引擎的基础知识。其他 Three.js 组件(例如控件、加载器和后处理效果)是addons/目录的一部分。插件不需要单独安装,但需要单独导入。
轨道控制
轨道控制允许相机围绕目标旋转。 要使用此功能,与 /examples 目录中的所有文件一样,您必须将该文件单独包含在 HTML 中。
OrbitControls 是一个附加组件,必须显式导入。请参阅安装/插件。
import{OrbitControls}from'three/addons/controls/OrbitControls.js';
创建场景
为了真正能够用 Three.js 显示任何东西,我们需要三样东西:场景、相机和渲染器,这样我们就可以用相机渲染场景。
const scene = new THREE.Scene(); | |
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 ); | |
const renderer = new THREE.WebGLRenderer(); | |
renderer.setSize( window.innerWidth, window.innerHeight ); | |
document.body.appendChild( renderer.domElement ); |
渲染场景
如果您将上面的代码复制到我们之前创建的 HTML 文件中,您将看不到任何内容。这是因为我们实际上还没有渲染任何东西。
function animate() { | |
requestAnimationFrame(animate); | |
controls.update(); | |
renderer.render(scene, camera); | |
} | |
animate(); |
添加轨道
var controls = new THREE.OrbitControls(camera, renderer.domElement); | |
controls.enableDamping = true; | |
controls.minPolarAngle = Math.PI / 2 - 0.6; | |
controls.maxPolarAngle = Math.PI / 2 + 0.1; | |
controls.target.y = 2; |
添加照片
function addBox(imageUrl) { | |
const texture = textureLoader.load(imageUrl); | |
const geometry = new THREE.BoxGeometry(5, 5, 0.2); | |
const material = new THREE.MeshLambertMaterial({ color: 0xffffff, map: texture }); | |
const cube = new THREE.Mesh(geometry, material); | |
//cube.position.y = 2.5; | |
cube.position.setFromCylindricalCoords(random(15, 25), random(-Math.PI * 2, Math.PI * 2), 2.5); | |
cube.lookAt(0, 2, 0); | |
scene.add(cube); | |
const lookAtPosition = new THREE.Vector3(0, 2, 0); | |
lookAtPosition.lerp(cube.position, 0.3); | |
controls.target.copy(lookAtPosition); | |
} |
代码
index.html
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Three js</title> | |
<style> | |
html, | |
body { | |
height: 100%; | |
overflow: hidden; | |
margin: 0; | |
} | |
input { | |
position: fixed; | |
top: 90vh; | |
left: 50vw; | |
transform: translate(-50%, -50%); | |
background: transparent; | |
border: 1px solid #fff; | |
padding: 10px 20px; | |
font-size: 24px; | |
color: #fff; | |
opacity: 0.2; | |
outline: none; | |
transition: 0.5s; | |
border-radius: 5px; | |
} | |
input:focus { | |
opacity: 1; | |
} | |
</style> | |
</head> | |
<body> | |
<input type="text" id="caption" placeholder="Type a caption"> | |
<script src="third_party/three.min.js"></script> | |
<script src="third_party/OrbitControls.js"></script> | |
<script src="js/index.js"></script> | |
</body> | |
</html> |
index.js
function random(min, max) { | |
return min + Math.random() * (max - min); | |
} | |
const scene = new THREE.Scene(); | |
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); | |
const renderer = new THREE.WebGLRenderer({ | |
antialias: true, | |
powerPreference: 'high-performance' | |
}); | |
renderer.setPixelRatio(window.devicePixelRatio); | |
renderer.setSize(window.innerWidth, window.innerHeight); | |
renderer.outputEncoding = THREE.sRGBEncoding; | |
document.body.appendChild(renderer.domElement); | |
var controls = new THREE.OrbitControls(camera, renderer.domElement); | |
controls.enableDamping = true; | |
controls.minPolarAngle = Math.PI / 2 - 0.6; | |
controls.maxPolarAngle = Math.PI / 2 + 0.1; | |
controls.target.y = 2; | |
const ambientLight = new THREE.AmbientLight(0x202020); | |
scene.add(ambientLight); | |
const hemiLight = new THREE.HemisphereLight(0xffffbb, 0x080820, 1); | |
hemiLight.color.setHSL(0.6, 1, 0.1); | |
hemiLight.groundColor.setHSL(0.1, 0.2, 0.1); | |
scene.add(hemiLight); | |
const gridHelper = new THREE.GridHelper(100, 20); | |
scene.add(gridHelper); | |
const pointLight = new THREE.PointLight(0xffffff, 1, 100); | |
pointLight.position.set(0, 10, 5); | |
scene.add(pointLight); | |
const groundGeo = new THREE.PlaneBufferGeometry(105, 105); | |
const groundMat = new THREE.MeshLambertMaterial({ side: THREE.DoubleSide }); | |
groundMat.color.setHSL(0.095, 1, 0.75); | |
const ground = new THREE.Mesh(groundGeo, groundMat); | |
ground.rotation.x = -Math.PI / 2; | |
scene.add(ground); | |
const textureLoader = new THREE.TextureLoader(); | |
function addBox(imageUrl) { | |
const texture = textureLoader.load(imageUrl); | |
const geometry = new THREE.BoxGeometry(5, 5, 0.2); | |
const material = new THREE.MeshLambertMaterial({ color: 0xffffff, map: texture }); | |
const cube = new THREE.Mesh(geometry, material); | |
//cube.position.y = 2.5; | |
cube.position.setFromCylindricalCoords(random(15, 25), random(-Math.PI * 2, Math.PI * 2), 2.5); | |
cube.lookAt(0, 2, 0); | |
scene.add(cube); | |
const lookAtPosition = new THREE.Vector3(0, 2, 0); | |
lookAtPosition.lerp(cube.position, 0.3); | |
controls.target.copy(lookAtPosition); | |
} | |
for (let i = 0; i < 10; i++) { | |
addBox('img/641.jpg') | |
} | |
camera.position.z = 5; | |
function generateImage(caption) { | |
const inputs = { | |
"caption": caption | |
}; | |
fetch('http://localhost:8001/query', { | |
method: 'POST', | |
headers: { | |
Accept: 'application/json', | |
'Content-Type': 'application/json', | |
}, | |
body: JSON.stringify(inputs) | |
}) | |
.then(response => response.json()) | |
.then(outputs => { | |
const { result } = outputs; | |
console.log(result); | |
addBox(result); | |
}) | |
} | |
function animate() { | |
requestAnimationFrame(animate); | |
controls.update(); | |
renderer.render(scene, camera); | |
} | |
animate(); | |
document.getElementById('caption').addEventListener('keydown', (e) => { | |
if (e.key === 'Enter') { | |
const caption = e.currentTarget.value; | |
generateImage(caption); | |
e.currentTarget.value = ''; | |
} | |
}) | |
generateImage('a boat'); |