Форум программистов, компьютерный форум, киберфорум
8Observer8
Войти
Регистрация
Восстановить пароль

Управление камерой с помощью скрипта OrbitControls.js на Three.js: Вращение, зум и панорамирование

Запись от 8Observer8 размещена 05.03.2026 в 17:37. Обновил(-а) 8Observer8 05.03.2026 в 22:21
Показов 2799 Комментарии 2

Содержание блога

Финальная демка в браузере работает на Desktop и мобильных браузерах. Итоговый код: orbit-controls-threejs-js.zip. Сканируйте QR-код на мобильном. Вращайте камеру одним пальцем, перемещайте камеру двумя пальцами и делайте зум щипком.



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

Установка редактора кода и ПО для локального сервера




Пишем код по шагам



  • Создайте пустую папку, например, с именем "orbit-controls-threejs-js"
  • Откройте эту папку в редакторе кода, например, в Sublime Text 4 (ST4). Проще всего добавить ST4 в системную Path на Windows 10. Если не знаете, как добавить путь к EXE программы в Path, то спросите у ИИ, например, у Gemini: "Как добавить путь к Sublime Text 4 в Path". Тогда можно будет в CMD из созданной папки набрать:
    Bash
    1
    
    subl .
  • Создайте файл index.html и наберите "html" и нажмите Tab и будет сгенерирован код:
    PHP/HTML
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title></title>
    </head>
    <body>
     
    </body>
    </html>
  • Можете отформатировать код командой:
    Bash
    1
    
    js-beautify -n *.html -b "collapse, preserve-inline"
  • После этой команды код будет отформатирован:
    PHP/HTML
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
    <!DOCTYPE html>
    <html>
     
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title></title>
    </head>
     
    <body>
     
    </body>
     
    </html>
  • Найдём ссылки на библиотеку Three.js. Перейдите по ссылке: https://cdn.jsdelivr.net, прокрутите страницу немного вниз и наберите в поиске: three.js
  • Перейдите по первой ссылке в поиске:
  • Кликните по ссылке "Files":
  • Кликните по папке "build":
  • Найдите строку с "three.module.min.js" и эту нажмите кнопку для копирования URL:
  • Добавьте следующий код с "importmap" в "index.html" и вставьте скопированный URL:
    PHP/HTML
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    
    <!DOCTYPE html>
    <html>
     
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title></title>
    </head>
     
    <body>
        <script type="importmap">
            {
                "imports": {
                    "three": "https://cdn.jsdelivr.net/npm/three@0.183.2/build/three.module.min.js"
                }
            }
        </script>
    </body>
     
    </html>
  • Примечание. Благодаря "importmap" мы можем в файлах .js импортировать Three.js командой:
    JavaScript
    1
    
    import * as THREE from "three";
  • В файле "index.html" внутри тега <body> добавьте тег холста с id="renderCanvas":
    PHP/HTML
    1
    2
    3
    4
    5
    6
    
    <body>
        <canvas id="renderCanvas"></canvas>
     
        <!-- ... -->
     
    </body>
  • Добавьте подключение файла "./js/index.js", который мы добавим позже:
    PHP/HTML
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    
    <!DOCTYPE html>
    <html>
     
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title></title>
    </head>
     
    <body>
        <canvas id="renderCanvas"></canvas>
     
        <script type="importmap">
            {
                "imports": {
                    "three": "https://cdn.jsdelivr.net/npm/three@0.183.2/build/three.module.min.js"
                }
            }
        </script>
     
        <script type="module" src="./js/index.js"></script>
    </body>
     
    </html>
  • Создайте в папку "js", а в папке "js" создайте файл "index.js"
  • Протестируем запуск приложения. Добавьте в "index.js" строку вывода "Hello World!" в консоль браузера:
    JavaScript
    1
    
    console.log("Hello World!");
  • В консоле введите команду для запуска локального сервера:
    Bash
    1
    
    http-server -c-1
  • Будет выведен список адресов для браузера, например у меня:
    Bash
    1
    2
    3
    4
    
    Available on:
      http://192.168.1.65:8080
      http://127.0.0.1:8080
    Hit CTRL-C to stop the server
  • Если у вас телефон подключён по Wi-Fi, то введите в браузере телефона адрес: 192.168.1.65:8080
  • Перейдите в Chrome (или Edge) и нажмите "Ctrl+Shift+J" для открытия консоли браузера. Если у вас Firefox, то погуглите, как открыть консоль в Firefox
  • Введите в адресной строке браузера следующий адрес и после этого нажмите Enter:
    Bash
    1
    
    localhost:8080
  • В консоли вы увидите "Hello World!"
  • Примечание. Если вы что-то меняете в проекте и хотите перезапустить приложение в браузере, то обновляйте страницу с очисткой Cache - правой кнопкой по кнопке перезагрузки и выберите: "Empty Cache and Hard Reload"
  • Откройте файл "index.js" и добавьте следующий код, который импортирует библиотеки Three.js, создаёт три функции: main(), init(), animate(), создаёт рисовальщик (renderer), сцену (scene) и камеру (camera):
    JavaScript
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    
    import * as THREE from "three";
     
    let renderer, scene, camera;
     
    function main() {
        init();
        animate();
    }
     
    window.onload = main;
     
    function init() {
        const canvas = document.getElementById("renderCanvas");
     
        renderer = new THREE.WebGLRenderer({ antialias: true, canvas });
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.setPixelRatio(window.devicePixelRatio);
     
        scene = new THREE.Scene();
        scene.background = new THREE.Color(0x222222);
     
        camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 100);
        camera.position.set(5, 5, 10);
    }
     
    function animate() {
        requestAnimationFrame(animate);
        renderer.render(scene, camera);
    }
  • Обновите страницу браузера и вы увидите холст тёмно-серого цвета
  • Уберём полосы прокрутки со страницы и растянем холст. Для этого создайте папку "css" в корне проекта и в папке "css" добавьте файл "style.css":
    CSS
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    
    body,
    html {
        overflow: hidden;
        width: 100%;
        height: 100%;
        margin: 0;
        padding: 0;
    }
     
    #renderCanvas {
        width: 100%;
        height: 100%;
    }
  • Добавьте подключение файла "css/style.css" в файле "index.html". Для этого вы можете внутри тега <head> набрать "link" (без ковычек) и нажать Tab и написать в свойстве href="" путь к файлу "./css/style.css" следующим образом и добавьте текст "Examples" в тег <title>:
    PHP/HTML
    1
    2
    3
    4
    5
    6
    
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" type="text/css" href="./css/style.css">
        <title>Example</title>
    </head>
  • Обновите страницу браузера и теперь вы видите, что холст растянут на всю клиентскую область браузера и полос прокрутки нет. Текущий код:

    index.html

    PHP/HTML
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    
    <!DOCTYPE html>
    <html>
     
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" type="text/css" href="./css/style.css">
        <title>Example</title>
    </head>
     
    <body>
        <canvas id="renderCanvas"></canvas>
     
        <script type="importmap">
            {
                "imports": {
                    "three": "https://cdn.jsdelivr.net/npm/three@0.183.2/build/three.module.min.js"
                }
            }
        </script>
     
        <script type="module" src="./js/index.js"></script>
    </body>
     
    </html>
    js/index.js

    JavaScript
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    
    import * as THREE from "three";
     
    let renderer, scene, camera;
     
    function main() {
        init();
        animate();
    }
     
    window.onload = main;
     
    function init() {
        const canvas = document.getElementById("renderCanvas");
     
        renderer = new THREE.WebGLRenderer({ antialias: true, canvas });
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.setPixelRatio(window.devicePixelRatio);
     
        scene = new THREE.Scene();
        scene.background = new THREE.Color(0x222222);
     
        camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 100);
        camera.position.set(5, 5, 10);
    }
     
    function animate() {
        requestAnimationFrame(animate);
        renderer.render(scene, camera);
    }
    css/style.css

    CSS
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    
    body,
    html {
        overflow: hidden;
        width: 100%;
        height: 100%;
        margin: 0;
        padding: 0;
    }
     
    #renderCanvas {
        width: 100%;
        height: 100%;
    }

