Напишите отражающий шар с помощью three.js: панорама 360 + зеркальное отражение

WebGL three.js

предисловие

В этой статье мы будем использовать three.js для имитации отражающего мяча. Эффект следующий:

reflection.gif

Предварительное знание

это обучениеthree.js系列Третья статья, первые две статьи:

Напишите анимацию дождя с помощью three.js

Напишите небольшую сцену с помощью three.js

оthree.jsБазовые знания размещены в первой статье:Напишите анимацию дождя с помощью three.js, можете идти проверять, следующие случаи не повторятся.

Геометрия и материалы

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

существуетthree.js, при создании объекта нужно передать два параметра, один — это геометрия (Geometry), а другой — материал (Material).

const object = new THREE.Mesh(geometry, material)

геометрия

Функция Geometry (Геометрия) объекта хранит информацию о вершинах, информация о вершинах которой определяет форму объекта. Нарисуйте объект в пространстве, если он используетсяWebGL, требует от программиста указания местоположения каждой вершины, а вthree.js, вы можете напрямую объявлять геометрические фигуры, такие как куб, плоскость, сфера, цилиндр, тетраэдр, октаэдр и т. д. Вам нужно только передать параметры, необходимые для определения этих геометрических фигур в соответствии с документацией.

Некоторые примеры:

const floorGeometry = new THREE.PlaneGeometry( 800, 1000 )  //创建一个平面几何体,传入宽高
const sphereGeometry = new THREE.SphereGeometry(350, 50, 50)     //创建一个球体,传入半径和经度、纬度的分片
const doorGeometry = new THREE.BoxGeometry(100,210,40)      //创建一个立方体,传入长、宽、高

материал

Материалы подобны коже объекта, определяющей внешний вид геометрии. Например, скины определяют, выглядит ли часть геометрии металлической, прозрачной или нет, или отображается в виде каркаса.

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

  • MeshBasicMaterial: Цвет объекта после рендеринга всегда является цветом материала, который не реагирует на освещение, и не будет давать светотеневые и теневые эффекты из-за освещения.
const geometry = new THREE.BoxGeometry();    //不传入参数,则使用长宽高的默认值:1
const material = new THREE.MeshBasicMaterial({       //创建Basic材质
  color: 0x00ff00
})
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
图片替换文本
  • MeshLambertMaterial: Учитывается только диффузное отражение, а эффект зеркального отражения не учитывается.Не подходит для таких объектов, как металл и стекло.Если объект используетMeshLambertMaterial, необходимо добавить в сцену освещение, иначе объект не будет отображаться. И окончательный цвет отображения объекта определяется материаломcolor参数Определяется вместе со светлым цветом.Вот несколько типов света:

image.pngНиже показано сочетание направления света и материала Ламберта.Вы можете видеть, что каждая грань куба имеет разную степень освещенности и тени.

const material = new THREE.MeshLambertMaterial({ color: 0x00ff00 });    //创建Lambert材质

const directionLight = new THREE.DirectionalLight(0xffffff)  //创建平行光,参数是光的颜色
directionLight.position.set(10,10,10)                        //定义平行光方向
scene.add(directionLight)                                    //将平行光添加到场景中
图片替换文本
  • MeshPhongMaterial: Учитывая эффект зеркального отражения, подходит для металла, стекла и т. Д. В той же параллельной светлой среде материал куба установлен наMeshPhongMaterial, эффект выглядит следующим образом, вы можете видеть, что куб будет производить зеркальное отражение света.
const material = new THREE.MeshPhongMaterial({ 
  color: 0x00ff00,
  shininess: 100                      //决定Phong材质的高光度,当shininess值为0时,表现和MeshLambertMaterial材质一样
});
图片替换文本

Выше приведены некоторые основные методы создания материалов.Дополнительные материалы и параметры материалов можно найти в официальной документации.

текстура

Раньше мы все передавали материал, когда создавали его.colorзначение, созданный таким образом материал имеет один цвет. Однако чаще нам нужно генерировать материалы на основе изображений.

Ниже мы создаем куб с изображениями на всех шести сторонах. Здесь мы не учитываем влияние света и тени, используемMeshBasicMaterial

