three.js 7 材质

import * as THREE from 'three';
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { RectAreaLightHelper } from "three/examples/jsm/helpers/RectAreaLightHelper";

/**
 * 3d Material 材质
 * https://threejs.org/docs/index.html#api/zh/materials/LineBasicMaterial
 */
export class ThreeDoc7Material {
    constructor(canvasId) {
        this.work(canvasId);
    }

    work(canvasId) {
        // 创建 3d 场景
        const scene = new THREE.Scene();
        scene.background = new THREE.Color(0x9e9e9e);

        const renderer = new THREE.WebGLRenderer();
        renderer.setSize(window.innerWidth, window.innerHeight);
        // 最后一步很重要,我们将renderer(渲染器)的dom元素(renderer.domElement)添加到我们的HTML文档中。这就是渲染器用来显示场景给我们看的<canvas>元素。
        document.body.appendChild(renderer.domElement);

        // AxesHelper  3个坐标轴的对象.
        this.addAxesHelper(scene);

        // 添加几何体
        const geometry = new THREE.BoxGeometry(1, 1, 1);

        let material;
        // 基础线条材质(LineBasicMaterial) - 不受光照影响?
        material = this.getLineBasicMaterial();
        // 虚线材质(LineDashedMaterial) - 不受光照影响?
        material = this.getLineDashedMaterial();
        // 基础网格材质(MeshBasicMaterial) - 这种材质不受光照的影响。
        material = this.getMeshBasicMaterial();
        // 深度网格材质(MeshDepthMaterial)
        material = this.getMeshDepthMaterial();
        // MeshDistanceMaterial
        // material = this.getMeshDistanceMaterial();
        // Lambert网格材质(MeshLambertMaterial) - 一种非光泽表面的材质,没有镜面高光。
        material = this.getMeshLambertMaterial();
        // MeshMatcapMaterial
        material = this.getMeshMatcapMaterial();
        // 法线网格材质(MeshNormalMaterial)
        material = this.getMeshNormalMaterial();
        // Phong网格材质(MeshPhongMaterial)
        material = this.getMeshPhongMaterial();
        // 物理网格材质(MeshPhysicalMaterial)
        material = this.getMeshPhysicalMaterial();
        // 标准网格材质(MeshStandardMaterial)
        material = this.getMeshStandardMaterial();
        // MeshToonMaterial
        material = this.getMeshToonMaterial();
        // 点材质(PointsMaterial)
        this.getPointsMaterial(scene);
        // 原始着色器材质(RawShaderMaterial) - 需要额外 script 内容,参考 three.js  webgl_buffergeometry_rawshader.html
        // material = this.getRawShaderMaterial(scene);
        // 着色器材质(ShaderMaterial) - 类似上一个
        // 阴影材质(ShadowMaterial)
        this.getShadowMaterial(scene);
        // 点精灵材质(SpriteMaterial)
        this.getSpriteMaterial(scene);



        // 创建物体
        const dodecahedron = new THREE.Mesh(geometry, material);
        scene.add(dodecahedron);


        // 包围盒辅助线框对象
        // const box = new THREE.BoxHelper(dodecahedron, 0xffff00);
        // scene.add(box);

        // 半球光(HemisphereLight)
        this.addHemisphereLight(scene);
        // 平面光光源(RectAreaLight)
        this.addRectAreaLight(scene);

        const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
        // 设置相机位置
        camera.position.x = 10;
        camera.position.y = 10;
        camera.position.z = 10;
        // camera.lookAt(0, 0, 0);

        // 添加控制器
        let orb = new OrbitControls(camera, document.body);
        orb.addEventListener('change', function () {
            renderer.render(scene, camera);
        });

        renderer.render(scene, camera);
    }

    /**
     * AxesHelper
     * 用于简单模拟3个坐标轴的对象.
     * 红色代表 X 轴. 绿色代表 Y 轴. 蓝色代表 Z 轴.
     * AxesHelper( size : Number )
     * size -- (可选的) 表示代表轴的线段长度. 默认为 1.
     */
    addAxesHelper(scene) {
        const axesHelper = new THREE.AxesHelper(12);
        scene.add(axesHelper);
    }

