Introduction of WebGL 3.js Learning Notes Normal Vector Mesh Material and Method of Creating 360 Degree Panoramic Skybox

WebGL Learning - Three.js Learning Notes (5)

Click to view demo demonstration

Demo address: https://nsytsqdtn.github.io/d...

Simple Mesh Normal Material

Mesh Normal Material is a material that is not affected by the color used in rendering. It is only related to the normal vector from inside to outside of each side of itself. Normal vectors are widely used in webgl. The reflection of light and texture mapping of three-dimensional graphics are related to this.

As can be seen from the graph, each side of the mesh is rendered in different colors. If we want to add normal vectors to the surface of the object, we can use THREE.ArrowHelper to represent each normal vector, whose parameters are

THREE.ArrowHelper(dir, origin, length, color, headLength, headWidth)

** The meaning of the parameters is as follows:
dir: Direction, default normal vector
origin: The starting coordinate position
Length: the length of the auxiliary line
Color: the color of the auxiliary line
headLength: Head Length
headWidth: Head Width**

For a sphere, to describe the normal vector of each surface, we first need to traverse every surface of the sphere, extract the three vertices of the surface (because the surface of webgl is triangle, so it is three vertices). By calculating the center position of the sphere through the divideScalar(3) function, we can derive an ArrowHelper from inside out at the center point. To simulate normal vectors.

 for(let i=0;i<sphereGeometry.faces.length;i++){//Cycle on each surface
            let face = sphereGeometry.faces[i];//Get the object for each face
            let centroid = new THREE.Vector3();
            //First create a vector3 object to use to find the center of each face
            centroid.add(sphereGeometry.vertices[face.a]);
             // Pass the index of the three vertices on this surface to sphereGeometry.vertices to find the coordinates of their vertices
             //Add centroid again
            centroid.add(sphereGeometry.vertices[face.b]);
            centroid.add(sphereGeometry.vertices[face.c]);
            centroid.divideScalar(3);//The coordinates of the central point of a triangle
            let arrow = new THREE.ArrowHelper(
                face.normal,//The normal vector of face
                centroid,
                2,
                0xffcc55,
                0.5,
                0.5);//The arrow auxiliary line is equivalent to the normal vector represented by the arrow.
            sphere.add(arrow);
        }

Among them, sphereGeometry.vertices in the code of centroid.add(sphereGeometry.vertices[face.a]) contains all vertex information of the geometry body, and one of them can be obtained by [] index. Face.a and the following face.b and C are vertex index numbers of the face, indicating that the face is a triangle composed of three vertices with vertex numbers face.a, face.b and face.c. (The faces of webgl are triangles). Then we calculate the center points of the three vertices.

Settings of menu panel

Set some properties of Mesh Normalmaterial in the menu panel to test some characteristics of this material.
Among them:
** this.visible = meshMaterial.visible; // visible

        this.wireframe = meshMaterial.wireframe;//Whether or not to render objects in a wireframe fashion
        this.wireframeWidth = meshMaterial.wireframeLinewidth;//Width of Wire Frame
        this.transparent = meshMaterial.transparent;//Is it transparent?
        this.opacity = meshMaterial.opacity;//Transparency requires transparent to be true to be effective
        this.side = "front";//There are three ways to render edges: front, back, and both sides.
        this.selectMesh = "sphere";//Currently selected geometry
        this.shading = "smooth";//The way of shading, flat shading and smooth shading, can hardly distinguish a very flat geometry, such as cube **
    
function initDatGUI() {
        //Setting the parameters needed in the menu
        controls = new function () {
            this.rotationSpeed = 0.02;
            this.visible = meshMaterial.visible;//Visible
            this.wireframe = meshMaterial.wireframe;//Whether or not to render objects in a wireframe fashion
            this.wireframeWidth = meshMaterial.wireframeLinewidth;//Width of Wire Frame
            this.transparent = meshMaterial.transparent;//Is it transparent?
            this.opacity = meshMaterial.opacity;//Transparency requires transparent to be true to be effective
            this.side = "front";//There are three ways to render edges: front, back, and both sides.
            this.selectMesh = "sphere";//Currently selected geometry
            this.shading = "smooth";//The way of shading, flat shading and smooth shading, can hardly distinguish a flat geometry, such as a cube.
        };
        let gui = new dat.GUI();
        //Add the parameters just set to the menu
        let F1 = gui.addFolder("Mesh");
        F1.add(controls, "rotationSpeed", 0, 0.1);
        F1.add(controls, "visible").onChange(function (e) {
            meshMaterial.visible = e;
        });
        F1.add(controls, "wireframe").onChange(function (e) {
            meshMaterial.wireframe = e;
        });
        F1.add(controls, "wireframeWidth",0,10).onChange(function (e) {
            meshMaterial.wireframeWidth = e;
        });
        F1.add(controls, "transparent").onChange(function (e) {
            meshMaterial.transparent = e;
        });
        F1.add(controls, "opacity",0,1).onChange(function (e) {
            meshMaterial.opacity = e;
        });
        F1.add(controls, "side",["front","back","double"]).onChange(function (e) {
            switch (e) {
                case "front":
                    meshMaterial.side = THREE.FrontSide;
                    break;
                case "back":
                    meshMaterial.side = THREE.BackSide;
                    break;
                case "double":
                    meshMaterial.side = THREE.DoubleSide;
                    break;
            }
            meshMaterial.needsUpdate = true;//To update the material in the program, you need to add this sentence
        });
        F1.add(controls, "selectMesh",["sphere","cube","plane"]).onChange(function (e) {
            //First remove the objects in the scene, then add them.
            scene.remove(cube);
            scene.remove(sphere);
            scene.remove(plane);
            switch (e) {
                case "sphere":
                    scene.add(sphere);
                    break;
                case "cube":
                    scene.add(cube);
                    break;
                case "plane":
                    scene.add(plane);
                    break;
            }
        });
        F1.add(controls, "shading",["flat","smooth"]).onChange(function (e) {
            switch (e) {
                case "flat":
                    meshMaterial.shading = THREE.FlatShading;
                    break;
                case "smooth":
                    meshMaterial.shading = THREE.SmoothShading;
                    break;
            }
            meshMaterial.needsUpdate = true;//To update the material in the program, you need to add this sentence
        });
    }