Добавляем библиотеку OrbitControls.js и рисование кубика средствами Three.js



  • Найдём ссылки на библиотеку OrbitControls.js. Перейдите по ссылке: https://cdn.jsdelivr.net, прокрутите страницу немного вниз и наберите в поиске: three.js
  • Перейдите по первой ссылке в поиске:
  • Кликните по ссылке "Files":
  • Кликните по папке "examples":
  • Кликните по папке "jsm":
  • Кликните по папке "controls":
  • Скопируйте URL, нажав на кнопку:
  • Откройте файл "index.html" и вставьте URL, создав новую строку подключения для OrbitControls.js:
    PHP/HTML
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    
    <!DOCTYPE html>
    <html>
     
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" type="text/css" href="./css/style.css">
        <title>Example</title>
    </head>
     
    <body>
        <canvas id="renderCanvas"></canvas>
     
        <script type="importmap">
            {
                "imports": {
                    "three": "https://cdn.jsdelivr.net/npm/three@0.183.2/build/three.module.min.js",
                    "orbit-controls": "https://cdn.jsdelivr.net/npm/three@0.183.2/examples/jsm/controls/OrbitControls.js"
                }
            }
        </script>
     
        <script type="module" src="./js/index.js"></script>
    </body>
     
    </html>
  • Откройте файл index.js и добавьте импортирование библиотеки OrbitControls.js:
    JavaScript
    1
    
    import { OrbitControls } from "orbit-controls";
  • Добавьте глобальные переменные "controls" и "cube" к уже имеющимся:
    JavaScript
    1
    
    let renderer, scene, camera, controls, cube;
  • В функции init() после создания камеры добавьте код создания "controls", передав в конструктор OrbitControls() ссылку на камеру и ссылку на <canvas>:
    JavaScript
    1
    2
    
        controls = new OrbitControls(camera, renderer.domElement);
        controls.enableDamping = true; // Smooth movement
  • Далее добавьте код создания геометрии и материала куба и добавьте куб на сцену командой scene.add(cube):
    JavaScript
    1
    2
    3
    4
    
        const geometry = new THREE.BoxGeometry(2, 2, 2);
        const material = new THREE.MeshStandardMaterial({ color: 0x00ff88 });
        cube = new THREE.Mesh(geometry, material);
        scene.add(cube);
  • Добавьте на сцену два источника света - направленный свет, как Солнце и окружающий свет:
    JavaScript
    1
    2
    3
    4
    5
    6
    
        const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
        directionalLight.position.set(5, 4, 3);
        scene.add(directionalLight);
     
        const ambientLight = new THREE.AmbientLight(0xffffff, 0.4);
        scene.add(ambientLight);
  • Добавьте команду controls.update() в функцию animate():
    JavaScript
    1
    2
    3
    4
    5
    
    function animate() {
        requestAnimationFrame(animate);
        controls.update();
        renderer.render(scene, camera);
    }
  • Добавим функцию onWindowResize(), которая должна вызываться при изменении клиентской области окна браузера, чтобы при изменении соотношения сторон клиентской области окна браузера не деформировались объекты на сцене:
    JavaScript
    1
    2
    3
    4
    5
    
    function onWindowResize() {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);
    }
  • Добавим в main() строку настройки "window.onresize = onWindowResize", чтобы функция onWindowResize() вызывалась при изменении размера клиентской области окна браузера:

    JavaScript
    1
    2
    3
    4
    5
    
    function main() {
        init();
        window.onresize = onWindowResize;
        animate();
    }
  • Получается следующий код:

    js/index.js

    JavaScript
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    
    import * as THREE from "three";
    import { OrbitControls } from "orbit-controls";
     
    let renderer, scene, camera, controls, cube;
     
    function main() {
        init();
        window.onresize = onWindowResize;
        animate();
    }
     
    window.onload = main;
     
    function init() {
        const canvas = document.getElementById("renderCanvas");
     
        renderer = new THREE.WebGLRenderer({ antialias: true, canvas });
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.setPixelRatio(window.devicePixelRatio);
     
        scene = new THREE.Scene();
        scene.background = new THREE.Color(0x222222);
     
        camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 100);
        camera.position.set(5, 5, 10);
     
        controls = new OrbitControls(camera, renderer.domElement);
        controls.enableDamping = true; // Smooth movement
     
        const geometry = new THREE.BoxGeometry(2, 2, 2);
        const material = new THREE.MeshStandardMaterial({ color: 0x00ff88 });
        cube = new THREE.Mesh(geometry, material);
        scene.add(cube);
     
        const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
        directionalLight.position.set(5, 4, 3);
        scene.add(directionalLight);
     
        const ambientLight = new THREE.AmbientLight(0xffffff, 0.4);
        scene.add(ambientLight);
    }
     
    function animate() {
        requestAnimationFrame(animate);
        controls.update();
        renderer.render(scene, camera);
    }
     
    function onWindowResize() {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);
    }
  • Скопируйте проект на бесплатный хостинг, например, на GitHub Pages и он будет доступен по ссылка, например: ссылка
  • Финальный проект: orbit-controls-threejs-js.zip