    /**
     * 半球光(HemisphereLight) - 喜欢这个光
     * 光源直接放置于场景之上,光照颜色从天空光线颜色渐变到地面光线颜色。
     * 半球光不能投射阴影。
     *
     * HemisphereLight( skyColor : Integer, groundColor : Integer, intensity : Float )
     * skyColor - (可选参数) 天空中发出光线的颜色。 缺省值 0xffffff。
     * groundColor - (可选参数) 地面发出光线的颜色。 缺省值 0xffffff。
     * intensity - (可选参数) 光照强度。 缺省值 1。
     */
    addHemisphereLight(scene) {
        const light = new THREE.HemisphereLight(0xffffbb, 0x080820, 100);
        scene.add(light);
        light.position.set(0, -5, 0);
        const helper = new THREE.HemisphereLightHelper(light, 3);
        scene.add(helper);
    }

    /**
     * 平面光光源(RectAreaLight) - 这个光源也不错!
     * 平面光光源从一个矩形平面上均匀地发射光线。这种光源可以用来模拟像明亮的窗户或者条状灯光光源。
     * 注意事项:
     * 不支持阴影。
     * 只支持 MeshStandardMaterial 和 MeshPhysicalMaterial 两种材质。
     * 你必须在你的场景中加入 RectAreaLightUniformsLib ,并调用init()。
     *
     * RectAreaLight( color : Integer, intensity : Float, width : Float, height : Float )
     * color - (可选参数) 十六进制数字表示的光照颜色。缺省值为 0xffffff (白色)
     * intensity - (可选参数) 光源强度/亮度 。缺省值为 1。
     * width - (可选参数) 光源宽度。缺省值为 10。
     * height - (可选参数) 光源高度。缺省值为 10。
     */
    addRectAreaLight(scene) {
        const width = 20;
        const height = 10;
        const intensity = 100;
        const rectLight = new THREE.RectAreaLight(0xffffff, intensity, width, height);
        rectLight.position.set(5, 5, 0);
        rectLight.lookAt(0, 0, 0);
        scene.add(rectLight);

        let rectLightHelper = new RectAreaLightHelper(rectLight);
        scene.add(rectLightHelper);
    }

    /**
     * 基础线条材质(LineBasicMaterial) - 不受光照影响?
     * LineBasicMaterial( parameters : Object )
     * parameters - (可选)用于定义材质外观的对象,具有一个或多个属性。材质的任何属性都可以从此处传入(包括从Material继承的任何属性)。
     * 属性color例外,其可以作为十六进制字符串传递,默认情况下为 0xffffff(白色),内部调用Color.set(color)。
     * .color : Color
     * 材质的颜色(Color),默认值为白色 (0xffffff)。
     * .fog : Boolean
     * 材质是否受雾影响。默认为true。
     * .linewidth : Float
     * 控制线宽。默认值为 1。
     * 由于OpenGL Core Profile与 大多数平台上WebGL渲染器的限制,无论如何设置该值,线宽始终为1。
     * .linecap : String
     * 定义线两端的样式。可选值为 'butt', 'round' 和 'square'。默认值为 'round'。
     * 该属性对应2D Canvas lineCap属性, 并且会被WebGL渲染器忽略。
     * .linejoin : String
     * 定义线连接节点的样式。可选值为 'round', 'bevel' 和 'miter'。默认值为 'round'。
     */
    getLineBasicMaterial() {
        return new THREE.LineBasicMaterial({
            color: 0x00ffff,
            linewidth: 1,
            linecap: 'round', //ignored by WebGLRenderer
            linejoin: 'round' //ignored by WebGLRenderer
        });
    }

    /**
     * 虚线材质(LineDashedMaterial) - 不受光照影响?
     * LineDashedMaterial( parameters : Object )
     * parameters - (可选)用于定义材质外观的对象,具有一个或多个属性。材质的任何属性都可以从此处传入
     * (包括从LineBasicMaterial继承的任何属性)。
     * .dashSize : number
     * 虚线的大小,是指破折号和间隙之和。默认值为 3。
     * .gapSize : number
     * 间隙的大小,默认值为 1。
     * .isLineDashedMaterial : Boolean
     * Read-only flag to check if a given object is of type LineDashedMaterial.
     * .scale : number
     * 线条中虚线部分的占比。默认值为 1。
     */
    getLineDashedMaterial() {
        return new THREE.LineDashedMaterial({
            color: 0x00ffff,
            linewidth: 1,
            scale: 1,
            dashSize: 3,
            gapSize: 1,
        });
    }

