Заработайте 4 Вт за 2 дня и научитесь создавать автомобильный салон Web3D с помощью Threejs!

внешний интерфейс JavaScript HTML
Заработайте 4 Вт за 2 дня и научитесь создавать автомобильный салон Web3D с помощью Threejs!

Эта статья участвовала в приказе о созыве Haowen, нажмите, чтобы просмотреть:Двойные заявки на внутреннюю и внешнюю стороны, призовой фонд в 20 000 юаней ждет вас, чтобы бросить вызов!


предисловие

Вот в чем дело, некоторое время назад外包工头Лао Ян снова подошел ко мне и сказал, что крупный автомобильный бренд собирается создать веб-салон, надеясь показать 3D-модель своего нового автомобиля на 360 градусов на веб-странице, а также позволить пользователям самостоятельно выбирать цвет автозапчастей. .

image.png

Многие мои знакомые подумают после прочтения этой статьи, что две недели вполне обильные, но это не так, так как нет права говорить партию С, часто с партией неоднократно пересматривали много раз, чтобы изменить изменить последнюю строку накануне вечером, не затягивая прямым путем, жизненный цикл рекламного сайта не долгий, на кону будет до 1-3 месяцев.

Эй, времени мало, а бюджет большой!

Я подумал предложить четыре W и оставить ему место для торга.

Кто знал, что Лао Ян согласился с одним словом и попросил меня отправиться в мир ХХ после того, как он закончит свои дела.

Я предполагаю, что он собирается сделать не менее 10 Вт от клиента

image.png

Интерактивная тема

Сначала посмотрите на окончательный эффект, как вы думаете, стоит ли он четырех W?

BMW在线展厅

То есть предыдущая статья«Три передовых решения для панорамного просмотра VR! Однажды это может пригодиться! 》упоминается вthreejsдостигать

Базовые знания 3D-движков

Цель этой статьи - позволить всем начать использовать ее сразу после прочтения.Поскольку мы собираемся использовать 3D-движок, мы получим некоторые базовые знания о 3D, прежде чем читатьthreejsЭффективность документирования API будет очень высокой. Какой бы ни был 3д движок, он состоит из следующих основных элементов

Сцены(scene)

Контейнер, который содержит все в трехмерном мире, кроме средства визуализации. Элементы сцены используют правостороннюю декартову систему координат, положительная ось x направлена ​​вправо, положительная ось y направлена ​​вверх, а ось z направлена ​​изнутри наружу экрана.

image.png

камера (camera)

Как и человеческие глаза, вы можете смотреть в любом направлении в пространстве, и вы можете настроить угол обзора и расстояние просмотра с помощью параметров.

Как правило, мы используем перспективную камеру, которая соответствует реальной ситуации в физическом мире.PerspectiveCamera, а в некоторых особых случаях требуется одинаковый размер в дальнем и ближнем плане, тогда используйте орфографическую камеруOrthographicCamera

PerspectiveCamera( fov : Number, aspect : Number, near : Number, far : Number )
//构造函数参数
//fov:视场角
//aspect:视场宽高比(一般用 画布宽/画布 高即可)
//near:能看多近
//far:能看多远
//这几个参数决定了哪些scene里的三维顶点会被渲染/绘制出来

image.png

Рендерер(renderer)

БудуcameraсуществуетsceneВизуализируйте/нарисуйте то, что вы видите на холсте, на холст

геометрия (geometry)

Все объекты в трехмерном мире点组成面,面组成几何体. Я полагаю, вы знакомы со следующей стандартной геометрией

  • сфера
  • куб
  • Конус
  • цилиндр
  • ...

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

image.png

Кроме того, мы обычно говорим3d模型Это одна или несколько геометрий, но некоторые файлы 3D-моделей могут содержать некоторую дополнительную информацию в дополнение к геометрии, такую ​​как текстуры, материалы и т. д. Ее необходимо анализировать при чтении файла модели.

свет(light)

3D-движок будет иметь освещение по умолчанию без создания источника света вручную.环境光, иначе ничего не увидишь. Распространенные типы огней следующие

  • AmbientLight (окружающий свет, глобальное освещение без направления, без затенения)
  • DirectionLight (параллельный свет, для понимания обратитесь к солнечному свету)

image.png

  • PointLight (точечный источник света, для понимания обратитесь к лампочке)

image.png

  • SpotLight (прожектор, эталон Stage Spotlight)

image.png

карта (texture)

Представьте, что у вас в руке куб, вы оборачиваете его со всех сторон листом бумаги формата А4 и рисуете на нем. то, что ты рисуешь贴图.

image.png

Есть несколько типов карт и иллюминации, а потом мы это используем

Материал (material)

Продолжая воображение на карте, используете ли вы белый картон или масляную бумагу для рисования, представленная текстура отличается, верно?材质! Пять шаров ниже имеют одинаковый цвет, а материалы слева направо

  • MeshBasicMaterial (базовый материал, на который не влияет освещение)
  • MeshStandardMaterial (стандартный материал PBR)
  • MeshPhongMaterial (глянцевый материал, подходит для керамики, текстура краски)
  • MeshToonMaterial (мультяшный материал, широко известный как три рендеринга два)
  • MeshStandardMaterial (стандартный материал PBR имитирует металлические отражения)

image.png

Давай сражаться!

С этими основами легко начать работу с threejs. Можно сказать, что 90% эффектов, передаваемых в программном обеспечении, таком как 3dmax, можно найти с соответствующими параметрами конфигурации threejs.

Создайте базовую сцену

//<div id='container' style="width:100%;height: 100%;"></div>
var scene, camera, renderer;

function init(){
    scene = new THREE.Scene();
    //这里参数不懂的同学回去看基本知识里的camera部分
    camera = new THREE.PerspectiveCamera(90, document.body.clientWidth / document.body.clientHeight, 0.1, 100);
    //camera的位置在x0,y0,z3,还记得迪尔卡右手坐标系吗?
    camera.position.set(0, 0, 3);
    
    renderer = new THREE.WebGLRenderer();
    renderer.setSize(document.body.clientWidth, document.body.clientHeight);
    document.getElementById("container").appendChild(renderer.domElement);
    
    var controls = new THREE.OrbitControls(camera, renderer.domElement);

    //等待添加模型

    loop();
}

function loop() {
    requestAnimationFrame(loop);
    renderer.render(scene, camera);
}

window.onload = init;

Теперь мы можем добавить стандартную геометрию, чтобы попробовать, например, мы добавим куб, чтобы попробовать.

const geometry = new THREE.BoxGeometry( 1, 1, 1 );
const material = new THREE.MeshBasicMaterial( {color: 0x00ff00} );
const cube = new THREE.Mesh( geometry, material );
scene.add( cube );

2021-06-28 14_14_45.gif

Очевидно, сцена в действии... всем обратить внимание на блок исходного кода注释

Модель автомобиля

Возвращаясь к нашему проекту, сторона бренда предоставила очень подробную модель с сотнями мегабайт файлов и миллионами лиц (triangles).

Snipaste_2021-07-01_11-02-49.jpg

Я сказал, что это недоступно, вы должны减面Мне нужно преобразовать его в формат, который может поддерживать движок.gltfилиobj

По моим оценкам, для бесперебойной работы на мобильных веб-страницах он не должен превышать 100 000 страниц.

Мастер-аутсорсер Лао Ян сказал: «Не позволяйте клиентам делать это за вас, они не будут этого делать».

Я знаю, ты понимаешь, ты можешь просто сделать это, я добавлю тебе [5K]

К тому же 5 тысяч ты заставляешь меня так смущаться, чтобы отказаться...

image.png

Затем я трачу25美刀огромные суммы денегsketchfabкупил модель на

Небольшая модификация может удовлетворить требования, конечно, у sketchfab есть и бесплатные модели.

Но, в конце концов, я получил 5 тысяч Лао Янга и немного переживаю из-за того, что не трачу деньги.不安На: р

Оптимизированная структура модели

image.png

В соответствии с фактическими потребностями, такими как车窗要透明可以看到内饰, поэтому окну нужно отдельно придать материал с прозрачными свойствами. Колеса, плафоны, автомобильные сетки, рамы, кузов и т. д. должны быть разобраны на независимые几何体можно настроить самостоятельно材质.

image.png

Разобравшись со структурой модели, нам нужно подготовить файл модели

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

Существует множество форматов файлов для 3D-моделей, ноthreejsНаиболее часто используются

  • формат OBJ

Старый файл 3d-модели общего назначения не содержит такой информации, как текстуры, материалы, анимация и т. д.

  • Формат GLTF (формат передачи графического языка)

Распространенный формат современных 3D-моделей, запущенный официальной командой поддержки OpenGL, который может содержать такую ​​информацию, как геометрия, материал, анимация, сцена, камера и т. д., а размер файла по-прежнему невелик. Он известен как JPEG индустрии 3D-моделей.

В исходном проекте я использовал формат OBJ, в этой статье мы используем формат GLTF. Используйте предоставленные threejseditor, мы можем преобразовать формат модели и экспортировать ее.

image.png

С помощью GLTFLoader мы можем загрузить.gltfОтформатируйте файл 3D-модели. Следует отметить, что эти загрузчики существуют в виде плагинов, и соответствующиеXXXLoader.jsиспользовать

//<script src="js/GLTFLoader.js"></script>
//放到之前添加立方体的代码处
const loader = new THREE.GLTFLoader();

loader.load(
    'images/model.gltf',
    function ( gltf ) {
        scene.add( gltf.scene );
    },
    function ( xhr ) {
        //侦听模型加载进度
        console.log( ( xhr.loaded / xhr.total * 100 ) + '% loaded' );
    },
    function ( error ) {
        //加载出错时的回调
        console.log( 'An error happened' );
    }
);

2021-07-01 14_22_13.gif

С помощью этого кода вы можете перемещаться и просматривать список геометрии в модели.

console.log(gltf.scene.children);

//可以用for,也可以用traverse api
//gltf.scene.children.traverse((child){});

Текстуры и материалы

Теперь добавим текстуры в геометрию, как делать текстуры - это профессия дизайнера. Здесь особо нечего сказать, нам просто нужно знать, как использовать эти текстуры.

image.png

  • Нормальная текстура (_col)

material.map, альтернативные цвета

  • нормальная карта (_nor)

material.normalMap, который позволяет поверхностям с низкой детализацией генерировать точные направления освещения и отражения с высокой детализацией.

  • Карта окружающего затенения (_occ)

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

  • Карта отражения окружающей среды

material.envMap, который имитирует эффект материала, отражающего окружающую среду.

Теперь мы равномерно загружаем эти файлы текстур в память.

var allTexture;
function loadAllTexture(cb){
    allTexture = {};

    var loadIndex = 0;
    var textures = [
        "skymap",
        "shache_occ",
        "shache_nor",
        "shache_col",
        "neishi_occ",
        "neishi_nor",
        "mennei_col",
        "luntai_nor",
        "luntai_col",
        "lungu_occ",
        "lungu_nor",
        "lungu_col",
        "linjian_occ",
        "linjian_nor",
        "linjian_col",
        "floor",
        "deng_occ",
        "deng_nor",
        "deng_col",
        "cheshen_occ",
        "cheshen_nor",
        "chejia_occ",
        "chejia_nor",
        "chedengzhao_nor"
    ];

    function loadNextTexture(){
        var textureName = textures[loadIndex];
        loadTexture("images/textures/"+textureName+".jpg",function(texture){
            if(loadIndex<textures.length-1){
                allTexture[textureName] = {
                    texture:texture
                };

                loadIndex++;
                loadNextTexture();
            }else{
                if(cb)cb();
            }
        });
    }
    loadNextTexture();
}
function loadTexture(filepath,cb){
    const textureLoader = new THREE.TextureLoader();
    textureLoader.load(filepath,cb);
}

Потом вручную соответствуем по названию, например сначала добавляем текстуру ступицы колеса

image.png

for(var i=0;i<gltf.scene.children[0].children.length;i++){
    var modelObj = gltf.scene.children[0].children[i];

    if(modelObj.name=="smart_lungu0"||modelObj.name=="smart_lungu1"||modelObj.name=="smart_lungu2"||modelObj.name=="smart_lungu3"){
        modelObj.material = new THREE.MeshStandardMaterial();
        modelObj.material.map = allTexture["lungu_col"].texture;
        modelObj.material.normalMap = allTexture["lungu_nor"].texture;
        modelObj.material.aoMap = allTexture["lungu_occ"].texture;
    }
}

Продолжаем добавлять текстуру колеса

image.png

else if(modelObj.name=="smart_chelun0"||modelObj.name=="smart_chelun1"||modelObj.name=="smart_chelun2"||modelObj.name=="smart_chelun3"){
    modelObj.material = new THREE.MeshStandardMaterial();
    modelObj.material.map = allTexture["luntai_col"].texture;
    modelObj.material.normalMap = allTexture["luntai_nor"].texture;
}

Таким образом добавляются остальные карты материала.Конечно, есть много деталей материала, которые можно будет скорректировать в будущем, но это тонкая работа, и основной упор здесь делается на то, чтобы поделиться.玻璃的反射和透明,金属漆的反光

  • Чистое стекло

Прозрачность и основной цвет люка и лобового стекла отличаются

else if(child.name=="smart_boli"){
    child.material=new THREE.MeshPhongMaterial();
    child.material.color = new THREE.Color( 0x333333 );
    child.material.transparent=true;
    child.material.opacity=.2;
}else if(child.name=="smart_tianchuang"){
    child.material=new THREE.MeshPhongMaterial();
    child.material.color = new THREE.Color( 0x000 );
    child.material.transparent=true;
    child.material.opacity=.5;
}

Присмотритесь к разнице в прозрачности лобового стекла и люка в анимации

2021-07-02 09_50_58.gif

  • отражение стекла

Хотите действительно отразить реальную окружающую среду? Не думайте об этом слишком много, используйте envMap, чтобы создать фальшивый вид, и это сработает...

child.material.envMap=allTexture["skymap"].texture;
//环境反射贴图envMap的映射方式,这里用的是一个叫等量矩形投影的映射方法
child.material.envMap.mapping = THREE.EquirectangularReflectionMapping;
//环境反射贴图的强度
child.material.envMapIntensity=1;

2021-07-02 10_02_08.gif

Посмотрите внимательно на лобовое стекло на анимации, оно что-то отражает? Видимый«Три передовых решения для панорамного просмотра VR! Однажды это может пригодиться! 》Ребята, вы помните эту картинку?

  • Текстура краски для тела

использоватьMeshStandardMaterialматериал, регулируяmetalness,roughnessзначение для настройки текстуры металла

child.material = new THREE.MeshStandardMaterial();
                    
child.material.color=new THREE.Color(0x70631B);
child.material.metalness = 0.44;
child.material.roughness = 0;

image.png

Информационный пункт

В конце концов, это онлайн-шоурум, и некоторые информационные точки должны быть представлены вокруг кузова автомобиля, после нажатия во всплывающем окне может отображаться дополнительная информация, верно? Способ реализации также упоминается в статье про VR панораму, т.е.Sprite+Raycast

2021-07-02 11_01_36.gif

//frame只是一个标记,叫什么都行
var poiPosArray=[
    {x:-1.47,y:0.87,z:-0.36,frame:1},
    {x:-1.46,y:0.49,z:-0.69,frame:2},
    {x:1.5,y:.7,z:0,frame:8},
    {x:0.33,y:1.79,z:0,frame:3},
    {x:0,y:0.23,z:0.96,frame:4},
    {x:0.73,y:1.38,z:-0.8,frame:5},
    {x:-.1,y:1.17,z:0.88,frame:6},
    {x:-1.16,y:0.16,z:0.89,frame:7}
],poiObjects=[];
function setupInfoPoint(){
    const pointTexture = new THREE.TextureLoader().load("images/point.png");

    var group = new THREE.Group();
    var materialC = new THREE.SpriteMaterial( { map: pointTexture, color: 0xffffff, fog: false } );
    for ( var a = 0; a < poiPosArray.length; a ++ ) {
        var x = poiPosArray[a].x;
        var y = poiPosArray[a].y-.5;
        var z = poiPosArray[a].z;

        var sprite = new THREE.Sprite( materialC );
        sprite.scale.set( .15, .15, 1 );
        sprite.position.set( x, y, z );
        sprite.idstr="popup_"+poiPosArray[a].frame;
        group.add( sprite );

        poiObjects.push(sprite);
    }
    scene.add( group );

    document.body.addEventListener("click",function (event) {
        event.preventDefault();

        var raycaster = new THREE.Raycaster();
        var mouse = new THREE.Vector2();
        mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
        mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;

        raycaster.setFromCamera( mouse, camera );

        var intersects = raycaster.intersectObjects( poiObjects );
        if(intersects.length>0){
            var popIndex=parseInt(intersects[ 0 ].object.idstr.substr(6,1));
            console.log(popIndex);
        }
    });
}

Как сделать интерфейс

image.png

Поскольку мы использовалиthreejs, так что мы собираемсяthreejsВы сделали интерфейс? Если вы так думаете, вы будете истощены. Вы должны знать, что сделать двухмерный пользовательский интерфейс в трехмерной сцене — непростая задача, и еще труднее реализовать некоторые действия пользователя (щелчок, перетаскивание и т. д.) пользовательского интерфейса... Поэтому мы напрямую используемhtmlПросто сделайте пользовательский интерфейс~

2021-07-02 11_20_56.gif

Здесь вы узнали (fei) основную часть этого 3D-автосалона!

Эпилог

Вышеупомянутое простоthreejsОдиночень мелкоиспользование,threejsКлассных эффектов, которых можно добиться, гораздо больше. Я надеюсь, что эта статья поможет вам заинтересоваться разработкой Web3D. Если вы считаете, что эта статья неплохая, пожалуйста, поставьте лайк, соберите и подпишитесь~

BTW: Очевидно,笨驰Умный, как вы говорите BMW? Поскольку эта история является чисто вымышленной, пожалуйста, не занимайте свое место. Все записи чата в этой статье используютсяГенератор разговоров WeChatподделка.

Посмотрите видеоинструкцию, сопровождающую эту статью

Если вам нравятся уроки Дашуая, добавьте в закладки, лайкните и подпишитесь

  • Билибили:大帅老猿
  • Публичный аккаунт WeChat:大帅老猿