使用Three.Js制作3D相册

JavaScript/前端
82
0
0
2024-09-14
标签   JavaScript库

前言

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

<!DOCTYPE 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');

引用

https://threejs.org/

https://github.com/mrdoob/three.js