3D Земля с WebGL

JavaScript WebGL Canvas three.js
3D Земля с WebGL

После прочтения холстов г-на Сяосяоцяна я по прихоти научился делать трехмерную землю, которая считается WebGL. Раньше я использовал родной холст для рисования 2D-графики, но в этот раз я использовал 3D-фреймворки Three.js и stats.js, учился и практиковался, и эффект меня вполне удовлетворил... Ведь это мой первый контакт с WebGL.

Разговоры дешевы, покажи код!

Адрес исходного кода проекта GitHub:GitHub.com/fighting ха О…
Адрес демонстрации проекта:хороший бой GitHub.IO/мечта о кодировании…

В коде еще много недостатков, пожалуйста, просмотрите..

Что такое Three.js

С быстрым развитием интерфейса в последние годы производительность веб-страниц становится все более и более мощной.Браузер предоставляет интерфейс WebGL (Библиотека обработки веб-графики), который может рисовать 3D-графику, вызывая соответствующий API.Three.jsЭто еще один уровень инкапсуляции поверх основного интерфейса.Three.jsЭто самый популярный JS-движок для 3D-рендеринга веб-страниц.

Как использовать Three.js

Этап подготовки

  1. Добавить элемент холста на страницу
  <!-- 作为Three.js渲染器输出3D图形 -->
  <canvas id="webglcanvas"></canvas>
  1. Импорт файла библиотеки Three.js
  • местный импорт
  <!-- Three.js库 -->
  <script src="./libs/three.min.js"></script>
  • Удаленный импорт CDN
  <script src='http://cdnjs.cloudflare.com/ajax/libs/three.js/r70/three.min.js'></script>
  1. Переменные, используемые в проекте
let canvas,  //画布标签
  stats,     //性能检测器
  camera,    //相机
  scene,     //场景
  renderer,  //渲染器
  group,     //物体组
  mouseX = 0,  //鼠标横向位置
  mouseY = 0,  //鼠标纵向位置
  windowHalfX = window.innerWidth / 2,  //视口大小的一般
  windowHalfY = window.innerHeight / 2; //视口大小的一半

Создать материал сцены

Для отображения three.js нужны три вещи: сцена, камера и рендерер.

  1. Сцену можно понимать как сцену. Потому что для рисования 3D-эффекта должна быть сцена для демонстрации эффекта.
    API создания сцены:THREE.Scene()
scene = new THREE.Scene() //创建场景
  1. Со сценой теперь нужна камера для съемки материала, поэтому вторым шагом является создание «камеры».
    Создать API камеры:THREE.PerspectiveCamera(fov, aspect, near, far)
    • fov Угол обзора, который можно понимать как поле зрения, представляет собой диапазон сцены, видимой на мониторе, в градусах.
    • аспект - это ширина/высота, обычно устанавливаемая на соотношение сторон элемента холста.
    • NEAR ближнее конечное расстояние
    • дальнее расстояние
    • Только расстояние от камеры больше, чем ближнее значение, меньше, чем дальнее значение, и в пределах угла обзора камеры оно может проецироваться камерой.
camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 2000)
camera.position.z = 500  //相机的远近
  1. Сцена и камера имеются, то есть материал можно снимать, но материал должен пройти через какой-то ПС, красоту и т.д., чтобы стать красивым. Здесь нужен рендер.
    Создайте API рендерера:THREE.WebGLRenderer({})
renderer = new THREE.WebGLRenderer({
    canvas: canvas,
    antialias: true, // true/false表示是否开启反锯齿,
    /*
    alpha: false,              // true/false 表示是否可以设置背景色透明,
    precision: 'highp',        // highp/mediump/lowp 表示着色精度选择,
    premultipliedAlpha: false, // true/false 表示是否可以设置像素深度(用来度量图像的分辨率),
    maxLights: 3,              // 最大灯光数,
    stencil: false             // false/true 表示是否使用模板字体或图案
    */
  })

Укажите ширину и высоту рендерера API:renderer.setSize(window.innerWidth, window.innerHeight)Параметры ширина и высота соответственно

Создать 3D графику

Мы сняли камерой сцену из материала, но только после того, как все эти элементы в 2D, теперь мы хотим, чтобы материал из 2D стал 3D, тогда для этого требуется 3D-графика с 2D-материалом в качестве носителя. С простым пониманием продовольственных товаров, то есть за пределами куриного рулона, 2D-плоскость начала катиться, курица катиться по поверхности, рулон, завернутый в игровую курицу, затем становится куриным рулетом 3D из 2D-ролла справа. эммм... хорошо стесняюсь объяснить.
API:

  • графическая формаTHREE.SphereGeometry(radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength)
    • радиус: радиус сферы
    • widthSegments, heightSegments: количество сегментов в горизонтальном и вертикальном направлениях. Минимальное значение widthSegments равно 3, а значение по умолчанию — 8. Минимальное значение heightSegments равно 2, а значение по умолчанию — 6.
    • phiStart: начальный угол в горизонтальном направлении, значение по умолчанию 0
    • phiLenght: радианы, покрываемые поверхностью сферы в горизонтальном направлении, по умолчанию Math.PI * 2
    • thetaStart: начальный угол в вертикальном направлении, по умолчанию 0
    • thetaLength: Вертикальное направление — это радиан, покрываемый поверхностью сферы, значение по умолчанию — Math.PI.
  • Графический материалTHREE.MeshBasicMaterial({})
    Есть много видов графических материалов, я проверил информацию в Интернете, и я думаю, что это резюме очень хорошее, вы можете посмотреть.blog.CSDN.net/QQ_30100043…
  • Графическая композицияTHREE.Mesh(geometry, material)
    • форма объекта геометрии
    • материальный объект материал