Подключение библиотек локально



Вы можете не зависеть от работы сайта https://www.jsdelivr.com/ в случае, если сайт по каким-то причинам будет недоступен. Вы можете скопировать файлы на свой хостинг, например, на GitHub Pages. Сейчас файл скачивают в кэш браузера по ссылкам:

PHP/HTML
1
2
3
4
5
6
7
8
    <script type="importmap">
        {
            "imports": {
                "three": "https://cdn.jsdelivr.net/npm/three@0.183.2/build/three.module.min.js",
                "orbit-controls": "https://cdn.jsdelivr.net/npm/three@0.183.2/examples/jsm/controls/OrbitControls.js"
            }
        }
    </script>
Вы можете у себя в корне хостинга создать папку "libs", а в ней папку "three@0.183.2" и далее уже в этой новой папке "three@0.183.2" создать две папки: "build" и "examples" и т.д. То есть вы создаёте у себя на хостинге папки, где будут храниться два файла: three.module.min.js и OrbitControls.js При этом лучше сохранить туже самую иерархию папок:

PHP/HTML
1
2
3
4
5
6
7
8
    <script type="importmap">
        {
            "imports": {
                "three": "/libs/three@0.183.2/build/three.module.min.js",
                "orbit-controls": "/libs/three@0.183.2/examples/jsm/controls/OrbitControls.js"
            }
        }
    </script>
