threejs-材质


前言

threejs材质讲解:材质常用属性,材质种类,效果示例


材质的常用属性

基础属性

 id // 标识符,创建时自增
 uuid // 唯一标识
 name // 材质名称
 opacity // 不透明度,[0,1],transpant为true时生效
 transpant // bool
 overdraw // 过度描绘
 visible // 是否可见
 side // 侧面,定义为哪一面使用材质:Three.FrontSide,Three.BackSide,Three.DoubleSide
 needsUpdate // bool,为true时,使用最新的材质属性而不是缓存
 colorWrite // bool,为true时,不会输出真实的颜色
 flatShading // bool,平面着色,为flase时光照效果更加平滑
 lights // bool,为true时接收光照
 dithering // bool,开启时使用颜色抖动
 shadowSide // 产生投影的面,与side对应的面相反
 vertexColors // 顶点颜色
 fog // bool,雾化效果

融合属性

渲染的颜色与背景交互的方式

 blending // 材质与背景融合的方式
 blendSrc // 融合源
 blendDst // 融合目标
 blendequation // 融合人透明度,结blendSrc,blendDst自定义融合方式
 blendSrcAplha // 为 blendSrc指定透明度
 blendDstAplha // 为 blendDst指定透明度

高级属性

WebGL底层相关的一些参数,不常用

 depthTest // 
 depthWrite // 
 depthFunc //
 alphstest //
 precision // 

常用的材质

MeshBasicMaterial()

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

  • 具备一些自有属性
color // 颜色
wireframe // bool,将材质渲染成线框,对调试有利
wireframeLinewidth // 开启wireframe时,定义线框中线的宽度
(线框线宽)
这个属性
wireframeLinecap // 开启wireframe时,定义线框模式下顶点间线段的端点如何显示。可选值包括 butt(平)、round(圆)和 square(方)
wireframeLinejoin //定义线段的连接点如何显示。可选的值包括 round、bevel(斜角)和 miter(尖角)。

MeshDepthMaterial()

按深度绘制几何体的材质。深度基于相机远近平面。白色最近,黑色最远,可以通过相机的near属性和far属性之间的差距决定场景的亮度和物体消失的速度。

联合材质createMultiMaterialObject ( geometry, materials: Array )

需要借助SceneUtils这个外部工具包

  • geometry 几何体
  • materials 材质数组

举例

    const cubeGeometry = new THREE.BoxGeometry(10, 10, 10);

    // 定义要联合的两种材质
    const cubeMaterial = new THREE.MeshDepthMaterial();
    const colorMaterial = new THREE.MeshBasicMaterial({
        color: controls.color,
        transparent: true, // 当材质为MeshBasicMaterial时,需要设置,否则会出现一个纯色物体
        blending: THREE.MultiplyBlending
    });
    const cube = new THREE.SceneUtils.createMultiMaterialObject(
        cubeGeometry,
        [
            colorMaterial,
            cubeMaterial
      ]);

    cube.children[1].scale.set(0.99, 0.99, 0.99); // 防止画面闪烁 
    cube.castShadow = true;

    scene.add(cube);

createMultiMaterialObject函数创建一个网格的时候,几何体会被复制,返回一个Group,里面两个网格完全相同,分布被赋予不同的材料。通过缩小MeshDepthMaterial材质的网格,就可以避免画面闪烁。方法如下:

cube.children[1].scale.set(0.99, 0.99, 0.99);

法线材质MeshNormalMaterial()

把法向量映射到RGB颜色的材质

Lambert材质MeshLambertMaterial()

该材质使用基于非物理的Lambertian模型来计算反射率。 这可以很好地模拟一些表面(例如未经处理的木材或石材),但不能模拟具有镜面高光的光泽表面(例如涂漆木材)

Phong材质MeshPhongMaterial()

该材质使用非物理的Blinn-Phong模型来计算反射率。 该材质可以模拟具有镜面高光的光泽表面(例如涂漆木材)

标准格材质MeshStandardMaterial()

使用物理上正确的模型计算表面材质与光照的互动。能够更好地表现塑料质感和金属质感

物理材质MeshPhysicalMaterial()

MeshStandardMaterial的扩展,能够更好地控制反射率

线材质LineMaterial()

一种用于绘制线框样式几何体的材质

效果示例

场景搭建见链接 threejs-场景创建(基于react-hooks)

