Three.js——基础材质、深度材质、法向材质、面材质、朗伯材质、Phong材质、着色器材质、直线和虚线、联合材质

个人简介

👀个人主页: 前端杂货铺
🙋‍♂️学习方向: 主攻前端方向,正逐渐往全干发展
📃个人状态: 研发工程师,现效力于中国工业软件事业
🚀人生格言: 积跬步至千里,积小流成江海
🥇推荐学习:🍍前端面试宝典 🍉Vue2 🍋Vue3 🍓Vue2/3项目实战 🥝Node.js🍒Three.js🍖数据结构与算法体系教程

🌕个人推广:每篇文章最下方都有加入方式,旨在交流学习&资源分享,快加入进来吧

内容参考链接
WebGL专栏WebGL 入门
Three.js(一)创建场景、渲染三维对象、添加灯光、添加阴影、添加雾化
Three.js(二)scene场景、几何体位置旋转缩放、正射投影相机、透视投影相机
Three.js(三)聚光灯、环境光、点光源、平行光、半球光

文章目录

    • 前言
    • 一、基础网格材质
    • 二、深度网格材质
    • 三、法向网格材质
    • 四、面材质
    • 五、朗伯网格材质
    • 六、Phong 网格材质
    • 七、着色器网格材质
    • 八、直线和虚线
    • 九、联合材质
    • 总结

前言

大家好,这里是前端杂货铺。

上篇文章我们学习了 聚光灯、环境光、点光源、平行光、半球光。接下来,我们继续我们 three.js 的学习!

在学习的过程中,如若需要深入了解或扩展某些知识,可以自行查阅 => three.js官方文档。


老规矩,我们先把本篇文章需要使用的 ./controls/index.js 补充完毕

const basicType = {
    // 颜色。默认为一个白色(0xffffff)的 Color 对象。
    color: {
        method: 'addColor',
        getValue: item => item.color.getStyle(),
        setValue: (item, value) => item.color.setStyle(value),
    },
    // 
    skyColor: {
        method: 'addColor',
        getValue: item => item.skyColor.getStyle(),
        setValue: (item, value) => item.skyColor.setStyle(value),
    },
    // 光照强度。默认值为 1
    intensity: {
        method: 'add',
        extends: [0, 2],
        getValue: item => item.intensity,
        setValue: (item, value) => item.intensity = +value,
    },
    // 光源照射的最大距离。默认值为 0(无限远)
    distance: {
        method: 'add',
        extends: [0, 1],
        getValue: item => item.distance,
        setValue: (item, value) => item.distance = +value,
    },
    // 光线照射范围的角度。默认值为 Math.PI/3
    angle: {
        method: 'add',
        extends: [0, Math.PI / 2],
        getValue: item => item.angle,
        setValue: (item, value) => item.angle = +value,
    },
    // 决定了光线强度递减的速度。
    exponent: {
        method: 'add',
        extends: [0, 20],
        getValue: item => item.exponent,
        setValue: (item, value) => item.exponent = +value,
    },
    // 亮度
    opacity: {
        extends: [0, 1],
        getValue: item => item.opacity,
        setValue: (item, value) => item.opacity = +value
    },
    // 透明度
    transparent: {
        getValue: item => item.transparent,
        setValue: (item, value) => item.transparent = value
    },
    // 线框
    wireframe: {
        getValue: item => item.wireframe,
        setValue: (item, value) => item.wireframe = value
    },
    // 显隐
    visible: {
        getValue: item => item.visible,
        setValue: (item, value) => item.visible = value
    },
    cameraNear: {
        extends: [0, 50],
        getValue: (item, camera) => camera.near,
        setValue: (item, value, camera) => camera.near = value
    },
    cameraFar: {
        extends: [50, 200],
        getValue: (item, camera) => camera.far,
        setValue: (item, value, camera) => camera.far = value
    },
    side: {
        extends: [['font', 'back', 'double']],
        getValue: (item, camera) => 'font',
        setValue: (item, value) => {
            switch(value) {
                case 'font':
                    item.side = THREE.FrontSide;
                    break;
                case 'back':
                    item.side = THREE.BackSide;
                    break; 
                case 'double':
                    item.side = THREE.DoubleSide;
                    break;
            }
        }
    },
    // 材料的环境颜色
    ambient: {
        method: 'addColor',
        getValue: (item) => item.ambient.getHex(),
        setValue: (item, value) => item.ambient = new THREE.Color(value),
    },
    // 物体材料本身发出的颜色
    emissive: {
        method: 'addColor',
        getValue: (item) => item.emissive.getHex(),
        setValue: (item, value) => item.emissive = new THREE.Color(value),
    },
    // 设置高亮部分的颜色
    specular: {
        method: 'addColor',
        getValue: (item) => item.specular.getHex(),
        setValue: (item, value) => item.specular = new THREE.Color(value),
    },
    // 设置高亮部分的亮度
    shininess: {
        extends: [0, 100],
        getValue: (item) => item.shininess,
        setValue: (item, value) => item.shininess = value,
    },
    red: {
        extends: [0, 1],
        getValue: (item) => item.uniforms.r.value,
        setValue: (item, value) => item.uniforms.r.value = value,
    },
    alpha: {
        extends: [0, 1],
        getValue: (item) => item.uniforms.a.value,
        setValue: (item, value) => item.uniforms.a.value = value,
    },
    dashSize: {
        extends: [0, 5],
        getValue: (item) => item.dashSize,
        setValue: (item, value) => item.dashSize = +value,
    },
    gapSize: {
        extends: [0, 5],
        getValue: (item) => item.gapSize,
        setValue: (item, value) => item.gapSize = +value,
    }
}