Важно! В папку "build" помимо файла "three.module.min.js" нужно скопировать файл "three.core.min.js", который можно найти на https://www.jsdelivr.com

У вас проекте будет три файла в папке "libs". Два файла в папке "build":



И одни файл в папке "controls":



Получился такой проект с включёнными в него библиотеками: orbit-controls-threejs-js-plus-libs.zip

Когда вы вводите в консоль команду для запуска локального сервера:
Bash
1
http-server -c-1
, то выводится список адресов для браузера, например у меня:
Bash
1
2
3
4
Available on:
  http://192.168.1.65:8080
  http://127.0.0.1:8080
Hit CTRL-C to stop the server
Если у вас телефон подключён по Wi-Fi, то введите в браузере телефона адрес: 192.168.1.65:8080, чтобы протестировать управление камерой в мобильном браузере. Одним пальцев - вращение камеры. Двумя пальцами - перемещение камеры, и увеличение уменьшение - щипком.

Миниатюры

Нажмите на изображение для увеличения
Название: orbit-controls-threejs-js.gif
Просмотров: 8067
Размер:	321.8 Кб
ID:	11696
Нажмите на изображение для увеличения
Название: 85064bec-84b4-4956-8f8e-c44ff24eb498.png
Просмотров: 1665
Размер:	21.4 Кб
ID:	11697
Нажмите на изображение для увеличения
Название: 120f0383-433f-49fc-9a50-2766f48536a7.png
Просмотров: 1670
Размер:	9.6 Кб
ID:	11698
Нажмите на изображение для увеличения
Название: 72489d28-eab6-4793-beb6-392cac13637e.png
Просмотров: 1667
Размер:	14.6 Кб
ID:	11699
Нажмите на изображение для увеличения
Название: 77864069-5ba6-4111-aeeb-f9e64d42ee54.png
Просмотров: 1658
Размер:	12.2 Кб
ID:	11700
Нажмите на изображение для увеличения
Название: 3adc9175-c9d3-495f-8aaa-0095b1f8efd0.png
Просмотров: 1667
Размер:	12.5 Кб
ID:	11702
Нажмите на изображение для увеличения
Название: 82af4fee-34ef-4b94-b717-01e6feb8d932.png
Просмотров: 1660
Размер:	15.6 Кб
ID:	11703
Нажмите на изображение для увеличения
Название: 8a9b7c42-72c5-4872-864d-255fa571c7bf.png
Просмотров: 1654
Размер:	22.9 Кб
ID:	11704
Нажмите на изображение для увеличения
Название: cc585296-8298-4b66-aea1-4c62aa559efe.png
Просмотров: 1635
Размер:	21.6 Кб
ID:	11705
Нажмите на изображение для увеличения
Название: 01ca7cdb-8fad-4edd-8b8e-d0f6291a1b4d.png
Просмотров: 1642
Размер:	3.2 Кб
ID:	11707
Нажмите на изображение для увеличения
Название: 3b1431b2-b417-441e-954f-a8a4bbe37c2e.png
Просмотров: 1642
Размер:	3.1 Кб
ID:	11708
Вложения
Тип файла: zip orbit-controls-threejs-js.zip (2.1 Кб, 201 просмотров)
Тип файла: zip orbit-controls-threejs-js-plus-libs.zip (192.4 Кб, 62 просмотров)
Размещено в Без категории
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Всего комментариев 2
Комментарии
  1. Старый комментарий
    В коде была ошибка. Вместо имени функции updateProjectionMatrix() было написано updateProjectMatrix(). Недостаток JavaScript, что ошибка может сидеть в функции или условии, которое долгое время не выполняется. Такого бы не произошло на Си или C++. В данном случае я заметил ошибку, когда начал менять размер окна браузера, поэтому вызвалась функция onWindowResize().
    Запись от 8Observer8 размещена 05.03.2026 в 22:28 8Observer8 вне форума
    Обновил(-а) 8Observer8 05.03.2026 в 23:23
  2. Старый комментарий
    Простейший кастомный джойстик на чистом HTML и CSS для мобильный устройств, написанный с помощью бесплатного Gemini

    Исходники



    QR-Code для запуска в браузере на мобильном устройстве:



    Демка для Desktop-браузеров (управление: WASD или клавиши-стрелки)
    Запись от 8Observer8 размещена 06.03.2026 в 13:47 8Observer8 вне форума
    Обновил(-а) 8Observer8 06.03.2026 в 13:52
 