let geometry = new THREE.SphereGeometry(200, 20, 20)  //形状
let material = new THREE.MeshBasicMaterial({ map: texture })  //材质
let mesh = new THREE.Mesh(geometry, material)  //物体
  • загрузить графикуnew THREE.TextureLoader().load(img, callback)
    Загрузите график выше
loader.load('./img/land_ocean_ice_cloud_2048.jpg', function (texture) {
    let geometry = new THREE.SphereGeometry(200, 20, 20)  //形状
    let material = new THREE.MeshBasicMaterial({ map: texture })  //材质
    let mesh = new THREE.Mesh(geometry, material)  //物体
})

Создать портфолио

У нас есть 3D-графика, следующим шагом будет объединение этой графики в различные 3D-интерфейсы.
Создайте составной API:THREE.Group()

//创建一个组合
group = new THREE.Group()
scene.add(group)  //将组合添加进场景中渲染

Добавьте созданную 3D-графику в композицию

API:group.add(mesh)

  • сетка 3D-объектов

пошевеливайся

3D-графика была визуализирована в сцене, теперь пришло время ее анимировать!

function animate() {
  // 请求运动帧
  requestAnimationFrame(animate)
  render()
}

// 地球旋转逻辑函数
function render() {
  // 更新性能监视器
  stats.update();
  camera.position.x += (mouseX - camera.position.x) * 0.05
  camera.position.y += (mouseX - camera.position.y) * 0.05
  // 拍摄角度, 可改变地球视角
  camera.lookAt(scene.position)
  // 地球自转速度
  group.rotation.y -= 0.005
  // 运动核心 递归调用
  renderer.render(scene, camera)
}

Вращение трехмерной Земли в основном завершено.

что такое stats.js

Говоря о Three.js, давайте поговорим о том, что такое stats.js. stats.js — это вспомогательная библиотека, разработанная Three.js для проверки производительности кода WebGL путем определения количества кадров во время выполнения анимации.

СТАТИСТИКА.JS

Этап подготовки

Подобно Three.js, stats.js также необходимо импортировать библиотеку фреймворка и использовать div для рендеринга и отображения интерфейса теста производительности.

<!-- 用于显示和统计图形的性能 -->
<div id="stats-output"></div>
<!-- 引入stats.js库 -->
<script src="./libs/stats.min.js"></script>

начать использовать

Сначала вам нужно инициализировать статистику

// stats性能检测器初始化
stats = initStats();

function initStats() {
  stats = new Stats();
  //设置统计模式
  stats.setMode(0); // 0: fps, 1: ms
  //统计信息显示在左上角
  stats.domElement.style.position = 'absolute';
  stats.domElement.style.left = '10px';
  stats.domElement.style.top = '10px';
  //将统计对象添加到对应的<div>元素中
  document.getElementById("stats-output").appendChild(stats.domElement);
  return stats;
}

При смене сцены, то есть 3D движении, детектор статистики нужно обновлять в реальном времени API:stats.update();Используется для динамического обновления обнаружений при вращении Земли.

// 地球旋转逻辑函数
function render() {
  // 更新性能监视器
  stats.update();
  
  camera.position.x += (mouseX - camera.position.x) * 0.05
  camera.position.y += (mouseX - camera.position.y) * 0.05
  // 拍摄角度, 可改变地球视角
  camera.lookAt(scene.position)
  // 地球自转速度
  group.rotation.y -= 0.005
  // 核心 递归调用
  renderer.render(scene, camera)
}

Можно увидеть два случая обнаружения stats.setMode(0);// 0: кадров в секунду, 1: мс
Параметр 0 показывает FPS

stats.setMode(1); // 0: fps, 1: ms
Параметр 1 показывает MS

окончательная оптимизация

1. Угол земли можно контролировать с помощью мыши

// 绑定鼠标移动事件
document.addEventListener('mousemove', onDocumentMouseMove, false)

// 监听鼠标移动方向, 从而确定地球南北半球
function onDocumentMouseMove(ev) {
  ev = ev || event
  mouseX = ev.clientX - windowHalfX
  mouseY = ev.clientY - windowHalfY
}

2. Отзывчивый

Автоматически изменять размер визуализируемой графики в соответствии с размером окна.

// 窗口大小改变监听
window.addEventListener('resize', onWindowResize, false)