const geometry = new THREE.BoxGeometry();
const texture = new THREE.TextureLoader().load( `./images/pic1.jpg` )   //用TextureLoader加载图像文件
const material = new THREE.MeshBasicMaterial( { 
  map: texture     // 将加载好的图像作为map传给材质
} )
const cube = new THREE.Mesh(geometry, material);
图片替换文本

Обратите внимание, что использование загрузчика текстурTextureLoaderБудут междоменные ограничения на загрузку изображений. Если файл изображения и текущий HTML-файл не находятся в одном домене, а междоменное использование запрещено, загрузка файла изображения невозможна.

Таким образом, доступ к локальным файлам(file://xxx)Невозможно открыть html, вы можете использоватьlive-serverилиwebpack-dev-serverСоздайте сервер.

live-serverШаги по сборке сервера:Как использоватьlive-serverСоздайте простой сервер

Этот проект будет использоватьwebpack-dev-serverСоздайте сервер, и вы можете просмотреть исходный код, если вам нужна детская обувь.

К каждой стороне куба прикрепляется разное изображение.

Чтобы наклеить разные картинки на каждую грань куба, сначала подготовьте 6 картинок.image.pngИспользовать загрузчик текстурTextureLoaderДобавить 6 картинок отдельно, установить на шесть материалов:

const geometry = new THREE.BoxGeometry()
const materials = []   //材质数组
for( let i = 0; i < 6; i ++) {
  //使用TextureLoader加载每一张图片
  const texture = new THREE.TextureLoader().load( `../../images/reflection-sphere/${i+1}.jpg` );
  //根据纹理生成材质,并加入材质数组中
  materials.push( new THREE.MeshBasicMaterial({ 
    map: texture
  }));
}
//根据几何形状和材质数组生成物体
const cube = new THREE.Mesh(geometry, materials)

Эффект следующий: (красный представляет ось X, зеленый представляет ось Y, а синий представляет ось Z, сгенерированный с помощью AxesHelper )

图片替换文本

Видно, что материалы в массиве материалов будутX轴正方向、X轴负方向、Y轴正方向、Y轴负方向、Z轴正方向、Z轴负方向чтобы отобразить грани куба.

Самое простое использование текстур заключается в том, что они добавляются к материалам в виде карт (наложение текстур).Когда вы используете такие материалы для создания объектов (сетки), цвет объекта определяется текстурой. Текстурные материалы имитируют реальный мир лучше, чем чистые цвета.

Достичь панорамы 360

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

решение boxGeometry

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

В отличие от приведенного выше примера, мы действуем в два этапа:

  1. Карта внутренней поверхности. Нам просто нужноgeometryизscaleЕсли для одного из свойств задано отрицательное значение, материал будет применен к внутренней поверхности геометрии.
const geometry = new THREE.BoxGeometry(10,10,10)
geometry.scale(-1, 1, 1)  // 设置scale.x
// geometry.scale(1, -1, 1)  设置scale.y,会导致画面上下颠倒,所以通常都设置scale.x或者scale.z
// geometry.scale(1, 1, -1)  设置scale.z

const materials = []
for( let i = 0; i < 6; i ++) {
  const texture = new THREE.TextureLoader().load( `../../images/reflection-sphere/${i+1}.jpg` );
  materials.push( new THREE.MeshBasicMaterial({ 
    map: texture} 
  ));
}
  
const cube = new THREE.Mesh(geometry, materials)
cube.position.set(0, 0, 0)
  1. Поместите камеру в центр контейнера.
camera.position.set(0, 0, 0.01)
camera.lookAt(0,0,0)
图片替换文本

сцена.фоновая схема

Другим решением для достижения панорамы является использованиеTHREE.CubeTextureLoaderЗагрузите 6 изображений, затем используйте загруженную текстуру изображения как всю сцену.Sceneфон, который также может формировать 360-градусную панораму.

//准备6张图片,实现全景的图片也需要满足以下的顺序:
//X轴正方向、X轴负方向、Y轴正方向、Y轴负方向、Z轴正方向、Z轴负方向
const urls = [   
  'posx.jpg',
  'negx.jpg',
  'posy.jpg',
  'negy.jpg',
  'posz.jpg',
  'negz.jpg'
]
  
//实例化CubeTextureLoader
const loader = new THREE.CubeTextureLoader()    
  
//加载6个图像
const cubeMap = loader.setPath('../../images/reflection-sphere/').load(urls)
  
//将图像纹理作为场景的背景
scene.background = cubeMap  、
图片替换文本

Видно, что она имеет тот же эффект, что и первая схема.

Применимые сценарии двух схем: первая схема основана на BoxGeometry, которая может лучше контролировать добавление объектов в определенных координатных позициях в панораме. Она подходит для внутренних сцен, таких как 3D-просмотр, и может лучше удовлетворять потребности щелчка и выделение объектов на панораме.

Во второй схеме сложно создать объект с привязкой координат к определенному месту на панораме, поэтому она больше подходит для чисто экологической панорамы. Но пока координаты в панораме не задействованы, эта схема более свободна для манипулирования всей сценой и камерой. В нашем случае для получения панорамы будет использован второй способ.

Реализовать отражающий шар

добавить сферу

//创建球体形状
const sphereGeometry = new THREE.SphereGeometry(20, 30, 30)
//创建球体材质
const sphereMaterial = new THREE.MeshBasicMaterial({
  color: 0xff00ff
})
//生成球体
const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial)
//设置球体位置
sphere.position.set(0, 0, 0)
//将球体添加到场景中
scene.add(sphere)