const itemType = {
    SpotLight: ['color', 'intensity', 'distance', 'angle', 'exponent'], // 聚光灯
    AmbientLight: ['color'], // 环境光
    PointLight: ['color', 'intensity', 'distance'], // 点光源
    DirectionalLight: ['color', 'intensity'], // 平行光
    HemisphereLight: ['groundColor', 'intensity'], // 半球光
    MeshBasicMaterial: ['color', 'opacity', 'transparent', 'wireframe', 'visible'], // 基础网格材质
    MeshDepthMaterial: ['wireframe', 'cameraNear', 'cameraFar'], // 深度网格材质
    MeshNormalMaterial: ['opacity', 'transparent', 'wireframe', 'visible', 'side'],
    MeshLambertMaterial: ['opacity', 'transparent', 'wireframe', 'visible', 'side', 'ambient', 'emissive', 'color'], // 朗伯材质
    MeshPhongMaterial: ['opacity', 'transparent', 'wireframe', 'visible', 'side', 'ambient', 'emissive', 'color', 'specular', 'shininess'], // Phong材质
    ShaderMaterial: ['red', 'alpha'], // 着色器材质
    LineBasicMaterial: ['color'], // 直线
    LineDashedMaterial: ['dashSize', 'gapSize'], // 虚线
}

function initControls(item, camera) {
    console.log('item', item)
    const typeList = itemType[item.type];
    const controls = {};

    if (!typeList || !typeList.length) {
        return;
    }

    const gui = new dat.GUI();

    for (let i = 0; i < typeList.length; i++) {
        const child = basicType[typeList[i]];
        if (child) {
            controls[typeList[i]] = child.getValue(item, camera);

            const childExtends = child.extends || [];

            gui[child.method || 'add'](controls, typeList[i], ...childExtends).onChange((value) => {
                child.setValue(item, value, camera);
            })
        }
    }
}

一、基础网格材质

基础网格材质,是一个以简单着色(平面或线框)方式来绘制几何体的材质。这种材质不受光照的影响。

new MeshBasicMaterial(parameters: Object);

使用场景:适用于不需要光照计算或复杂渲染效果的简单物体。例如,静态的、不需要光照变化的物体。

特点:不受光照影响,颜色始终保持一致。

参数名称描述
color材质颜色
wireframe是否渲染成线框
wireframeLinewidth设置线框宽度
wireframeLinecap线段间的端点如何显示
wireframeLinejoin线段的连接点如何显示
shading定义如何着色
vertexColors为每个顶点定义不同的颜色
fog是否会受全局雾化效果设置的影响
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="../lib/three/three.js"></script>
    <script src="../lib/three/dat.gui.js"></script>
    <script src="../controls/index.js"></script>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
    </style>
</head>

