This article has participated in the good article call order activity, click to see: back end, big front end double track submission, 20,000 yuan prize pool for you to challenge!


preface

The thing is that some time ago, the contractor Lao Yang came to me again, said that a big car brand wants to develop a web page exhibition hall, hope to display its new car in 360 degrees in the web page 3D model, but also can let the user DIY car parts color.

May feel after a lot of friends to see the article two weeks is quite abundant, but it’s not, as the party c nothing say, often to cooperate with party a modify repeatedly, a lot of time to change is to last the night before to launch can’t directly on a campaign site nor life cycle long, the longest is online for 1 to 3 months.

Hey hey, time is tight, budget is much!

I wanted to offer him four W’s, give him some room to negotiate,

Who knows old Yang a promise, also said to finish to ask me to XX world

I’m guessing he made at least 10 dollars from the client

Interactive topic

Let’s look at the final result. Do you think it’s worth four W’s?

The previous article, “Three front-end VR panoramic house viewing solutions! You never know when you can use it!” In threejs

Basic knowledge of 3D engines

The goal of this article is to get you up and running, and since we’re going to use the 3D engine, it’s very efficient to look at the THREejs API documentation once we understand the basics of 3D. Any 3D engine is made up of the following basic elements

Scenario (scene)

A container that holds everything in the 3D world except the renderer. The elements of the scene are in a right-handed Cartesian coordinate system, with the positive X-axis pointing to the right, the positive Y-axis pointing up, and the z-axis pointing from the inside out of the screen

The camera (camera)

Just like people’s eyes, they can look in any direction in a space, and the visual Angle and visual distance can be adjusted by parameters.

Generally speaking, we use PerspectiveCamera, which graphically represents the reality of the physical world. In other cases, OrthographicCamera can be used to PerspectiveCamera with the same distance and size

PerspectiveCamera( fov : Number.aspect : Number.near : Number.far : Number )
// Constructor arguments
//fov: field of view
//aspect: aspect ratio (canvas width/canvas height)
// Near: how close you can see
// Far: How far can you see
// These parameters determine which 3d vertices in the scene will be rendered/drawn
Copy the code

The renderer (renderer)

Render/draw on the canvas what the camera sees in the scene

Geometry (geometry)

All objects in a 3D world are points that make up surfaces, and surfaces make up geometry. I believe you are familiar with the following standard geometry

  • A sphere
  • The cube
  • cone
  • The cylinder
  • .

Surfaces are made up of points, and surfaces can form all kinds of geometry. In the case of a sphere, the more points there are on its surface, the rounder it becomes. But the more points, the more computation…

In addition, we generally say that 3d model is one or more geometry, but some 3D model files in addition to the geometry can also contain some additional information, such as maps, materials and so on… It needs to be parsed when the model file is read

Lights (light)

The 3D engine will default to an ambient light without manually creating the light, otherwise you won’t see anything. Common lights are of the following types

  • If you have an AmbientLight, it will not produce light or dark.
  • DirectionLight (parallel light, refer to daylight)

  • PointLight (refer to light bulb)

  • SpotLight (reference stage SpotLight)

Map (texture)

Imagine that you have a cube in your hand, and you wrap a piece of A4 paper around all the sides of the cube and draw pictures on it. What you draw is a texture.

There are some types of textures that react to light… We’ll talk about it later when we need it

Material (material)

Continue the imagination in the map, you draw with white card paper or with oil paper, the texture presented is different, right? This is the material! The next five balls are all the same color, and the material from left to right is

  • MeshBasicMaterial (not affected by light)
  • MeshStandardMaterial
  • MeshPhongMaterial (high gloss material, suitable for ceramic, paint texture)
  • MeshToonMaterial (cartoon material, commonly known as three shading two)
  • MeshStandardMaterial (PBR Standard material simulates metal reflection)

Let’s do it!

With these basics in mind, using Threejs is easy to get started. It can be said that 90% of the effects in 3dMax and other software, using Threejs can find the corresponding configuration parameters.

Setting up basic scenarios

//
      
var scene, camera, renderer; function init(){ scene = new THREE.Scene(); // If you don't know the parameters, go back to the camera section in the basic knowledge camera = new THREE.PerspectiveCamera(90.document.body.clientWidth / document.body.clientHeight, 0.1.100); // Camera position x0,y0,z3, remember Dilka's right hand coordinate system? 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); // Wait to add the model loop(); } function loop() { requestAnimationFrame(loop); renderer.render(scene, camera); } window.onload = init; Copy the code

Now we can try it by adding a standard geometry, like a cube

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 );
Copy the code

Obviously, the scene works… Notice the comments in the source block

The car model

So back in our project, what the brand is saying is a very detailed model, with hundreds of megabits, millions of faces.

I said it’s not working, you have to reduce the face and give me a format that the engine can support GLTF or OBj

According to my assessment, to run smoothly on a mobile web, there should be no more than 100,000 pages

Outcontractor old Yang said, you also don’t let the client to do for you, they will not

I know you do. You just do it. I’ll add 5K.

Plus 5K how am I supposed to say no…

Then I bought a model from SketchFab for a whopping $25

With a few more tweaks, sketchFab also has free models

But after all, I received 5K from Lao Yang, and I felt a little uneasy about not spending money: P

Optimized model structure

According to the actual needs, such as transparent Windows can see the interior, so the Windows have to be given a transparent property of the material. The wheels, the lampshades, the mesh, the frame, the body, and so on, have to be separated into separate geometry to be configured with materials independently.

With the model structure sorted out, it’s time to prepare the model file

Load model

There are many file formats for 3D models, but the basic ones used in Threejs are

  • OBJ format

Old general purpose 3D model file, do not contain texture, material, animation and other information.

  • GLTF format (Graphics language transmission format)

OpenGL’s official maintenance team has developed a universal format for modern 3D models that can contain geometry, textures, animations, scenes, cameras, and other information in a small file size. The JPEG of 3D models.

In the original project, I used OBJ format. In this article, we use GLTF format. Using the Editor provided by Threejs, we can convert and export the format of the model.

With GLTFLoader, we can load a. GLTF format 3D model file. It is important to note that these loaders exist in the form of plug-ins and need to introduce the corresponding xxxLoader.js to use

//<script src="js/GLTFLoader.js"></script>
// Put it where we added the cube
const loader = new THREE.GLTFLoader();

loader.load(
    'images/model.gltf'.function ( gltf ) {
        scene.add( gltf.scene );
    },
    function ( xhr ) {
        // Listen for model loading progress
        console.log( ( xhr.loaded / xhr.total * 100 ) + '% loaded' );
    },
    function ( error ) {
        // The callback for loading errors
        console.log( 'An error happened'); });Copy the code

This code allows you to iterate through the list of geometries in the model

console.log(gltf.scene.children);

// You can use for or traverse API
//gltf.scene.children.traverse((child){});
Copy the code

Maps and Materials

Now let’s add texture to the geometry. It’s the designer’s job to do it. Not much to say here, we just need to know how to use these tiles.

  • Normal texture (_col)

Material. Map, instead of color

  • Normal map (_nor)

NormalMap, which allows low-detail surfaces to generate high-detail accurate lighting directions and reflections

  • Ambient light occlusion map (_occ)

Material. AoMap, used to describe the effect of objects crossing or approaching objects to block diffuse light around them

  • Ambient reflection map

Material. EnvMap, used to simulate how materials reflect their surroundings

We will now load these map files into memory

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);
}
Copy the code

Then we manually map to each other according to the name, for example, we first add the map of the wheel hub

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; }}Copy the code

Let’s go ahead and add the wheels

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;
}
Copy the code

The rest of the material maps are added in this way. Of course, there are many details of the material that can be adjusted later, but it is a fine work. The main focus here is to share the reflection and transparency of the glass and the reflection of the metal paint

  • Clear glass

The transparency and base color of the skylight and front windshield are different

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;
}
Copy the code

Take a closer look at the difference in transparency between the front windshield and the skylight in the GIF

  • Reflection of glass

Want to really reflect the real environment? You don’t want to think too much, envMap to make a fake look very good…

child.material.envMap=allTexture["skymap"].texture;
EnvMap envMap envMap envMap envMap envMap envMap
child.material.envMap.mapping = THREE.EquirectangularReflectionMapping;
// The intensity of the ambient reflection map
child.material.envMapIntensity=1;
Copy the code

Take a closer look at the front windshield in the GIF. Is it reflecting anything? I have seen three front-end VR panoramic house viewing schemes! You never know if you can use them one day! Do you remember this picture?

  • Body paint texture

Use MeshStandardMaterial, adjust the metalness, Roughness and roughness values to adjust the metal texture

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

Information point

After all, it’s an online showroom, and you have to have a little bit of information around the car, and you can click on it and you can pop it up to show more information. The implementation is also mentioned in the VR Panorama article, which is Sprite+Raycast

// Frame is just a tag
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); }}); }Copy the code

What do the UI

Now that we’re using Threejs, should we build the UI in Threejs? Thinking that way will kill you. It’s not easy to do a 2D UI in a 3D scene, and it’s even more difficult to implement the user actions of the UI (click, drag, etc.)… So let’s just use HTML for the UI

At this point, the core of this 3D car showroom you have learned (FEI)!

conclusion

That’s just a very superficial use of Threejs, but there’s a lot more to threejs than that. I hope this article got you interested in Web3D development. If it was good, please like it

BTW: It’s a smart car. How do you call it a BMW? Because this story is purely fictitious, please do not match. All chat records in this article are forged using the wechat dialogue generator.

Check out the accompanying video tutorial

Download the source code

Wechat search and follow the public number “Big handsome old ape”, reply “Smart3D” to obtain all source code of this article