    /**
     * 基础网格材质(MeshBasicMaterial)
     * 一个以简单着色(平面或线框)方式来绘制几何体的材质。
     * 这种材质不受光照的影响。
     * MeshBasicMaterial( parameters : Object )
     * parameters - (可选)用于定义材质外观的对象,具有一个或多个属性。材质的任何属性都可以从此处传入(包括从Material继承的任何属性)。
     * 属性color例外,其可以作为十六进制字符串传递,默认情况下为 0xffffff(白色),内部调用Color.set(color)。
     * .alphaMap : Texture
     * alpha贴图是一张灰度纹理,用于控制整个表面的不透明度。(黑色:完全透明;白色:完全不透明)。 默认值为null。
     * 仅使用纹理的颜色,忽略alpha通道(如果存在)。 对于RGB和RGBA纹理,WebGL渲染器在采样此纹理时将使用绿色通道, 因为在DXT压缩和未压缩RGB 565格式中为绿色提供了额外的精度。 Luminance-only以及luminance/alpha纹理也仍然有效。
     * .aoMap : Texture
     * 该纹理的红色通道用作环境遮挡贴图。默认值为null。aoMap需要第二组UV。
     * .aoMapIntensity : Float
     * 环境遮挡效果的强度。默认值为1。零是不遮挡效果。
     * .color : Color
     * 材质的颜色(Color),默认值为白色 (0xffffff)。
     * .combine : Integer
     * 如何将表面颜色的结果与环境贴图(如果有)结合起来。
     * 选项为THREE.MultiplyOperation(默认值),THREE.MixOperation, THREE.AddOperation。如果选择多个,则使用.reflectivity在两种颜色之间进行混合。
     * .envMap : Texture
     * 环境贴图。默认值为null。
     * .fog : Boolean
     * 材质是否受雾影响。默认为true。
     * .lightMap : Texture
     * 光照贴图。默认值为null。lightMap需要第二组UV。
     * .lightMapIntensity : Float
     * 烘焙光的强度。默认值为1。
     * .map : Texture
     * 颜色贴图。默认为null。
     * .reflectivity : Float
     * 环境贴图对表面的影响程度; 见.combine。默认值为1,有效范围介于0(无反射)和1(完全反射)之间。
     * .refractionRatio : Float
     * 空气的折射率(IOR)(约为1)除以材质的折射率。它与环境映射模式THREE.CubeRefractionMapping 和THREE.EquirectangularRefractionMapping一起使用。 The index of refraction (IOR) of air (approximately 1) divided by the index of refraction of the material. It is used with environment mapping mode THREE.CubeRefractionMapping. 折射率不应超过1。默认值为0.98。
     * .specularMap : Texture
     * 材质使用的高光贴图。默认值为null。
     * .wireframe : Boolean
     * 将几何体渲染为线框。默认值为false(即渲染为平面多边形)。
     * .wireframeLinecap : String
     * 定义线两端的外观。可选值为 'butt','round' 和 'square'。默认为'round'。
     * 该属性对应2D Canvas lineJoin属性, 并且会被WebGL渲染器忽略。
     * .wireframeLinejoin : String
     * 定义线连接节点的样式。可选值为 'round', 'bevel' 和 'miter'。默认值为 'round'。
     * 该属性对应2D Canvas lineJoin属性, 并且会被WebGL渲染器忽略。
     * .wireframeLinewidth : Float
     * 控制线框宽度。默认值为1。
     */
    getMeshBasicMaterial() {
        return new THREE.MeshBasicMaterial({
            color: 0x00ffff,
        });
    }

    /**
     * 深度网格材质(MeshDepthMaterial)
     * 一种按深度绘制几何体的材质。深度基于相机远近平面。白色最近,黑色最远。
     * MeshDepthMaterial( parameters : Object )
     * parameters - (可选)用于定义材质外观的对象,具有一个或多个属性。 材质的任何属性都可以从此处传入(包括从Material继承的任何属性)。
     * .alphaMap : Texture
     * alpha贴图是一张灰度纹理,用于控制整个表面的不透明度。(黑色:完全透明;白色:完全不透明)。 默认值为null。
     * 仅使用纹理的颜色,忽略alpha通道(如果存在)。 对于RGB和RGBA纹理,WebGL渲染器在采样此纹理时将使用绿色通道, 因为在DXT压缩和未压缩RGB 565格式中为绿色提供了额外的精度。 Luminance-only以及luminance/alpha纹理也仍然有效。
     * .depthPacking : Constant
     * depth packing的编码。默认为BasicDepthPacking。
     * .displacementMap : Texture
     * 位移贴图会影响网格顶点的位置,与仅影响材质的光照和阴影的其他贴图不同,移位的顶点可以投射阴影,阻挡其他对象,以及充当真实的几何体。 位移纹理是指:网格的所有顶点被映射为图像中每个像素的值(白色是最高的),并且被重定位。
     * .displacementScale : Float
     * 位移贴图对网格的影响程度(黑色是无位移,白色是最大位移)。如果没有设置位移贴图,则不会应用此值。默认值为1。
     * .displacementBias : Float
     * 位移贴图在网格顶点上的偏移量。如果没有设置位移贴图,则不会应用此值。默认值为0。
     * .map : Texture
     * 颜色贴图。默认为null。
     * .wireframe : Boolean
     * 将几何体渲染为线框。默认值为false(即渲染为平滑着色)。
     * .wireframeLinewidth : Float
     * 控制线框宽度。默认值为1。
     */
    getMeshDepthMaterial() {
        return new THREE.MeshDepthMaterial({
            color: 0xffffff,
        });
    }