<body>
    <script>
        // 创建场景
        const scene = new THREE.Scene();
        // 创建相机 视野角度FOV、长宽比、近截面、远截面
        const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
        // 设置相机位置
        camera.position.set(0, 0, 20);

        // 创建渲染器
        const renderer = new THREE.WebGLRenderer();
        // 设置渲染器尺寸
        renderer.setSize(window.innerWidth, window.innerHeight);
        document.body.appendChild(renderer.domElement);

        // 添加立方体
        const cubeGeometry = new THREE.BoxGeometry(1, 1, 1);
        // 创建立方体材质
        const cubeMaterial = new THREE.MeshBasicMaterial({
            color: 0xff0000,
            wireframe: false
        });

        const cube = new THREE.Mesh(cubeGeometry, cubeMaterial);

        // 添加到场景
        scene.add(cube);

        // 添加灯光
        const spotLight = new THREE.SpotLight(0xffffff);
        spotLight.position.set(-10, 10, 90);
        scene.add(spotLight);
        spotLight.shadowMapWidth = 3456; // 分辨率宽度
        spotLight.shadowMapHeight = 3456; // 分辨率高度 越大越清晰但也越消耗性能
        
        initControls(cubeMaterial);

        const animation = () => {
            cube.rotation.x += 0.01;
            cube.rotation.y += 0.01;

            // 渲染
            renderer.render(scene, camera);
            requestAnimationFrame(animation);
        }

        animation();
    </script>
</body>

</html>

基础网格材质


二、深度网格材质

深度网格材质是一种 按深度绘制几何体的材质。深度基于相机远近平面。白色最近,黑色最远。

new MeshDepthMaterial(parameters: Object);

使用场景:用于显示物体的深度信息,通常用于深度测试或特殊视觉效果。

特点:只渲染物体的深度信息,不显示颜色或纹理。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="../lib/three/three.js"></script>
    <script src="../lib/three/dat.gui.js"></script>
    <script src="../controls/index.js"></script>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
    </style>
</head>

<body>
    <script>
        // 创建场景
        const scene = new THREE.Scene();
        // 创建相机 视野角度FOV、长宽比、近截面、远截面
        const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
        // 设置相机位置
        camera.position.set(0, 0, 20);

        // 创建渲染器
        const renderer = new THREE.WebGLRenderer();
        // 设置渲染器尺寸
        renderer.setSize(window.innerWidth, window.innerHeight);
        document.body.appendChild(renderer.domElement);

        // 添加立方体
        const cubeGeometry = new THREE.BoxGeometry(1, 1, 1);
        // 创建立方体材质
        const cubeMaterial = new THREE.MeshDepthMaterial();

        const cube = new THREE.Mesh(cubeGeometry, cubeMaterial);

        // 添加到场景
        scene.add(cube);

        // 添加灯光
        const spotLight = new THREE.SpotLight(0xffffff);
        spotLight.position.set(-10, 10, 90);
        scene.add(spotLight);
        spotLight.shadowMapWidth = 3456; // 分辨率宽度
        spotLight.shadowMapHeight = 3456; // 分辨率高度 越大越清晰但也越消耗性能
        
        initControls(cubeMaterial, camera);

        const animation = () => {
            cube.rotation.x += 0.01;
            cube.rotation.y += 0.01;

            // 渲染
            renderer.render(scene, camera);
            requestAnimationFrame(animation);
        }

        animation();
    </script>
</body>

</html>

深度网格材质


三、法向网格材质

法向网格材质是一种 把法向量映射到 RGB 颜色的材质

new THREE.MeshNormalMaterial(parameters: Object);

使用场景:适用于低多边形数模型或动态生成的几何形状。通过使用法线贴图,它可以在没有复杂几何形状的情况下创建逼真的凹凸效果。

特点:基于法向量的颜色映射,MeshNormalMaterial渲染的每一个面颜色都不同;但即使在物体旋转时,这些颜色也基本保持在原来的位置,这使得MeshNormalMaterial在需要保持颜色与面关联的场景中非常有用。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="../lib/three/three.js"></script>
    <script src="../lib/three/dat.gui.js"></script>
    <script src="../controls/index.js"></script>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
    </style>
</head>

<body>
    <script>
        // 创建场景
        const scene = new THREE.Scene();
        // 创建相机 视野角度FOV、长宽比、近截面、远截面
        const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
        // 设置相机位置
        camera.position.set(0, 0, 20);

        // 创建渲染器
        const renderer = new THREE.WebGLRenderer();
        // 设置渲染器尺寸
        renderer.setSize(window.innerWidth, window.innerHeight);
        document.body.appendChild(renderer.domElement);

        // 添加立方体
        const cubeGeometry = new THREE.BoxGeometry(1, 1, 1);
        // 创建立方体材质
        const cubeMaterial = new THREE.MeshNormalMaterial();

        const cube = new THREE.Mesh(cubeGeometry, cubeMaterial);

        // 添加到场景
        scene.add(cube);

        // 添加灯光
        const spotLight = new THREE.SpotLight(0xffffff);
        spotLight.position.set(-10, 10, 90);
        scene.add(spotLight);
        spotLight.shadowMapWidth = 3456; // 分辨率宽度
        spotLight.shadowMapHeight = 3456; // 分辨率高度 越大越清晰但也越消耗性能
        
        initControls(cubeMaterial, camera);

        const animation = () => {
            cube.rotation.x += 0.01;
            cube.rotation.y += 0.01;

            // 渲染
            renderer.render(scene, camera);
            requestAnimationFrame(animation);
        }

        animation();
    </script>
