Используйте CSS3DRenderer в three.js для достижения эффекта 3D-карт.

внешний интерфейс three.js

предисловие

Недавно я хочу сделать эффект 3D карты.Схема конструкции выглядит следующим образом:

первая попытка

В первый раз я выбрал PixiJS, с которым я знаком.По поводу того, как я сделал неудачную 3D-карту со Sprite3d в PixiJS, вы можетеНажмите здесь, чтобы просмотреть.

вторая попытка

После первой неудачи я решил использовать three.js для достижения 3D-эффектов.

Но зачем использовать реализацию CSS3DRenderer, возможно, CSS3DRenderer связан с CSS.

CSS3DRenderer может напрямую передаватьTHREE.CSS3DObject(DOMElement)Преобразуйте элемент Dom в 3D-элемент, затем управляйте объектом.positionа такжеrotationв атрибутеx,y,zдля достижения анимационных эффектов.

Эффект

Визуализация выглядит следующим образом, онлайн-превьюкликните сюда.

Процесс реализации

Сначала определите и инициализируйте камеру, сцену, средство визуализации и элементы управления.

основной код

импортные компоненты

<script src="./js/three.js"></script>
<script src="./js/tween.min.js"></script>
<script src="./js/TrackballControls.js"></script>
<script src="./js/CSS3DRenderer.js"></script>

Соберите фреймворк three.js, следующий код завершает построение 3D-сцены, после чего вам нужно только добавить элементы в сцену.

let camera,scene,renderer; // 定义相机、场景和渲染器
let controls; // 定义控制器

window.onload = ()=>{
    init(); 
    animate();
};

function init() {
    // 相机初始化
    camera = new THREE.PerspectiveCamera(40,window.innerWidth/window.innerHeight,1,10000); 
    camera.position.z = 3000;

    // 场景初始化
    scene = new THREE.Scene();
    
    // 场景中的元素在此处添加,代码在下一个片段
    ....

    // 渲染器初始化,这里使用的是 CSS3DRenderer 渲染
    renderer = new THREE.CSS3DRenderer();
    renderer.setSize(window.innerWidth,window.innerHeight);
    document.getElementById('container').appendChild(renderer.domElement);

    // 控制器初始化
    controls = new THREE.TrackballControls(camera, renderer.domElement);
    controls.addEventListener('change',render);

    window.addEventListener('resize',onWindowResize,false);

    render();
}

function onWindowResize(){
    camera.aspect = window.innerWidth/window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth,window.innerHeight);
    render();
}

function animate(){
    requestAnimationFrame(animate);
    controls.update();
}

function render(){
    renderer.render(scene,camera);
}

Добавьте элементы на сцену

// 这里我将元素的 css 属性放到 json 当中,方便遍历创建
const objectData = [
    // 卡片
    {
        verticalBg:{
            url:'./assets/bg_0.jpg',
            width: 1203,
            height: 589,
        },
        ground:{
            url:'./assets/bg_1.jpg',
            width:1203,
            height: 589,
            rotation:-Math.PI/180*70,
        },
        thingsRotation:Math.PI/180*70,
        things:[
            {
                url:'./assets/card1_thing_0.png',
                width:403,
                height: 284,
                x:-80,
                y:-445,
            },
            ...
        ]
    }
];
// 最外层元素
const container = document.createElement('div'); // 使用 js 动态创建 DomElement
container.className = 'container';
const objectContainer = new THREE.CSS3DObject(container); // 使用 CSS3DObject 将 DomElement 转换为 3d 元素
scene.add(objectContainer); // 将转换好的 3d 元素添加到场景