Новые блоги и статьи
Модель заражения группы наркоманов
alhaos 17.04.2026
Условия задачи сформулированы тут Суть: - Группа наркоманов из 10 человек. - Только один инфицирован ВИЧ. - Колются одной иглой. - Колются раз в день. - Колются последовательно через. . .
Мысли в слух. Про "навсегда".
kumehtar 16.04.2026
Подумалось тут, что наверное очень глупо использовать во всяких своих установках понятие "навсегда". Это очень сильное понятие, и я только начинаю понимать край его смысла, не смотря на то что давно. . .
My Business CRM
MaGz GoLd 16.04.2026
Всем привет, недавно возникла потребность создать CRM, для личных нужд. Собственно программа предоставляет из себя базу данных клиентов, в которой можно фиксировать звонки, стадии сделки, а также. . .
Знаешь почему 90% людей редко бывают счастливыми?
kumehtar 14.04.2026
Потому что они ждут. Ждут выходных, ждут отпуска, ждут удачного момента. . . а удачный момент так и не приходит.
Фиксация колонок в отчете СКД
Maks 14.04.2026
Фиксация колонок в СКД отчета типа Таблица. Задача: зафиксировать три левых колонки в отчете. Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка) / / . . .
Настройки VS Code
Loafer 13.04.2026
{ "cmake. configureOnOpen": false, "diffEditor. ignoreTrimWhitespace": true, "editor. guides. bracketPairs": "active", "extensions. ignoreRecommendations": true, . . .
Оптимизация кода на разграничение прав доступа к элементам формы
Maks 13.04.2026
Алгоритм из решения ниже реализован на нетиповом документе, разработанного в конфигурации КА2. Задачи, как таковой, поставлено не было, проделанное ниже исключительно моя инициатива. Было так:. . .
Контроль заполнения и очистка дат в зависимости от значения перечислений
Maks 12.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "ПланированиеПерсонала", разработанного в конфигурации КА2. Задача: реализовать контроль корректности заполнения дат назначения. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru