Крутые 3D-страницы в кислотном стиле с three.js

внешний интерфейс three.js
Крутые 3D-страницы в кислотном стиле с three.js

Мало знаний, большой вызов! Эта статья участвует в "Необходимые знания для программистов«Творческая деятельность.

задний план

недавно узналWebGLа такжеThree.jsНекоторые базовые знания, поэтому я хочу объединить популярный в последнее время стиль кислотного дизайна, украсить личную домашнюю страницу и обобщить некоторые полученные знания. Содержание этой статьи в основном представлено с помощьюReact + three.jsстек технологий, загружен3D模型,Добавить к3D文字, добавить анимацию, взаимодействие с кликом и т. д., используя дизайн стиля, чтобы добиться ощущения дизайна.🤢Страница в кислотном стиле.

Базовые знания

Three.js

Three.jsявляется уроженцемWebGLИнкапсулирует запуск в браузере3D引擎, вы можете использовать его для создания различных 3D-сцен, включая камеры, источники света, материалы и другие объекты. Это очень широко используемый 3D-движок. допустимыйОфициальная китайская документация three.jsУзнать больше.

Кислотный дизайн

酸性设计слово, переведенное сAcid Graphics, начинается в上世纪90年代эйсид-хаус, электронная танцевальная музыка и культура хиппи. В области дизайна эта кислотная эстетика имеет большое значение.自由的主张, гротескная графика, смелые и яркие цветовые схемы, особые фактуры материалов и разнообразие шрифтов формируют уникальный кислотный стиль дизайна.

Вкратце,鲜艳高饱和度сочетание цветов; темно-серая основа с высокой насыщенностью荧光色украшение экрана五彩斑斓的黑;Полный футуристический, крутой, полный технологического смысла液态金属,玻璃,铝箔塑料и другие материалы;随机элементы, макет графики;重复, резать, комбинировать几何图形и т. д. — это все кислотные стили дизайна. Кислотные стили также набирают популярность в обложках музыкальных альбомов, визуальных плакатах, обложках книг и фильмов, а также в веб-дизайне.

добиться эффекта

онлайн просмотр:tricell.fun

выполнить

3D модель

инициализация сцены

🌏Создать сцену
scene = new THREE.Scene();
📷Инициализировать камеру

透视相机 PerspectiveCameraиз4个Параметры относятся к: полю зрения, соотношению сторон, ближней плоскости, дальней плоскости.

camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.1, 1000);
// 设置相机位置
camera.position.set(600, 20, -200);
// 相机聚焦到屏幕中央
camera.lookAt(new THREE.Vector3(0, 0, 0));
💡Инициализировать источник света

Добавить к半球光源 HemisphereLight: Создает более естественный источник света для наружных эффектов.

light = new THREE.HemisphereLight(0xffffff, 0x444444);
light.position.set(0, 20, 0);
scene.add(light);
light = new THREE.DirectionalLight(0xffffff);
light.position.set(0, 20, 10);
light.castShadow = true;
scene.add(light);

Добавить к环境光 AmbientLight:

var ambiColor = '#0C0C0C';
var ambientLight = new THREE.AmbientLight(ambiColor);
scene.add(ambientLight);

Добавьте вспомогательные инструменты (необязательно)

📦Добавить вспомогательную сетку

GridHelperМожет использоваться для добавления направляющих сетки, а также может использоваться для украшения черезGridHelper(size, divisions, colorCenterLine, colorGrid)выполнить.

  • size: ширина сетки, по умолчанию10.
  • divisions: равная дробь, значение по умолчанию10.
  • colorCenterLine: цвет центральной линии, по умолчанию0x444444.
  • colorGrid: цвет линии сетки, по умолчанию0x888888.
var grid = new THREE.GridHelper(1000, 100, 0x000000, 0x000000);
grid.material.opacity = 0.1;
grid.material.transparent = true;
grid.position.set(0, -240, 0);
scene.add(grid);
📦Добавьте элементы управления камерой

Через управление камеройOrbitControlsТрехмерную сцену можно масштабировать, перемещать и вращать, причем существенно меняется не сама сцена, а параметры камеры. при разработкеOrbitControls.jsнеобходимо импортировать отдельно.

controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.target.set(0, 0, 0);
controls.update();
📦Добавить плагин просмотра производительности