** Note that if you want to change the properties of the material in the process of running the program, you need to add a sentence after the modification.
meshMaterial.needsUpdate = true, so that the update is successful. * *

360 degree panoramic background

A 360-degree panoramic background gives people a sense of immersion. All the backgrounds here use panoramic backgrounds.


If you want to use a panoramic background, you need six pictures in six directions to synthesize a complete background (you can also use one picture in six directions), and then assign these maps to scene background.

 let urls =[
            'image/posx.jpg',
            'image/negx.jpg',
            'image/posy.jpg',
            'image/negy.jpg',
            'image/posz.jpg',
            'image/negz.jpg'
        ];//Introducing 6-Direction Mapping
        let cubeMap = THREE.ImageUtils.loadTextureCube( urls );
        scene = new  THREE.Scene();
        scene.background = cubeMap;

These pictures need to be placed in order, right, left, back and forth, otherwise the background will be confused.
Here is a panoramic picture website, there are many 360 degree scenery, are six types, download and decompress can be directly introduced.
http://www.humus.name/index.p...

The complete code for this example is as follows:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Depth Material Test</title>
    <script src="../../import/three.js"></script>
    <script src="../../import/stats.js"></script>
    <script src="../../import/Setting.js"></script>
    <script src="../../import/OrbitControls.js"></script>
    <script src="../../import/dat.gui.min.js"></script>
    <script src="../../import/SceneUtils.js"></script>
    <style type="text/css">
        div#WebGL-output {
            border: none;
            cursor: pointer;
            width: 100%;
            height: 850px;
            background-color: #333333;
        }
    </style>
</head>
<body onload="Start()">
<div id="WebGL-output"></div>
<script>
    let camera, renderer, scene, light;
    let controller;
    let controls;
    let cube, sphere, plane, meshMaterial;

    function initThree() {
        //Render initialization
        renderer = new THREE.WebGLRenderer({
            antialias: true
        });
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.setClearColor(0x333333);
        document.getElementById("WebGL-output").appendChild(renderer.domElement);//Add rendering to div

        //Initialize the camera, using the perspective projection camera here
        camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 10, 100);
        camera.position.set(0, 40, 60);
        camera.up.x = 0;//Set the orientation of the camera in which direction, and define the orientation of the Y axis above the camera here.
        camera.up.y = 1;
        camera.up.z = 0;
        camera.lookAt(0, 0, 0);

        //Initialization scenario
        let urls =[
            'image/posx.jpg',
            'image/negx.jpg',
            'image/posy.jpg',
            'image/negy.jpg',
            'image/posz.jpg',
            'image/negz.jpg'
        ];//Introducing 6-Direction Mapping
        let cubeMap = THREE.ImageUtils.loadTextureCube( urls );
        scene = new  THREE.Scene();
        scene.background = cubeMap;

        //Camera movement
        controller = new THREE.OrbitControls(camera, renderer.domElement);
        controller.target = new THREE.Vector3(0, 0, 0);


        light = new THREE.AmbientLight(0x0c0c0c);
        scene.add(light);

        // add spotlight for the shadows
        light = new THREE.SpotLight(0xffffff);
        light.position.set(0, 30, 30);
        scene.add(light);

    }

    //Initialization menu panel
    function initDatGUI() {
        //Setting the parameters needed in the menu
        controls = new function () {
            this.rotationSpeed = 0.02;
            this.visible = meshMaterial.visible;//Visible
            this.wireframe = meshMaterial.wireframe;//Whether or not to render objects in a wireframe fashion
            this.wireframeWidth = meshMaterial.wireframeLinewidth;//Width of Wire Frame
            this.transparent = meshMaterial.transparent;//Is it transparent?
            this.opacity = meshMaterial.opacity;//Transparency requires transparent to be true to be effective
            this.side = "front";//There are three ways to render edges: front, back, and both sides.
            this.selectMesh = "sphere";//Currently selected geometry
            this.shading = "smooth";//The way of shading, flat shading and smooth shading, can hardly distinguish a flat geometry, such as a cube.
        };
        let gui = new dat.GUI();
        //Add the parameters just set to the menu
        let F1 = gui.addFolder("Mesh");
        F1.add(controls, "rotationSpeed", 0, 0.1);
        F1.add(controls, "visible").onChange(function (e) {
            meshMaterial.visible = e;
        });
        F1.add(controls, "wireframe").onChange(function (e) {
            meshMaterial.wireframe = e;
        });
        F1.add(controls, "wireframeWidth",0,10).onChange(function (e) {
            meshMaterial.wireframeWidth = e;
        });
        F1.add(controls, "transparent").onChange(function (e) {
            meshMaterial.transparent = e;
        });
        F1.add(controls, "opacity",0,1).onChange(function (e) {
            meshMaterial.opacity = e;
        });
        F1.add(controls, "side",["front","back","double"]).onChange(function (e) {
            switch (e) {
                case "front":
                    meshMaterial.side = THREE.FrontSide;
                    break;
                case "back":
                    meshMaterial.side = THREE.BackSide;
                    break;
                case "double":
                    meshMaterial.side = THREE.DoubleSide;
                    break;
            }
            meshMaterial.needsUpdate = true;//To update the material in the program, you need to add this sentence
        });
        F1.add(controls, "selectMesh",["sphere","cube","plane"]).onChange(function (e) {
            //First remove the objects in the scene, then add them.
            scene.remove(cube);
            scene.remove(sphere);
            scene.remove(plane);
            switch (e) {
                case "sphere":
                    scene.add(sphere);
                    break;
                case "cube":
                    scene.add(cube);
                    break;
                case "plane":
                    scene.add(plane);
                    break;
            }
        });
        F1.add(controls, "shading",["flat","smooth"]).onChange(function (e) {
            switch (e) {
                case "flat":
                    meshMaterial.shading = THREE.FlatShading;
                    break;
                case "smooth":
                    meshMaterial.shading = THREE.SmoothShading;
                    break;
            }
            meshMaterial.needsUpdate = true;//To update the material in the program, you need to add this sentence
        });
    }

    function initObject() {
        //Create Cubes, Geometries of the Earth and the Earth
        let cubeGeometry = new THREE.BoxGeometry(10, 10, 10);
        let sphereGeometry = new THREE.SphereGeometry(10, 20, 20);
        let planeGeometry = new THREE.PlaneGeometry(10, 10, 1, 1);
        //Create a Normal Material
        meshMaterial = new THREE.MeshNormalMaterial();

        cube = new THREE.Mesh(cubeGeometry, meshMaterial);
        sphere = new THREE.Mesh(sphereGeometry, meshMaterial);
        plane = new THREE.Mesh(planeGeometry, meshMaterial);
        //Unify the three positions
        cube.position.set(0,0,0);
        sphere.position = cube.position;
        plane.position = cube.position;

        //A normal vector is displayed on each surface of the sphere to facilitate observation of the rendering method of the normal vector material.
        for(let i=0;i<sphereGeometry.faces.length;i++){//Cycle on each surface
            let face = sphereGeometry.faces[i];//Get the object for each face
            let centroid = new THREE.Vector3();//First, create a vector3 object to use to find the center of each face.
            centroid.add(sphereGeometry.vertices[face.a]);
            // Pass the index of the three vertices on this surface to sphereGeom.vertices to find the coordinates of their vertices and add them to the centroid
            centroid.add(sphereGeometry.vertices[face.b]);
            centroid.add(sphereGeometry.vertices[face.c]);
            centroid.divideScalar(3);//The coordinates of the central point of a triangle
            let arrow = new THREE.ArrowHelper(
                face.normal,
                centroid,
                2,
                0xffcc55,
                0.5,
                0.5);//The arrow auxiliary line is equivalent to the normal vector represented by the arrow.
            sphere.add(arrow);
        }
        scene.add(sphere);
    }

    function rotation() {
        scene.traverse(function (e) {
            if (e instanceof THREE.Mesh) {
                e.rotation.y += controls.rotationSpeed;
            }
        })
    }

    //renderer
    function render() {
        rotation();
        stats.update();
        renderer.clear();
        requestAnimationFrame(render);
        renderer.render(scene, camera);
    }

    //Function function
    function setting() {
        loadFullScreen();
        loadAutoScreen(camera, renderer);
        loadStats();
    }

    //Running the main function, typing the code is always wrong, so it's more convenient to change the name to Start.
    function Start() {
        initThree();
        initObject();
        initDatGUI();
        setting();
        render();
    }
</script>
</body>
</html>

Tags: Javascript github

Posted on Thu, 25 Apr 2019 12:06:34 -0400 by HAN!