</body>

</html>

法向网格材质


四、面材质

MeshFaceMaterial 在 Three.js 中并不是一个真正的材质,它更像是一个 材质容器。其主要用途是为几何体的每个面指定不同的材质,从而允许每个面具有独特的视觉表现。

new THREE.MeshFaceMaterial(parameters: Object);

注:MeshFaceMaterial 在新版 Three.js 中已经被材质数组所取代。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="../lib/three/three.js"></script>
    <script src="../lib/three/dat.gui.js"></script>
    <script src="../controls/index.js"></script>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
    </style>
</head>

<body>
    <script>
        // 创建场景
        const scene = new THREE.Scene();
        // 创建相机 视野角度FOV、长宽比、近截面、远截面
        const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
        // 设置相机位置
        camera.position.set(0, 0, 20);

        // 创建渲染器
        const renderer = new THREE.WebGLRenderer();
        // 设置渲染器尺寸
        renderer.setSize(window.innerWidth, window.innerHeight);
        document.body.appendChild(renderer.domElement);

        // 添加立方体
        const cubeGeometry = new THREE.BoxGeometry(1, 1, 1);
        // 创建立方体材质
        const cubeMaterial = new THREE.MeshFaceMaterial([
            new THREE.MeshBasicMaterial({ color: 0x009e60 }),
            new THREE.MeshBasicMaterial({ color: 0x0051ba }),
            new THREE.MeshBasicMaterial({ color: 0xffd500 }),
            new THREE.MeshBasicMaterial({ color: 0xc41e3a }),
            new THREE.MeshBasicMaterial({ color: 0xffff00 }),
            new THREE.MeshBasicMaterial({ color: 0xff5800 }),
        ]);

        const cube = new THREE.Mesh(cubeGeometry, cubeMaterial);

        // 添加到场景
        scene.add(cube);

        // 添加灯光
        const spotLight = new THREE.SpotLight(0xffffff);
        spotLight.position.set(-10, 10, 90);
        scene.add(spotLight);
        spotLight.shadowMapWidth = 3456; // 分辨率宽度
        spotLight.shadowMapHeight = 3456; // 分辨率高度 越大越清晰但也越消耗性能
        
        initControls(cubeMaterial, camera);

        const animation = () => {
            cube.rotation.x += 0.01;
            cube.rotation.y += 0.01;

            // 渲染
            renderer.render(scene, camera);
            requestAnimationFrame(animation);
        }

        animation();
    </script>
</body>

</html>

面材质


五、朗伯网格材质

朗伯网格材质是 一种非光泽表面的材质,没有镜面高光

new THREE.MeshLambertMaterial(parameters: Object);

使用场景:适用于需要模拟漫反射光照效果的物体。这种材质对光源的方向和强度敏感,适合表现柔和的表面。

特点:根据光源方向和强度计算表面颜色,产生柔和的阴影。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="../lib/three/three.js"></script>
    <script src="../lib/three/dat.gui.js"></script>
    <script src="../controls/index.js"></script>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
    </style>
</head>

<body>
    <script>
        // 创建场景
        const scene = new THREE.Scene();
        // 创建相机 视野角度FOV、长宽比、近截面、远截面
        const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
        // 设置相机位置
        camera.position.set(0, 0, 20);

        // 创建渲染器
        const renderer = new THREE.WebGLRenderer();
        // 设置渲染器尺寸
        renderer.setSize(window.innerWidth, window.innerHeight);
        document.body.appendChild(renderer.domElement);

        // 添加立方体
        const cubeGeometry = new THREE.BoxGeometry(1, 1, 1);
        // 创建立方体材质
        const cubeMaterial = new THREE.MeshLambertMaterial({ color: 0xff0000 });

        const cube = new THREE.Mesh(cubeGeometry, cubeMaterial);

        // 添加到场景
        scene.add(cube);

        // 添加灯光
        const spotLight = new THREE.SpotLight(0xffffff);
        spotLight.position.set(-10, 10, 90);
        scene.add(spotLight);
        spotLight.shadowMapWidth = 3456; // 分辨率宽度
        spotLight.shadowMapHeight = 3456; // 分辨率高度 越大越清晰但也越消耗性能
        
        initControls(cubeMaterial, camera);

        const animation = () => {
            cube.rotation.x += 0.01;
            cube.rotation.y += 0.01;

            // 渲染
            renderer.render(scene, camera);
            requestAnimationFrame(animation);
        }

        animation();
    </script>
</body>

</html>

朗伯网格材质


六、Phong 网格材质

Phong 网格材质是一种 用于具有镜面高光的光泽表面的材质

new THREE.MeshPhongMaterial(parameters: Object);

使用场景:适用于需要更高级光照效果的物体,如镜面反射和高光。这种材质可以模拟更真实的光照效果。

特点:支持漫反射、镜面反射和高光,可以产生更丰富的光影效果。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="../lib/three/three.js"></script>
    <script src="../lib/three/dat.gui.js"></script>
    <script src="../controls/index.js"></script>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
    </style>
</head>

<body>
    <script>
        // 创建场景
        const scene = new THREE.Scene();
        // 创建相机 视野角度FOV、长宽比、近截面、远截面
        const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
        // 设置相机位置
        camera.position.set(0, 0, 20);

        // 创建渲染器
        const renderer = new THREE.WebGLRenderer();
        // 设置渲染器尺寸
        renderer.setSize(window.innerWidth, window.innerHeight);
        document.body.appendChild(renderer.domElement);

        // 添加立方体
        const cubeGeometry = new THREE.BoxGeometry(1, 1, 1);
        // 创建立方体材质
        const cubeMaterial = new THREE.MeshPhongMaterial({ color: 0xff0000 });

        const cube = new THREE.Mesh(cubeGeometry, cubeMaterial);

        // 添加到场景
        scene.add(cube);

        // 添加灯光
        const spotLight = new THREE.SpotLight(0xffffff);
        spotLight.position.set(-10, 10, 90);
        scene.add(spotLight);
        spotLight.shadowMapWidth = 3456; // 分辨率宽度
        spotLight.shadowMapHeight = 3456; // 分辨率高度 越大越清晰但也越消耗性能
        
        initControls(cubeMaterial, camera);

        const animation = () => {
            cube.rotation.x += 0.01;
            cube.rotation.y += 0.01;

            // 渲染
            renderer.render(scene, camera);
            requestAnimationFrame(animation);
        }

        animation();
    </script>
</body>

</html>

Phong网格材质


七、着色器网格材质

着色器网格材质是一种 使用自定义shader渲染的材质

const material = new THREE.ShaderMaterial( {
	uniforms: {
		time: { value: 1.0 },
		resolution: { value: new THREE.Vector2() }
	},

	vertexShader: document.getElementById( 'vertexShader' ).textContent,
	fragmentShader: document.getElementById( 'fragmentShader' ).textContent
} );

使用场景:适用于需要自定义渲染逻辑的高级场景。通过编写自定义的 GLSL 着色器代码,可以实现各种独特的视觉效果。

特点:允许用户编写自定义的顶点和片段着色器,实现高度自定义的渲染效果。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="../lib/three/three.js"></script>
    <script src="../lib/three/dat.gui.js"></script>
    <script src="../controls/index.js"></script>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
    </style>
</head>

<body>
    <script>
        // 创建场景
        const scene = new THREE.Scene();
        // 创建相机 视野角度FOV、长宽比、近截面、远截面
        const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
        // 设置相机位置
        camera.position.set(0, 0, 20);

        // 创建渲染器
        const renderer = new THREE.WebGLRenderer();
        // 设置渲染器尺寸
        renderer.setSize(window.innerWidth, window.innerHeight);
        document.body.appendChild(renderer.domElement);

        // 添加立方体
        const cubeGeometry = new THREE.BoxGeometry(1, 1, 1);
        // 创建立方体材质
        const cubeMaterial = new THREE.ShaderMaterial({
            uniforms: {
                r: {
                    type: 'f',
                    value: 1.0
                },
                a: {
                    type: 'f', // float 类型
                    value: 1.0
                }
            },
            // 顶点着色器
            vertexShader: `
                void main() {
                    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
                }
            `,
            // 片元着色器
            fragmentShader: `
                uniform float r;
                uniform float a;
                
                void main() {
                    gl_FragColor = vec4(r, 0.0, 0.0, a);
                
                }
            `,
            transparent: true,
        });

        const cube = new THREE.Mesh(cubeGeometry, cubeMaterial);

        // 添加到场景
        scene.add(cube);

        // 添加灯光
        const spotLight = new THREE.SpotLight(0xffffff);
        spotLight.position.set(-10, 10, 90);
        scene.add(spotLight);
        spotLight.shadowMapWidth = 3456; // 分辨率宽度
        spotLight.shadowMapHeight = 3456; // 分辨率高度 越大越清晰但也越消耗性能
        
        initControls(cubeMaterial, camera);

        const animation = () => {
            cube.rotation.x += 0.01;
            cube.rotation.y += 0.01;

            // 渲染
            renderer.render(scene, camera);
            requestAnimationFrame(animation);
        }

        animation();
    </script>