statsЯвляетсяThree.jsРазработка вспомогательной библиотеки в основном используется для определения количества кадров при работе.stats.jsЕго также необходимо импортировать отдельно.

stats = new Stats();
container.appendChild(stats.dom);

модель нагрузки

используется в этом примере扔铁饼的人статуя3DМодель происходит отthreedscans.com,Могу免费😄Скачивайте и пользуйтесь, в конце этой статьи приведено несколько бесплатных сайтов для скачивания моделей, в том числе200多页Бесплатная модель, если вы заинтересованы, вы можете выбрать понравившуюся модель для загрузки и использования. Конечно, учащиеся со способностями к моделированию также могут использоватьblender,3dmaxи другое профессиональное программное обеспечение для моделирования для создания ваших любимых моделей.

нагрузкаobjилиfbxМодель

необходимо представить отдельноFBXLoader.jsилиOBJLoader.js,.fbxа также.objМетод загрузки модели для формата такой же.

// var loader = new THREE.FBXLoader();
var loader = new THREE.OBJLoader();
loader.load(model, function (object) {
  object.traverse(function (child) {
    if (child.isMesh) {
      child.castShadow = true;
      child.receiveShadow = true;
    }
  });
  object.rotation.y = Math.PI / 2;
  object.position.set(0, -200, 0);
  object.scale.set(0.32, 0.32, 0.32);
  model = object;
  scene.add(object);
});
нагрузкаgltfМодель

необходимо представить отдельноGLTFLoader.js,нагрузка.gltfМетод форматной модели немного отличается, следует отметить, что объект обхода модели и финальное дополнение к сценеobject.sceneвместоobject.

var loader = new THREE.GLTFLoader();
loader.load(model, function (object) {
  object.scene.traverse(function (child) {
    if (child.isMesh) {
      child.castShadow = true;
      child.receiveShadow = true;
    }
  });
  object.scene.rotation.y = Math.PI / 2;
  object.scene.position.set(0, -240, 0);
  object.scene.scale.set(0.33, 0.33, 0.33);
  model = object.scene;
  scene.add(object.scene);
});

Эффект после добавления сетки и загрузки модели показан на рисунке ниже.

Добавить анимацию поворотного стола

пройти черезrequestAnimationFrameМетод обновления страницы добавляет эффект анимации поворотного стола.window.requestAnimationFrame()Сообщите браузеру, что вы хотите выполнить анимацию, и попросите браузер вызвать указанную функцию обратного вызова, чтобы обновить анимацию перед следующей перерисовкой. Этот метод должен передать функцию обратного вызова в качестве параметра, функция обратного вызова будет выполнена до следующей перерисовки браузера.

function animate () {
  requestAnimationFrame(animate);
  // 随着页面重绘不断改变场景的rotation.y来实现旋转
  scene.rotation.y -= 0.015;
  renderer.render(scene, camera);
}

Добавить взаимодействие с кликом

существуетThree.jsВ сцене мы хотим нажать на модель, чтобы получить информацию о ней, или выполнить какие-то другие операции, нам нужно использоватьRaycaster(光线投射), принцип заключается в том, чтобы испускать пучок лучей в том месте, где вы щелкаете мышью, и записываются объекты в лучах. Основной синтаксисRaycaster(origin, direction, near, far),в:

  • origin: Вектор начальной точки луча.
  • direction: Вектор направления луча.
  • near: Все возвращаемые результаты должны быть меньшеnearДалеко. Значение не может быть отрицательным, значение по умолчанию равно0.
  • far: Все возвращаемые результаты должны быть меньшеfarблизко. не может быть меньшеnear, значение по умолчанию无穷大.

Основные шаги реализации кода: получить координаты мыши на экранеПреобразование координат экрана в стандартные координаты устройстваПреобразование стандартных координат устройства в мировые координатыПолучить мировые координаты мыши в сценеСгенерируйте единичный вектор направления raycast из мировых координат и камерыСоздает объект raycaster из единичного вектора направления raycast.

