Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Интерактивные 3D-карты своими руками / Александр Амосов (Avito)

263 views

Published on

РИТ++ 2017, Frontend Сonf
Зал Мумбаи, 5 июня, 15:00

Тезисы:
http://frontendconf.ru/2017/abstracts/2603.html

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

В своем докладе я опишу полностью процесс создания WebGL-визуализации, начиная от создания модели в трехмерном редакторе и заканчивая оптимизациями из мира компьютерных игр, что поможет вам разработать собственный интерактивный 3D-проект.

Published in: Engineering
  • Be the first to comment

  • Be the first to like this

Интерактивные 3D-карты своими руками / Александр Амосов (Avito)

  1. 1. Интерактивные 3D-карты своими руками Амосов Александр, AVITO email: s9k0@ya.ru twitter: @gc_s9k
  2. 2. История 2
  3. 3. 3
  4. 4. 4
  5. 5. 5
  6. 6. 6
  7. 7. 2D vs 3D 7
  8. 8. Почему 3D? • Это красиво 8
  9. 9. Почему 3D? • Это красиво 9
  10. 10. Почему 3D? • Это красиво • Это наглядно 10
  11. 11. Почему 3D? • Это красиво • Это наглядно • Потому что я могу 11
  12. 12. Создание модели 12
  13. 13. Создание модели • Найти моделлера (опционально) • Найти готовые модели (опционально) • Освоить 3D-редактор самому 13
  14. 14. 14
  15. 15. Blender • бесплатность • открытый код • постоянное развитие • кроссплатформенность • пользовательские скрипты на python 15
  16. 16. 16
  17. 17. SVG Blender 17
  18. 18. 18
  19. 19. 19
  20. 20. 20
  21. 21. import bpy geometry = bpy.data.meshes['place'] for obj in bpy.context.selected_objects: obj.rotation_euler.x = 0 obj.rotation_euler.y = 0 obj.data = geometry obj.location.z = 0 21
  22. 22. 22
  23. 23. Тени 23
  24. 24. 24
  25. 25. 25
  26. 26. 26
  27. 27. OpenGL 1.5 OpenGL 2.0 OpenGL 3.3 OpenGL 4.5 OpenGL ES 1.1 OpenGL ES 2.0 OpenGL ES 3.0 Vulkan WebGL 1.0 WebGL 2.0 27 WebGL Next?
  28. 28. 28
  29. 29. 29
  30. 30. 2D vs 3D [2] 30
  31. 31. 2D 31 <canvas id="canvas" width="100" height="100"></canvas> <script> (function() { const canvas = document.getElementById('canvas'); const context = canvas.getContext('2d'); context.fillStyle = 'rgba(255, 0, 0, 1)'; context.fillRect(25, 25, 50, 50); }()); </script>
  32. 32. 3D 32 <canvas id="canvas" width="100" height="100"></canvas> <script> (function() { const canvas = document.getElementById('canvas'); const gl = canvas.getContext('webgl'); // Инициализировать шейдеры // Создать программу // Создать вершинный буфер // Сохранить ссылку на буферный объект в атрибут // Вызвать отрисовку }()); </script>
  33. 33. Вершинный шейдер 33 const vertexShaderSource = ` attribute vec4 position; void main() { gl_Position = position; } `; const vertexShader = gl.createShader(gl.VERTEX_SHADER); gl.shaderSource(vertexShader, vertexShaderSource); gl.compileShader(vertexShader);
  34. 34. Фрагментный шейдер 34 const fragmentShaderSource = ` void main() { gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); } `; const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); gl.shaderSource(fragmentShader, vertexShaderSource); gl.compileShader(fragmentShader);
  35. 35. Программа 35 const program = gl.createProgram(); gl.attachShader(program, vertexShader); gl.attachShader(program, fragmentShader); gl.linkProgram(program); gl.useProgram(program);
  36. 36. Вершинный буфер 36 const vertices = new Float32Array([ -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5, -0.5 ]); const vertexSize = 2; const vertexBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW); const attrPosition = gl.getAttribLocation(program, 'position'); gl.vertexAttribPointer(attrPosition, vertexSize, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(attrPosition);
  37. 37. Отрисовка 37 const vertices = new Float32Array([ -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5, -0.5 ]); const vertexSize = 2; // … gl.drawArrays(gl.TRIANGLE_STRIP, 0, vertices.length / vertexSize);
  38. 38. 38
  39. 39. WebGL Programming Guide: Interactive 3D Graphics: Programming with WebGL Авторы: Коичи Мацуда, Роджер Ли 39
  40. 40. WebGL Framework (three.js) 40
  41. 41. WebGL Framework • Удобные абстракции • Краткий код • Никаких шейдеров (поначалу) 41
  42. 42. var scene, camera, renderer, geometry, material, mesh; init(); animate(); function init() { scene = new THREE.Scene(); camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 10000); camera.position.z = 1000; geometry = new THREE.BoxGeometry( 200, 200, 200 ); material = new THREE.MeshBasicMaterial( { color: 0xff0000, wireframe: true } ); mesh = new THREE.Mesh( geometry, material ); scene.add( mesh ); renderer = new THREE.WebGLRenderer(); renderer.setSize( window.innerWidth, window.innerHeight ); document.body.appendChild( renderer.domElement ); } function animate() { requestAnimationFrame( animate ); mesh.rotation.y += 0.02; renderer.render( scene, camera ); } 42
  43. 43. var scene, camera, renderer, geometry, material, mesh; init(); animate(); function init() { scene = new THREE.Scene(); camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 10000); camera.position.z = 1000; geometry = new THREE.BoxGeometry( 200, 200, 200 ); material = new THREE.MeshBasicMaterial( { color: 0xff0000, wireframe: true } ); mesh = new THREE.Mesh( geometry, material ); scene.add( mesh ); renderer = new THREE.WebGLRenderer(); renderer.setSize( window.innerWidth, window.innerHeight ); document.body.appendChild( renderer.domElement ); } function animate() { requestAnimationFrame( animate ); mesh.rotation.y += 0.02; renderer.render( scene, camera ); } 43
  44. 44. 44
  45. 45. 45
  46. 46. var scene, camera, renderer, geometry, material, mesh; init(); animate(); function init() { scene = new THREE.Scene(); camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 10000); camera.position.z = 1000; geometry = new THREE.BoxGeometry( 200, 200, 200 ); material = new THREE.MeshBasicMaterial( { color: 0xff0000, wireframe: true } ); mesh = new THREE.Mesh( geometry, material ); scene.add( mesh ); renderer = new THREE.WebGLRenderer(); renderer.setSize( window.innerWidth, window.innerHeight ); document.body.appendChild( renderer.domElement ); } function animate() { requestAnimationFrame( animate ); mesh.rotation.y += 0.02; renderer.render( scene, camera ); } 46
  47. 47. 47
  48. 48. var scene, camera, renderer, geometry, material, mesh; init(); animate(); function init() { scene = new THREE.Scene(); camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 10000); camera.position.z = 1000; geometry = new THREE.BoxGeometry( 200, 200, 200 ); material = new THREE.MeshBasicMaterial( { color: 0xff0000, wireframe: true } ); mesh = new THREE.Mesh( geometry, material ); scene.add( mesh ); renderer = new THREE.WebGLRenderer(); renderer.setSize( window.innerWidth, window.innerHeight ); document.body.appendChild( renderer.domElement ); } function animate() { requestAnimationFrame( animate ); mesh.rotation.y += 0.02; renderer.render( scene, camera ); } 48
  49. 49. var scene, camera, renderer, geometry, material, mesh; init(); animate(); function init() { scene = new THREE.Scene(); camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 10000); camera.position.z = 1000; geometry = new THREE.BoxGeometry( 200, 200, 200 ); material = new THREE.MeshBasicMaterial( { color: 0xff0000, wireframe: true } ); mesh = new THREE.Mesh( geometry, material ); scene.add( mesh ); renderer = new THREE.WebGLRenderer(); renderer.setSize( window.innerWidth, window.innerHeight ); document.body.appendChild( renderer.domElement ); } function animate() { requestAnimationFrame( animate ); mesh.rotation.y += 0.02; renderer.render( scene, camera ); } 49
  50. 50. var scene, camera, renderer, geometry, material, mesh; init(); animate(); function init() { scene = new THREE.Scene(); camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 10000); camera.position.z = 1000; geometry = new THREE.BoxGeometry( 200, 200, 200 ); material = new THREE.MeshBasicMaterial( { color: 0xff0000, wireframe: true } ); mesh = new THREE.Mesh( geometry, material ); scene.add( mesh ); renderer = new THREE.WebGLRenderer(); renderer.setSize( window.innerWidth, window.innerHeight ); document.body.appendChild( renderer.domElement ); } function animate() { requestAnimationFrame( animate ); mesh.rotation.y += 0.02; renderer.render( scene, camera ); } 50
  51. 51. var scene, camera, renderer, geometry, material, mesh; init(); animate(); function init() { scene = new THREE.Scene(); camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 10000); camera.position.z = 1000; var loader = new THREE.ObjectLoader(); loader.load('model.json', function(mesh) { scene.add(mesh); }); ry = renderer = new THREE.WebGLRenderer(); renderer.setSize( window.innerWidth, window.innerHeight ); document.body.appendChild( renderer.domElement ); } function animate() { requestAnimationFrame( animate ); mesh.rotation.y += 0.02; renderer.render( scene, camera ); } 51
  52. 52. SVG Blender { "metadata": { "version": 4.4, "sourceFile": "model.blend", "generator": "io_three", "type": "Object" }, "geometries": [ ... ], "materials": [ ... ], "object": { ... } } JSON io_three 52
  53. 53. Больше контроля 53
  54. 54. Больше контроля 54
  55. 55. Больше контроля 55 <script src="three/build/three.js"></script> <script src="three/examples/js/controls/OrbitControls.js"></script>
  56. 56. var scene, camera, renderer, geometry, material, mesh; init(); animate(); function init() { scene = new THREE.Scene(); camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 10000); camera.position.z = 1000; var loader = new THREE.ObjectLoader(); loader.load('model.json', function(mesh) { scene.add(mesh); }); renderer = new THREE.WebGLRenderer(); renderer.setSize( window.innerWidth, window.innerHeight ); document.body.appendChild( renderer.domElement ); } function animate() { requestAnimationFrame( animate ); mesh.rotation.y += 0.02; renderer.render( scene, camera ); } 56
  57. 57. var scene, camera, renderer, geometry, material, mesh; init(); animate(); function init() { scene = new THREE.Scene(); camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 10000); camera.position.z = 1000; new THREE.OrbitControls(camera); var loader = new THREE.ObjectLoader(); loader.load('model.json', function(mesh) { scene.add(mesh); }); renderer = new THREE.WebGLRenderer(); renderer.setSize( window.innerWidth, window.innerHeight ); document.body.appendChild( renderer.domElement ); } function animate() { requestAnimationFrame( animate ); mesh.rotation.y += 0.02; renderer.render( scene, camera ); } 57
  58. 58. 58 https://goo.gl/ell2e7
  59. 59. Interactive 3D Graphics Course With Three.js & WebGL https://www.udacity.com/course/interactive-3d-graphics--cs291 59
  60. 60. Как работает приложение 60
  61. 61. Viewer 61 • Модель с запеченными тенями • Рейкастинг объектов • Спрайты для иконок
  62. 62. UI 62 • React
  63. 63. Viewer UI Redux store 63
  64. 64. Viewer UI Redux store 64 { type: 'SELECT_FLOOR', floor: 10 }
  65. 65. Все тормозит? 65
  66. 66. 66
  67. 67. Сглаживание 67 // WebGL: const gl = canvas.getContext("webgl", { antialias: true }); // three.js: const renderer = new THREE.WebGLRenderer({ antialias: true });
  68. 68. На взлет 68 function animate() { requestAnimationFrame(animate); renderer.render(scene, camera); }
  69. 69. Не рендерить все время 69 Начало движения камеры Конец движения камеры Запуск рендеринга Остановка рендеринга Изменение состояния приложения Отрендерить один кадр
  70. 70. Raycasting 70 const raycaster = new THREE.Raycaster(); raycaster.setFromCamera(normalizedMouseCoordinates, camera); const intersects = raycaster.intersectObjects(objects);
  71. 71. Colliders 71
  72. 72. 72
  73. 73. 73 Instancing До: 365 draw calls После: 51 draw calls
  74. 74. 74 ANGLE_instanced_arrays extension
  75. 75. 75
  76. 76. 76 uniform uniform uniform uniform
  77. 77. 77 uniform uniform uniform uniform uniform
  78. 78. 78 uniform uniform uniform uniform uniform
  79. 79. 79 uniform uniform uniform uniform attribute attribute attribute attribute
  80. 80. Instancing 80 • Сильно повышает производительность
  81. 81. Instancing 81 • Сильно повышает производительность • Сложно https://goo.gl/zdaWZU
  82. 82. 82
  83. 83. Упрощение модели 83
  84. 84. Оптимизация текстур 84
  85. 85. Сжатые текстуры Плюсы: • В 4 раза меньше видеопамяти занимают Ограничения: • Разные форматы: DXT, PVRTC, ETC • Ухудшение картинки • Проблемы с прозрачностью • Больший объем файлов (но можно применить gzip) 85 https://goo.gl/swsgxR
  86. 86. Сжатые текстуры 86
  87. 87. Сжатые текстуры 87
  88. 88. 88 Сжатые текстуры
  89. 89. Не гонитесь за реализмом 89
  90. 90. You are not alone 90
  91. 91. Ссылки Курс по трехмерной графике на Udacity Книга "Программирование трехмерной графики" Примеры threejs Видео про рендеринг текста в WebGL (слайды) Видео про производительность WebGL (статья) 91
  92. 92. Спасибо! Вопросы? 92 Ссылки https://goo.gl/wt4wzp

×