</body>

</html>

着色器网格材质


八、直线和虚线

基础线条材质(直线)是一种 用于绘制线框样式几何体的材质

// 直线
const material = new THREE.LineBasicMaterial({
  color: 0xff0000,
  linewidth: 1,
})

虚线材质(虚线)是一种 用于绘制虚线样式几何体的材质。

// 虚线
const material = new THREE.LineDashedMaterial({
  color: 0xff0000,
  dashSize: 1, // 短划线的长度
  gapSize: 1 // 间隔的长度
});
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="../lib/three/three.js"></script>
    <script src="../lib/three/dat.gui.js"></script>
    <script src="../controls/index.js"></script>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
    </style>
</head>

<body>
    <script>
        // 创建场景
        const scene = new THREE.Scene();
        // 创建相机 视野角度FOV、长宽比、近截面、远截面
        const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
        // 设置相机位置
        camera.position.set(0, 0, 20);

        // 创建渲染器
        const renderer = new THREE.WebGLRenderer();
        // 设置渲染器尺寸
        renderer.setSize(window.innerWidth, window.innerHeight);
        document.body.appendChild(renderer.domElement);

        // 添加直线和虚线
        const lines = new THREE.Geometry();
        lines.vertices = [
            new THREE.Vector3(0, 2, 5),
            new THREE.Vector3(0, -2, 5)
        ]

        // 直线
        // const material = new THREE.LineBasicMaterial({
        //     color: 0xff0000,
        //     linewidth: 1,
        // })

        // 虚线
        const material = new THREE.LineDashedMaterial({
            color: 0xff0000,
            dashSize: 1, // 短划线的长度
            gapSize: 1 // 间隔的长度
        });

        const line = new THREE.Line(lines, material);
        // 计算点到线的累积长度
        lines.computeLineDistances();

        scene.add(line);

        // 添加灯光
        const spotLight = new THREE.SpotLight(0xffffff);
        spotLight.position.set(-10, 10, 90);
        scene.add(spotLight);
        spotLight.shadowMapWidth = 3456; // 分辨率宽度
        spotLight.shadowMapHeight = 3456; // 分辨率高度 越大越清晰但也越消耗性能

        initControls(material, camera);

        const animation = () => {
            // 渲染
            renderer.render(scene, camera);
            requestAnimationFrame(animation);
        }

        animation();
    </script>
</body>

</html>

直线与虚线


九、联合材质

创建联合材质,需要使用 SceneUtils 场景工具,它一个用于操控场景的实用类。

.createMultiMaterialObject ( geometry : BufferGeometry, materials : Array ) : Group
geometry – 材料集的几何形状。
materials – 为物体准备的材料。

创建一个新组,囊括了在材质中定义的每种材质的新网格。请注意,这和为一个网格定义多种材质的材质数组不同。

该方法对于同时需要材质和线框绘制的物体非常有用。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="../lib/three/three.js"></script>
    <script src="../lib/three/dat.gui.js"></script>
    <script src="../controls/index.js"></script>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
    </style>
</head>

<body>
    <script>
        // 创建场景
        const scene = new THREE.Scene();
        // 创建相机 视野角度FOV、长宽比、近截面、远截面
        const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
        // 设置相机位置
        camera.position.set(0, 0, 20);

        // 创建渲染器
        const renderer = new THREE.WebGLRenderer();
        // 设置渲染器尺寸
        renderer.setSize(window.innerWidth, window.innerHeight);
        document.body.appendChild(renderer.domElement);

        // 添加立方体
        const cubeGeometry = new THREE.BoxGeometry(1, 1, 1);
        // 创建立方体材质
        const lambert = new THREE.MeshLambertMaterial({
            color: 0xff0000
        });
        const basic = new THREE.MeshBasicMaterial({
            wireframe: true
        });

        const cube = new THREE.SceneUtils.createMultiMaterialObject(cubeGeometry, [
            lambert, basic
        ]);

        // 添加到场景
        scene.add(cube);

        // 添加灯光
        const spotLight = new THREE.SpotLight(0xffffff);
        spotLight.position.set(-10, 10, 90);
        scene.add(spotLight);
        spotLight.shadowMapWidth = 3456; // 分辨率宽度
        spotLight.shadowMapHeight = 3456; // 分辨率高度 越大越清晰但也越消耗性能

        const animation = () => {
            cube.rotation.x += 0.01;
            cube.rotation.y += 0.01;

            // 渲染
            renderer.render(scene, camera);
            requestAnimationFrame(animation);
        }

        animation();
    </script>