//声明raycaster和mouse变量
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();
onMouseClick = event => {
  // 将鼠标点击位置的屏幕坐标转成threejs中的标准坐标,以屏幕中心为原点,值的范围为-1到1.
  mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
  mouse.y = - (event.clientY / window.innerHeight) * 2 + 1;
  // 通过鼠标点的位置和当前相机的矩阵计算出raycaster
  raycaster.setFromCamera(mouse, camera);
  // 获取raycaster直线和所有模型相交的数组集合
  let intersects = raycaster.intersectObjects(scene.children);
  if (intersects.length > 0) {
    alert('HELLO WORLD')
    // 可以通过遍历实现点击不同mesh触发不同交互,如:
    let selectedObj = intersects[0].object;
    if (selectedObj.name === 'car') {
      alert('汽车🚗')
    }
  }
}
window.addEventListener('click', onMouseClick, false);

Добавить 3D-текст

использоватьTextGeometry(text : String, parameters : Object)Добавить к3D文字, ниже приводится описание устанавливаемых свойств:

  • size: размер шрифта, обычно высота заглавных букв.
  • height: Толщина текста.
  • weight: значениеnormalилиbold, указывая, следует ли выделять жирным шрифтом или нет.
  • font: шрифт, по умолчаниюhelvetiker, который должен соответствовать указанному файлу шрифта.
  • style: значениеnormalилиitalics, указывая, выделено ли оно курсивом
  • bevelThickness: Толщина фаски.
  • bevelSize: Ширина фаски.
  • curveSegments: количество сегментов дуги, чтобы сделать изгиб текста более плавным.
  • bevelEnabled: логическое значение, используется ли фаска, что означает скос на краю.
var loader = new THREE.FontLoader();
loader.load('gentilis_regular.typeface.json', function (font) {
  var textGeo = new THREE.TextGeometry('HELLO WORLD', {
    font: font,
    size: .8,
    height: .8,
    curveSegments: .05,
    bevelThickness: .05,
    bevelSize: .05,
    bevelEnabled: true
  });
  var textMaterial = new THREE.MeshPhongMaterial({ color: 0x03c03c });
  var mesh = new THREE.Mesh(textGeo, textMaterial);
  mesh.position.set(0, 3.8, 0);
  scene.add(mesh);
});

оптимизация

Теперь загрузка модели в основном завершена, но3DРазмер модели, как правило, относительно велик. После развертывания я обнаружил, что загрузка веб-страницы очень медленная, что влияет на взаимодействие с пользователем. Крайне необходимо уменьшить размер модели.3D建模软件случае, использоватьobj2gltfможет быть большеOBJМодель формата преобразуется вgltfМоделируйте, эффективно оптимизируйте объем модели и улучшите скорость загрузки веб-страниц.

Установить
npm install obj2gltf --save
Скопируйте модель obj в следующий каталог
node_modules\obj2gltf\bin
Выполнение инструкций по транскодированию
node obj2gltf.js -i demo.obj -o demo.gltf

Как показано на рисунке, аналогично предыдущему, перекодирование завершено, и сравнивается объем файла до и после преобразования.В этом примереkas.objНачальный размер файла9.7Mпреобразованный файлkas.gltfТолько4.6M, объем уменьшен вдвое, в это время на страницу загружается сконвертированная модель, при этом эффект изменения модели практически незаметен невооруженным глазом, а скорость загрузки страницы значительно повышается.

obj2gltfТакже доступен в виде библиотеки черезnode服务Модель преобразования в реальном времени, заинтересованные студенты могут узнать больше по ссылке в конце статьи. также можно использовать3Dпрограммное обеспечение для моделирования, такое какblenderи т.д. вручную путем уменьшения модели面数а также缩小体积Сжатие и оптимизация модели осуществляются другими способами, и эффект оптимизации более очевиден.

полный код

var model = require('@/assets/models/kas.gltf');
var container, stats, controls;
var camera, scene, renderer, light, model;
class Kas extends React.Component {
  render () {
    return (
      <div id="kas"></div>
    )
  }
  componentDidMount () {
    this.initThree();
  }
  initThree () {
    init();
    animate();
    function init () {
      container = document.getElementById('kas');
      scene = new THREE.Scene();
      scene.fog = new THREE.Fog(0xa0a0a0, 200, 1000);
      // 透视相机:视场、长宽比、近面、远面
      camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.1, 1000);
      camera.position.set(600, 20, -200);
      camera.lookAt(new THREE.Vector3(0, 0, 0));
      // 半球光源:创建室外效果更加自然的光源
      light = new THREE.HemisphereLight(0xffffff, 0x444444);
      light.position.set(0, 20, 0);
      scene.add(light);
      light = new THREE.DirectionalLight(0xffffff);
      light.position.set(0, 20, 10);
      light.castShadow = true;
      scene.add(light);
      // 环境光
      var ambiColor = '#0C0C0C';
      var ambientLight = new THREE.AmbientLight(ambiColor);
      scene.add(ambientLight);
      // 网格
      var grid = new THREE.GridHelper(1000, 100, 0x000000, 0x000000);
      grid.material.opacity = 0.1;
      grid.material.transparent = true;
      grid.position.set(0, -240, 0);
      scene.add(grid);
      // 加载gltf模型
      var loader = new THREE.GLTFLoader();
      loader.load(model, function (object) {
        object.scene.traverse(function (child) {
          if (child.isMesh) {
            child.castShadow = true;
            child.receiveShadow = true;
          }
        });
        object.scene.rotation.y = Math.PI / 2;
        object.scene.position.set(0, -240, 0);
        object.scene.scale.set(0.33, 0.33, 0.33);
        model = object.scene;
        scene.add(object.scene);
      });
      renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
      renderer.setPixelRatio(window.devicePixelRatio);
      renderer.setSize(window.innerWidth, window.innerHeight);
      renderer.setClearAlpha(0);
      renderer.shadowMap.enabled = true;
      container.appendChild(renderer.domElement);
      window.addEventListener('resize', () => {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);
      }, false);
      stats = new Stats();
      container.appendChild(stats.dom);
    }
    function animate () {
      var clock = new THREE.Clock()
      requestAnimationFrame(animate);
      var delta = clock.getDelta();
      scene.rotation.y -= 0.015;
      renderer.render(scene, camera);
      stats.update();
    }
    // 增加点击事件
    //声明raycaster和mouse变量
    var raycaster = new THREE.Raycaster();
    var mouse = new THREE.Vector2();
    function onMouseClick(event) {
      // 通过鼠标点击位置计算出raycaster所需要点的位置,以屏幕中心为原点,值的范围为-1到1.
      mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
      mouse.y = - (event.clientY / window.innerHeight) * 2 + 1;
      // 通过鼠标点的位置和当前相机的矩阵计算出raycaster
      raycaster.setFromCamera(mouse, camera);
      // 获取raycaster直线和所有模型相交的数组集合
      var intersects = raycaster.intersectObjects(scene.children);
      if (intersects.length > 0) {
        alert('HELLO WORLD')
      }
    }
    window.addEventListener('click', onMouseClick, false);
  }
}

другие элементы дизайна

Эта статья в основном знакомит3D元素загрузка, в связи с ограниченностью места и времени статьи (博主太懒😂) Реализация остальных элементов подробно объясняться не буду (может будет время подытожить позжеmaybe) Заинтересованные студенты могут прочитать следующие превосходные статьи других великих богов.

жидкий фон

静态Жидкие фоновые изображения могут бытьSVG filterреализовано, можно читать«Создание шаблонов с фильтрами SVG»,выполнить动态Жидкий фон можно реализовать с помощью Three.js в сочетании с собственным GLSL, см.《Шадер шейдера CodePen》пример для реализации.

Шрифты с кислотным эффектом, такие как металлик, неон, эффект глюка, можно прочитать в другой моей статье.«Визуальные эффекты в стиле Cyberpunk 2077 всего за несколько шагов CSS», вы также можете использовать создание дизайна. Из-за нехватки времени текст с металлическим эффектом в этом проекте и текст на изображении заголовка баннера этой статьи используютсяОнлайн-сайт для создания художественных шрифтовОн создается, и заинтересованные студенты могут попытаться разработать его самостоятельно.

Дальнейшая оптимизация в будущем

  • #todoРеализация жидкого фона в кислотном стиле.
  • #todo 3D模型Эффект жидкого металла.

three.jsОтличная рекомендация кейса

Наконец, я рекомендую несколько очень удивительныхthree.jsПриходите, чтобы испытать и извлечь уроки из проекта, будь то взаимодействие со страницей, визуальный дизайн или оптимизация производительности, мы достигли максимума и можем многому у него научиться.

использованная литература