image.png

Текстура для отражения

Вычисление зеркальных эффектов очень интенсивно использует ЦП и обычно использует алгоритмы трассировки лучей. существуетThree.jsВы все еще можете добиться эффекта зеркального отражения, просто сделайте фальшивое. Вы можете создатьТекстура окружения объектачтобы замаскировать зеркальное отражение и применить его к указанному объекту.

envMap

Выше мы используемcolorа такжеmapМатериал создан, здесь мы будем использовать envMap (карту окружения).envMapБуквальное значение — окружающая среда объекта.Например, если вы визуализируете объект с отражающими характеристиками, окружающая среда объекта определенно повлияет на эффект визуализации объекта.

Здесь мы назначаем текстуру панорамы envMap для имитации зеркального отражения окружающей среды.

Для достижения панорамы 360 ранее используйтеTHREE.CubeTextureLoaderЗагрузите 6 изображений, Three.js объединит эти изображения вместе, чтобы создать бесшовную текстуру. В приведенной выше панораме эта текстура используется в качестве фона сцены, а здесь мы используем эту текстуру в качестве карты окружения сферы (envMap).

//创建球体形状
const sphereGeometry = new THREE.SphereGeometry(20, 30, 30)
//将图像纹理作为球体的环境贴图(cubeMap为实现全景时用CubeTextureLoader加载的纹理)
const sphereMaterial = new THREE.MeshBasicMaterial({
  envMap: cubeMap
})

const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial)
sphere.position.set(0, 0, 0)
scene.add(sphere)

Такие моделирования могут быть указаны только отражение фона, если в сцене есть другие объекты, и не отображается в отражающей сфере.

图片替换文本

cubeCamera

Для отражения любого объекта в реальном времени можно использоватьcubeCamera.

cubeCameraпостроит содержащий 6PerspectiveCameras(перспективная камера) кубическая камера и визуализирует сцену, которую она захватывает, вWebGLCubeRenderTargetначальство.

То есть мы можем использоватьcubeCameraДелайте фотографии объектов в вашей сцене в режиме реального времени, а затем используйте эти фотографии в реальном времени для создания текстур. Используйте эти текстуры в качестве карты окружения сферы (envMap) для имитации отражений в реальном времени.

//将要创建的纹理对象,定义目标纹理的一些参数
const cubeRenderTarget = new THREE.WebGLCubeRenderTarget( 128, { 
  format: RGBFormat, 
  generateMipmaps: true,
  minFilter: LinearMipmapLinearFilter
});

//创建cubeCamera
//1:近剪切面的距离;1000:远剪切面的距离;cubeRenderTarget:将要创建的纹理对象
const cubeCamera = new THREE.CubeCamera(1, 1000, cubeRenderTarget)

cubeCamera.position.set(0, 0, 0)
scene.add(cubeCamera)

Затем используйте полученную текстуру в качестве envMap для сферы:

const sphereMaterial = new THREE.MeshBasicMaterial({
   envMap: cubeCamera.renderTarget  //cubeCamera生成的纹理作为球体的环境贴图
})
const sphereGeometry = new THREE.SphereGeometry(20, 30, 30)
const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial)
phere.position.set(0, 0, 0)
scene.add(sphere)
图片替换文本