    /**
     * Lambert网格材质(MeshLambertMaterial)
     * 一种非光泽表面的材质,没有镜面高光。
     *
     * 该材质使用基于非物理的Lambertian模型来计算反射率。 这可以很好地模拟一些表面(例如未经处理的木材或石材),但不能模拟具有镜面高光的光泽表面(例如涂漆木材)。
     * MeshLambertMaterial( parameters : Object )
     * parameters - (可选)用于定义材质外观的对象,具有一个或多个属性。 材质的任何属性都可以从此处传入(包括从Material继承的任何属性)。
     *
     * 属性color例外,其可以作为十六进制字符串传递,默认情况下为 0xffffff(白色),内部调用Color.set(color)。
     */
    getMeshLambertMaterial() {
        return new THREE.MeshDepthMaterial({
            color: 0x00ffff,
        });
    }

    /**
     * MeshMatcapMaterial
     * MeshMatcapMaterial 由一个材质捕捉(MatCap,或光照球(Lit Sphere))纹理所定义,其编码了材质的颜色与明暗。
     * MeshMatcapMaterial( parameters : Object )
     * parameters - (可选)用于定义材质外观的对象,具有一个或多个属性。 材质的任何属性都可以从此处传入(包括从Material继承的任何属性)。
     *
     * 属性color例外,其可以作为十六进制字符串传递,默认情况下为 0xffffff(白色),内部调用Color.set(color)。
     */
    getMeshMatcapMaterial() {
        return new THREE.MeshDepthMaterial({
            color: 0x00ffff,
        });
    }

    /**
     * 法线网格材质(MeshNormalMaterial)
     * 一种把法向量映射到RGB颜色的材质。
     * MeshNormalMaterial( parameters : Object )
     * parameters - (可选)用于定义材质外观的对象,具有一个或多个属性。材质的任何属性都可以从此处传入(包括从Material继承的任何属性)。
     */
    getMeshNormalMaterial() {
        return new THREE.MeshNormalMaterial({});
    }

    /**
     * Phong网格材质(MeshPhongMaterial)
     * 一种用于具有镜面高光的光泽表面的材质。
     * MeshPhongMaterial( parameters : Object )
     * parameters - (可选)用于定义材质外观的对象,具有一个或多个属性。 材质的任何属性都可以从此处传入(包括从Material继承的任何属性)。
     *
     * 属性color例外,其可以作为十六进制字符串传递,默认情况下为 0xffffff(白色),内部调用Color.set(color)。
     */
    getMeshPhongMaterial() {
        return new THREE.MeshPhongMaterial({
            color: 0x00ffff,
        });
    }

    /**
     * 物理网格材质(MeshPhysicalMaterial)
     * MeshStandardMaterial的扩展,提供了更高级的基于物理的渲染属性:
     *
     * Clearcoat: 有些类似于车漆,碳纤,被水打湿的表面的材质需要在面上再增加一个透明的,具有一定反光特性的面。而且这个面说不定有一定的起伏与粗糙度。Clearcoat可以在不需要重新创建一个透明的面的情况下做到类似的效果。
     * 基于物理的透明度:.opacity属性有一些限制:在透明度比较高的时候,反射也随之减少。使用基于物理的透光性.transmission属性可以让一些很薄的透明表面,例如玻璃,变得更真实一些。
     * 高级光线反射: 为非金属材质提供了更多更灵活的光线反射。
     * MeshPhysicalMaterial( parameters : Object )
     * parameters - (可选)用于定义材质外观的对象,具有一个或多个属性。 材质的任何属性都可以从此处传入(包括从Material和MeshStandardMaterial继承的任何属性)
     *
     * 属性color例外,其可以作为十六进制字符串传递,默认情况下为 0xffffff(白色),内部调用Color.set(color)。
     */
    getMeshPhysicalMaterial() {
        return new THREE.MeshPhysicalMaterial({
            color: 0x00ffff,
        });
    }