// 监听窗口大小, 从而根据窗口大小改变地球大小, 类似响应式
function onWindowResize() {
  windowHalfX = window.innerWidth / 2
  windowHalfY = window.innerHeight / 2
  camera.aspect = window.innerWidth / window.innerHeight
  camera.updateProjectionMatrix()
  renderer.setSize(window.innerWidth, window.innerHeight)
}

Что ж, теперь трехмерная Земля практически завершена~
полный код

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>WebGL之3D地球</title>
  <style>
    /* 禁止系统默认滚动条 */
    html,
    body {
      height: 100%;
      overflow: hidden;
    }
  </style>
</head>

<body>
  <!-- 用于显示和统计图形的性能 -->
  <div id="stats-output"></div>

  <!-- 作为Three.js渲染器输出3D图形 -->
  <canvas id="webglcanvas"></canvas>

  <!-- webgl库 -->
  <script src="./libs/three.min.js"></script>
  <script src="./libs/stats.min.js"></script>
  <script>
    let canvas,  //画布标签  绘图API
      stats,     //性能检测器
      camera,    //相机
      scene,     //场景
      renderer,  //渲染器
      group,     //物体组
      mouseX = 0,  //鼠标横向位置
      mouseY = 0,  //鼠标纵向位置
      windowHalfX = window.innerWidth / 2,  //视口大小的一般
      windowHalfY = window.innerHeight / 2; //视口大小的一半

    init()  //构建地球
    animate()  //使地球旋转起来

    function init() {
      // 获取canvas画布
      canvas = document.getElementById('webglcanvas')
      // stats性能检测器初始化
      stats = initStats();

      // 3D绘制
      // 相机
      camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 2000)
      camera.position.z = 500  //相机的远近

      // 场景
      scene = new THREE.Scene()

      // 创建一个组合
      group = new THREE.Group()
      scene.add(group)  //将组合添加进场景中渲染

      // 地球 数学形状 贴图
      let loader = new THREE.TextureLoader()
      loader.load('./img/land_ocean_ice_cloud_2048.jpg', function (texture) {
        // console.log(texture)
        let geometry = new THREE.SphereGeometry(200, 20, 20)  //形状
        let material = new THREE.MeshBasicMaterial({ map: texture })  //材质
        let mesh = new THREE.Mesh(geometry, material)  //物体
        group.add(mesh)
      })

      // 渲染器
      renderer = new THREE.WebGLRenderer({
        canvas: canvas,
        antialias: true, // true/false表示是否开启反锯齿,
        /*
        alpha: false,              // true/false 表示是否可以设置背景色透明,
        precision: 'highp',        // highp/mediump/lowp 表示着色精度选择,
        premultipliedAlpha: false, // true/false 表示是否可以设置像素深度(用来度量图像的分辨率),
        maxLights: 3,              // 最大灯光数,
        stencil: false             // false/true 表示是否使用模板字体或图案
        */
      })
      // 指定渲染器宽高
      renderer.setSize(window.innerWidth, window.innerHeight)

      // 绑定鼠标移动事件
      document.addEventListener('mousemove', onDocumentMouseMove, false)

      // 窗口大小改变监听
      window.addEventListener('resize', onWindowResize, false)
    }

    // 监听鼠标移动方向, 从而确定地球南北半球
    function onDocumentMouseMove(ev) {
      ev = ev || event
      mouseX = ev.clientX - windowHalfX
      mouseY = ev.clientY - windowHalfY
    }

    // 监听窗口大小, 从而根据窗口大小改变地球大小, 类似响应式
    function onWindowResize() {
      windowHalfX = window.innerWidth / 2
      windowHalfY = window.innerHeight / 2
      camera.aspect = window.innerWidth / window.innerHeight
      camera.updateProjectionMatrix()
      renderer.setSize(window.innerWidth, window.innerHeight)
    }

    function animate() {
      // 请求运动帧
      requestAnimationFrame(animate)
      render()
    }

    // 地球旋转逻辑函数
    function render() {
      // 更新性能监视器
      stats.update();
      camera.position.x += (mouseX - camera.position.x) * 0.05
      camera.position.y += (mouseX - camera.position.y) * 0.05
      // 拍摄角度, 可改变地球视角
      camera.lookAt(scene.position)
      // 地球自转速度
      group.rotation.y -= 0.005
      // 核心 递归调用
      renderer.render(scene, camera)
    }

    function initStats() {
      stats = new Stats();
      //设置统计模式
      stats.setMode(0); // 0: fps, 1: ms
      //统计信息显示在左上角
      stats.domElement.style.position = 'absolute';
      stats.domElement.style.left = '10px';
      stats.domElement.style.top = '10px';
      //将统计对象添加到对应的<div>元素中
      document.getElementById("stats-output").appendChild(stats.domElement);
      return stats;
    }

    // ecchat 数据可视化
    // 平面的世界是错误的, css  perspective:1000px  transform-style:perserve-3d
    // Camera Scene render(渲染容器) Light  ->  canvas
  </script>
</body>

</html>

Материал с изображениями и библиотеку js можно скачать с моего github:
GitHub.com/fighting ха О…

Это первый раз, когда я публикую статью о Наггетс, надеюсь, она всем понравится, ха-ха~