</body>

</html>

联合材质


总结

本篇文章我们讲解了几种常见材质的基本使用,包括基础材质、深度材质、法向材质、面材质、朗伯材质、Phong材质、着色器材质、直线和虚线、联合材质。

更多内容扩展请大家自行查阅 => three.js官方文档,真心推荐读一读!!

好啦,本篇文章到这里就要和大家说再见啦,祝你这篇文章阅读愉快,你下篇文章的阅读愉快留着我下篇文章再祝!


参考资料:

  1. Three.js 官方文档
  2. WebGL+Three.js 入门与实战【作者:慕课网_yancy】

在这里插入图片描述


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/574018.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何使用rdtsc和C/C++来测量运行时间(如何使用内联汇编和获取CPU的TSC时钟频率)

本文主要是一个实验和思维扩展&#xff0c;是一个初步的尝试&#xff0c;旨在研究一些时间测量实现和在 C/C 中内联汇编和汇编函数的使用方法。除非你有特殊用途&#xff0c;不然不要使用汇编指令来实现这个功能。在“扩展阅读”部分会列出了一些不需要内联汇编实现的方法。 写…

猫头虎分享已解决Bug || TypeError: Cannot read property ‘map‘ of undefined**

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

4.25 C高级

思维导图 作业 2.输入两个数&#xff0c;实现两个数的排序 3.输入一个数&#xff0c;计算是否是水仙花 if ((g*g*gs*s*sb*b*bnum)) then echo YES else echo no fi 4.输入一个成绩实现登记判断 90-100A 80-89B 70-79C 60-69D 0-59E

“追忆似水年华 展望美好未来”——生命故事小组忆童趣活动

在人生的长河中&#xff0c;童年是明亮色彩的日子&#xff0c;但随着岁月的流逝&#xff0c;这些回忆有时会变得模糊&#xff0c;为唤起他们对美好童年的回忆&#xff0c;2024年4月9日上午9点&#xff0c;由成都市社会组织社区和社工人才服务中心支持&#xff0c;新都区民政局指…

OpenHarmony语言基础类库【@ohos.util.HashMap (非线性容器HashMap)】

HashMap底层使用数组链表红黑树的方式实现&#xff0c;查询、插入和删除的效率都很高。HashMap存储内容基于key-value的键值对映射&#xff0c;不能有重复的key&#xff0c;且一个key只能对应一个value。 HashMap和[TreeMap]相比&#xff0c;HashMap依据键的hashCode存取数据&…

文旅元宇宙解决方案|人工智能、虚拟数字人、导览系统深度应用

随着数字技术的飞速发展&#xff0c;文旅行业正迎来一场前所未有的变革。道可云文旅元宇宙平台以其前瞻性的技术视野和创新的解决方案&#xff0c;为各级文旅主管部门、旅游景区、博物馆、艺术展览馆等单位提供了全新的智慧景区导览、元宇宙场景搭建、AR场景开发以及数字人导游…

市场上免费且高效的云渲染平台,渲染100邀请码7788

在当今数字化时代&#xff0c;云渲染服务因其便捷性和高效性而日益受到追捧&#xff0c;广泛应用于建筑设计、影视制作和视觉艺术等多个领域。它不仅能够显著缩短项目完成的时间&#xff0c;还能大幅提升工作效率。 接下来&#xff0c;我们将探讨一些市场上公认的优质且免费的…

【Qt常用控件】—— QWidget 核心属性

目录 &#xff08;一&#xff09;控件概述 1.1 关于控件体系的发展 &#xff08;二&#xff09;QWidget 核心属性 2.1 核心属性概览 2.2 enabled 2.3 geometry 2.4 windowTitle 2.5 windowIcon 2.6 windowOpacity 2.7 cursor 2.8 font 2.9 toolTip 2.10 focus…

数据结构四:线性表之带头结点的单向循环循环链表的设计