    /**
     * 标准网格材质(MeshStandardMaterial)
     * 一种基于物理的标准材质,使用Metallic-Roughness工作流程。
     *
     * 基于物理的渲染(PBR)最近已成为许多3D应用程序的标准,例如Unity, Unreal和 3D Studio Max。
     * MeshStandardMaterial( parameters : Object )
     * parameters - (可选)用于定义材质外观的对象,具有一个或多个属性。 材质的任何属性都可以从此处传入(包括从Material继承的任何属性)。
     *
     * 属性color例外,其可以作为十六进制字符串传递,默认情况下为 0xffffff(白色),内部调用Color.set(color)。
     */
    getMeshStandardMaterial() {
        return new THREE.MeshPhysicalMaterial({
            color: 0x049EF4,
        });
    }

    /**
     * MeshToonMaterial
     * A material implementing toon shading.
     * MeshToonMaterial( parameters : Object )
     * parameters - (optional) an object with one or more properties defining the material's appearance. Any property
     * of the material (including any property inherited from Material) can be passed in here.
     */
    getMeshToonMaterial() {
        return new THREE.MeshToonMaterial({
            color: 0x00ffff,
        });
    }

    /**
     * 点材质(PointsMaterial)
     * Points使用的默认材质。
     * PointsMaterial( parameters : Object )
     * parameters - (可选)用于定义材质外观的对象,具有一个或多个属性。 材质的任何属性都可以从此处传入(包括从Material继承的任何属性)。
     *
     * 属性color例外,其可以作为十六进制字符串传递,默认情况下为 0xffffff(白色),内部调用Color.set(color)。
     */
    getPointsMaterial(scene) {
        const vertices = [];
        for (let i = 0; i < 10000; i++) {
            const x = THREE.MathUtils.randFloatSpread(2000);
            const y = THREE.MathUtils.randFloatSpread(2000);
            const z = THREE.MathUtils.randFloatSpread(2000);
            vertices.push(x, y, z);
        }
        const geometry = new THREE.BufferGeometry();
        geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));
        const material = new THREE.PointsMaterial({ color: 0x000000 });
        const points = new THREE.Points(geometry, material);
        scene.add(points);
    }

    /**
     * 原始着色器材质(RawShaderMaterial)
     * 此类的工作方式与ShaderMaterial类似,不同之处在于内置的uniforms和attributes的定义不会自动添加到GLSL shader代码中。
     * RawShaderMaterial( parameters : Object )
     * parameters - (可选)用于定义材质外观的对象,具有一个或多个属性。 材质的任何属性都可以从此处传入(包括从Material 和 ShaderMaterial继承的任何属性)。
     */
    getRawShaderMaterial() {
        return new THREE.RawShaderMaterial({
            uniforms: {
                time: { value: 1.0 }
            },
            vertexShader: document.getElementById('vertexShader').textContent,
            fragmentShader: document.getElementById('fragmentShader').textContent,
        });
    }

    /**
     * 阴影材质(ShadowMaterial)
     * 此材质可以接收阴影,但在其他方面完全透明。
     * ShadowMaterial( parameters : Object )
     * parameters - (可选)用于定义材质外观的对象,具有一个或多个属性。 材质的任何属性都可以从此处传入(包括从Material继承的任何属性)。
     */
    getShadowMaterial(scene) {
        const geometry = new THREE.PlaneGeometry( 2000, 2000 );
        geometry.rotateX( - Math.PI / 2 );

        const material = new THREE.ShadowMaterial();
        material.opacity = 0.2;

        const plane = new THREE.Mesh( geometry, material );
        plane.receiveShadow = true;
        scene.add( plane );
    }

    /**
     * 点精灵材质(SpriteMaterial)
     * 一种使用Sprite的材质。
     * SpriteMaterial( parameters : Object )
     * parameters - (可选)用于定义材质外观的对象,具有一个或多个属性。 材质的任何属性都可以从此处传入(包括从Material 和 ShaderMaterial继承的任何属性)。
     *
     * 属性color例外,其可以作为十六进制字符串传递,默认情况下为 0xffffff(白色), 内部调用Color.set(color)。 SpriteMaterials不会被Material.clippingPlanes裁剪。
     */
    getSpriteMaterial(scene) {
        const map = new THREE.TextureLoader().load( 'assets/111.png' );
        const material = new THREE.SpriteMaterial( { map: map, color: 0xffffff } );

        const sprite = new THREE.Sprite( material );
        sprite.scale.set(200, 200, 0);
        scene.add( sprite );
    }
}

 

posted @ 2022-06-01 09:10  名字不好起啊  阅读(114)  评论(0编辑  收藏  举报