objectData.forEach((cardItem,cardIndex)=>{
    // 卡片
    const cardContainer = document.createElement('div');
    cardContainer.style.width = 1448+'px';
    cardContainer.style.height = 750+'px';
    const objectCardContainer = new THREE.CSS3DObject(cardContainer);
    objectContainer.add(objectCardContainer); // 通过 object3D 的 add 方法实现嵌套

    //竖直背景
    const card_bg_vertical = document.createElement('div');
    card_bg_vertical.style.width = cardItem.verticalBg.width+'px';
    card_bg_vertical.style.height = cardItem.verticalBg.height+'px';
    card_bg_vertical.style.background = 'url('+cardItem.verticalBg.url+') no-repeat';
    const objectCardBgVertical = new THREE.CSS3DObject(card_bg_vertical);
    objectCardBgVertical.position.y = -80; // 通过 object3D 的 position 属性改变元素位置
    objectCardContainer.add(objectCardBgVertical);

    // 地面
    const card_groud = document.createElement('div');
    card_groud.style.width = cardItem.ground.width+'px';
    card_groud.style.height = cardItem.ground.height+'px';
    card_groud.style.transformOrigin = 'center top'; // 通过 css 中的 transform-origin 来改变旋转中心
    card_groud.style.background = 'url('+cardItem.ground.url+') no-repeat';
    const objectCardGround = new THREE.CSS3DObject(card_groud);
    objectCardGround.position.y = 80;
    objectCardGround.rotation.x = cardItem.ground.rotation; // 通过 object3D 的 rotation 属性来旋转元素
    objectCardContainer.add(objectCardGround);

    // 元素
    cardItem.things.forEach((item,index)=>{
        const thing = document.createElement('div');
        thing.style.width = item.width+'px';
        thing.style.height = item.height+'px';
        thing.style.background = 'url('+ item.url +') no-repeat';
        const objectThing = new THREE.CSS3DObject(thing);
        objectThing.rotation.x = cardItem.thingsRotation;
        objectThing.position.y = -(index+1)*68;
        objectThing.position.x = item.x;
        objectThing.position.z = -item.y-300;
        objectCardGround.add(objectThing);
    });
});

полный код

может быть напрямуюШтамп ссылкиСмотри, код не сжат.

Суммировать

Об API

  1. пройти черезTHREE.CSS3DObject(DOMElement)Элементы Dom могут быть преобразованы вobject3DТак что элемент DOM может напрямую наслаждаться 3D-сценой, предоставляемой Three.js;
  2. Вы можете управлять объектом Object3D с помощью анимированной библиотеки TWEEN.JS.positionа такжеrotationв атрибутеx,y,z, что позволяет добиться плавной анимации. Использование js для управления анимацией более гибко, чем css, и вы можете использовать three.js вlookat()и другие готовые методы.
  3. в состоянии пройтиcssсерединаtransform-originизменить центр вращения, потому что созданныйobject3DПо умолчанию центрировано, поэтому отладка положения после изменения центрального положения может быть немного хлопотной.

Отзывы

  1. Надо признать, что 3D-сцена, построенная с помощью three.js, действительно круче, чем сцена, построенная с помощью PixiJS;
  2. несмотря на то чтоobject3DВложенность может быть достигнута, но, просмотрев Дом в консоли, вы можете увидеть, что родительский и дочерний элементы дома находятся на одном уровне, что навело меня на мысль, что сначала вложенность не может быть достигнута;
  3. пройти черезcssсерединаtransform-originПосле смены центра вращения будут какие-то непонятные ситуации, попробуйте уменьшить смену центра вращения;
  4. Хотя сцена настроена, это тоже неудачная попытка. Так как у меня много уровней вложенности, после смены центра поворота вращение приведет к смещению элементов.Я не понял этой проблемы, поэтому на этом попытка остановилась, и я могу попробовать только другой путь;
  5. Если вы просто хотите создать 3D-сцену с картинками или простыми картинками, CSS3DRenderer — хороший выбор;
  6. ZibenСтуденты обнаружили в фактической разработке, что, когда сцена большая или добавляется анимация последовательности CSS, слабый Android будет отображаться медленнее, спасибо.Zibenотзывы одноклассников. Если вам нужна совместимость с недорогими устройствами Android, возможно, вам придется тщательно выбирать.

больше статей