前面两篇介绍了线性表的顺序和链式存储结构&#xff0c;其中链式存储结构为单向链表&#xff08;即一个方向的有限长度、不循环的链表&#xff09;&#xff0c;对于单链表&#xff0c;由于每个节点只存储了向后的结点的地址&#xff0c;到了尾巴结点就停止了向后链的操作。也就…

MySQL统计一个表的行数,使用count(1), count(字段), 还是count(*)?

为什么要使用count函数&#xff1f; 在开发系统的时候&#xff0c;我们经常要计算一个表的行数。比如我最近开发的牛客社区系统&#xff0c;有一个帖子表&#xff0c;其中一个功能就是要统计帖子的数量&#xff0c;便于分页显示计算总页数。 CREATE TABLE discuss_post (id i…

展览模型一般怎么打灯vray---模大狮模型网

在展览模型的设计中&#xff0c;灯光的运用是至关重要的&#xff0c;它不仅能够增强展品的视觉效果&#xff0c;还可以营造出独特的氛围和情感。在利用V-Ray进行灯光设置时&#xff0c;有一些常用的技巧和方法可以帮助设计师实现理想的展览效果。在本文中&#xff0c;我们将介绍…

漏洞修复优先级考虑-不错的思路

权威说法&#xff1a; 漏洞利用预测评分系统 &#xff08;EPSS&#xff09; 是一项数据驱动的工作&#xff0c;用于估计软件漏洞在野外被利用的可能性&#xff08;概率&#xff09; https://www.first.org/epss/ GitHub - TURROKS/CVE_Prioritizer: Streamline vulnerability…

在windows上安装MySQL数据库全过程

1.首先在MySQL的官网找到其安装包 在下图中点击MySQL Community(gpl) 找到MySQL Community Server 选择版本进行安装包的下载 2.安装包&#xff08;Windows (x86, 64-bit), MSI Installer&#xff09;安装步骤 继续点击下一步 继续进行下一步&#xff0c;直到出现此界面&#…

基于小程序实现的惠农小店系统设计与开发

作者主页&#xff1a;Java码库 主营内容&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app等设计与开发。 收藏点赞不迷路 关注作者有好处 文末获取源码 技术选型 【后端】&#xff1a;Java 【框架】&#xff1a;spring…

leetcode-比较版本号-88

题目要求 思路 1.因为字符串比较大小不方便&#xff0c;并且因为需要去掉前导的0&#xff0c;这个0我们并不知道有几个&#xff0c;将字符串转换为数字刚好能避免。 2.当判断到符号位的时候加加&#xff0c;跳过符号位。 3.判断数字大小&#xff0c;来决定版本号大小 4.核心代…

探索直播+电商系统中台架构:连接消费者与商品的智能纽带

随着直播电商的崛起&#xff0c;电商行业进入了全新的智能时代。直播形式的互动性和即时性为消费者提供了全新的购物体验&#xff0c;而电商平台则为商品的展示、销售和配送提供了强大的支持。在这一背景下&#xff0c;直播电商系统中台架构成为了连接消费者与商品的智能纽带&a…

ABTest如何计算最小样本量-工具篇

如果是比例类指标&#xff0c;有一个可以快速计算最小样本量的工具&#xff1a; https://www.evanmiller.org/ab-testing/sample-size.html 计算样本量有4个要输入的参数&#xff1a;①一类错误概率&#xff0c;②二类错误概率 &#xff08;一般是取固定取值&#xff09;&…

【JavaScript】内置对象 ③ ( Math 内置对象 | Math 内置对象简介 | Math 内置对象的使用 )

文章目录 一、Math 内置对象1、Math 内置对象简介2、Math 内置对象的使用 二、代码示例1、代码示例 - Math 内置对象的使用2、代码示例 - 封装 Math 内置对象 一、Math 内置对象 1、Math 内置对象简介 JavaScript 中的 Math 内置对象 是一个 全局对象 , 该对象 提供了 常用的 数…

名家采访:国家级中国茶文化首席非遗传承人——罗大友

“崇高的理想是一个人心中的太阳,能照亮生活中的每一步。”罗大友&#xff0c;性别&#xff1a;男&#xff0c;国家级中国茶文化首席非遗传承人•中国茶文化研究院院长、美国巴拿马太平洋万国博览会终身评委兼中国区联合主席&#xff0c;大学文化&#xff0c;高级政工师。 “第…

【算法】删除有序数组中的重复项

本题来源---《删除有序数组中的重复项》 题目描述 给你一个 非严格递增排列 的数组 nums &#xff0c;请你删除重复出现的元素&#xff0c;使每个元素 只出现一次 &#xff0c;返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。 示…
最新文章