const createGeo = () => {
        /**
         * 创建两个法向量材质的球和立方体
         */
        const sphereGeometry = new THREE.SphereGeometry(5, 20, 20);
        const cubeGeometry = new THREE.BoxGeometry(10, 10, 10);

        const meshMaterial = new THREE.MeshNormalMaterial();
        const sphere = new THREE.Mesh(sphereGeometry, meshMaterial);
        const cube = new THREE.Mesh(cubeGeometry, meshMaterial);

        sphere.position.set(-40, 20, 0);
        cube.position.set(-20, 20, 0);

        sphere.castShadow = true;
        cube.castShadow = true;

        scence.add(sphere);
        scence.add(cube);

        /**
         * 创建一个指定材质的立方体
         */
        const group = new THREE.Mesh();
        // add all the rubik cube elements
        const mats = [
            new THREE.MeshBasicMaterial({ color: 0x009e60 }),
            new THREE.MeshBasicMaterial({ color: 0x0051ba }),
            new THREE.MeshBasicMaterial({ color: 0xffd500 }),
            new THREE.MeshBasicMaterial({ color: 0xff5800 }),
            new THREE.MeshBasicMaterial({ color: 0xC41E3A }),
            new THREE.MeshBasicMaterial({ color: 0xffffff }),
        ];

        for (let x = 0; x < 3; x++) {
            for (let y = 0; y < 3; y++) {
                for (let z = 0; z < 3; z++) {
                    const cubeGeom = new THREE.BoxGeometry(2.9, 2.9, 2.9);
                    const cube = new THREE.Mesh(cubeGeom, mats);
                    cube.castShadow = true;
                    cube.position.set(x * 3 - 3, y * 3 - 3 + 20, z * 3 - 3);
                    group.add(cube);
                }
            }
        }
        group.castShadow = true
        scence.add(group);


        /**
         * 创建一个lambert材质的立方体
         */
        const LambertMaterial = new THREE.MeshLambertMaterial({
            color: 0x7777ff
        });
        const lambertSphere = new THREE.Mesh(sphereGeometry, LambertMaterial);
        lambertSphere.castShadow = true;
        lambertSphere.position.set(20, 20, 0);
        scence.add(lambertSphere);

        /**
         * 创建一个Phong材质的立方体
         */
        const PhongMaterial = new THREE.MeshPhongMaterial({
            color: 0x7777ff
        });
        const PhongSphere = new THREE.Mesh(sphereGeometry, PhongMaterial);
        PhongSphere.castShadow = true;
        PhongSphere.position.set(40, 20, 0);
        scence.add(PhongSphere);

        /**
         * 创建一个标准材质的立方体
         */
        const Standardmaterial = new THREE.MeshStandardMaterial({ color: 0x7777ff });
        const StandardCube = new THREE.Mesh(cubeGeometry, Standardmaterial);

        StandardCube.castShadow = true;
        StandardCube.position.set(60, 20, 0);
        scence.add(StandardCube);

        /**
         * 创建一个物理材质的立方体
         */
        const Physicalmaterial = new THREE.MeshPhysicalMaterial({ color: 0x7777ff });
        const PhysicalCube = new THREE.Mesh(cubeGeometry, Physicalmaterial);

        PhysicalCube.castShadow = true;
        PhysicalCube.position.set(80, 20, 0);
        scence.add(PhysicalCube);


        /**
         * 创建一个线材质的立方体
         */
        const lineMater = new THREE.LineBasicMaterial({ vertexColors: true })
        const geometry = new THREE.BufferGeometry()
        const color = new THREE.Color();
        let vertices = new Array();
        let color1 = new Array();
        for (let i = 0; i < 5000; i++) {
            const x = Math.random() * 10 
            const y = Math.random() * 10 
            const z = Math.random() * 10 
            vertices.push(x, y, z);

            color.setHSL(Math.random(), Math.random(), Math.random());
            color1.push(color.r, color.g, color.b);
            geometry.setAttribute(
                'position',
                new THREE.Float32BufferAttribute(vertices, 3)
            );
            geometry.setAttribute('color', new THREE.Float32BufferAttribute(color1, 3));
        }

        const mesh = new THREE.Line(geometry, lineMater)
        mesh.position.set(100, 12.5, -5)
        mesh.castShadow = true
        scence.add(mesh)
    }

效果如下:
在这里插入图片描述