three MeshDistanceMaterial 阴影生成材质

81 阅读2分钟

在阴影映射材质中,alphaMap map displacementMap 程现的效果没有什么大的区别就是用来对光照进行一定程序的遮挡,一般这个材质在内部使用,还有一种用法可以在材质在使用下面给出了使用示例并将three中官网的属性注解进行了描述

MeshDistanceMaterial 阴影映射材质 五个属性

  • alphaMap alpha贴图是一张灰度纹理,用于控制整个表面的不透明度。(黑色:完全透明;白色:完全不透明)。 默认值为null。
  • displacementMap 位移贴图会影响网格顶点的位置,与仅影响材质的光照和阴影的其他贴图不同,移位的顶点可以投射阴影,阻挡其他对象,以及充当真实的几何体。 位移纹理是指:网格的所有顶点被映射为图像中每个像素的值(白色是最高的),并且被重定位。
  • displacementScale 位移贴图对网格的影响程度(黑色是无位移,白色是最大位移)。如果没有设置位移贴图,则不会应用此值。默认值为1。
  • displacementBias 位移贴图在网格顶点上的偏移量。如果没有设置位移贴图,则不会应用此值。默认值为0。
  • map 颜色贴图。可以选择包括一个alpha通道,通常与.transparent 或.alphaTest。默认为null。
<template>
    <div id="parkingLot" ref="parkingLot">
    </div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from "vue";
import * as THREE from 'three';
import imgPng from "@public/person.jpg"
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
const parkingLot = ref();

onMounted(() => {
    const DOMEl = parkingLot.value;
    // 获取 DOMEl 的宽度和高度,以设置渲染器的大小。
    const width = DOMEl.clientWidth;
    const height = DOMEl.clientHeight;

    const renderer = new THREE.WebGLRenderer({ antialias: true });
    renderer.setSize( width, height );
    renderer.shadowMap.enabled = true; // 启用阴影映射
    renderer.shadowMap.type = THREE.PCFSoftShadowMap; // 选择阴影类型
    DOMEl.appendChild( renderer.domElement );
    const scene = new THREE.Scene();
    const camera = new THREE.PerspectiveCamera( 75, width / height, 0.1, 1000 );
    camera.position.set( 0, 80, 0 );
    camera.lookAt( 0, 0, 0 );

    const geometryCube = new THREE.BoxGeometry( 30, 30, 30 );
    const materialCube = new THREE.MeshPhongMaterial( {
        color: 0xffffff,
        shininess: 10,
        specular: 0x111111,
        side: THREE.BackSide
    } );

    // 创建点光源并启用阴影
    const pointLight = new THREE.PointLight(0x0000ff, 1000, 500);
    pointLight.position.set(0, 0, 0);  // 调整光源位置
    pointLight.castShadow = true;

    // 0.6 为物体半径 当物体半径为1时产生的遮挡就越大,否则越小为0无遮挡
    let geometry = new THREE.SphereGeometry( 0.6, 12, 6 );
    let material = new THREE.MeshBasicMaterial( { color: 0xff0000,opacity: 0.5 } );
    let sphere = new THREE.Mesh( geometry, material );
    // 产生投影
    sphere.castShadow = true;
    // 接收投影
    sphere.receiveShadow = true;
    pointLight.add( sphere );
    
    // 创建自定义的 MeshDistanceMaterial
    const distanceMaterial = new THREE.MeshDistanceMaterial({
        depthTest: true,
        transparent: true,
    });

    // 加载位移贴图
    distanceMaterial.displacementMap = new THREE.TextureLoader().load(imgPng);
    distanceMaterial.displacementScale = 0.5;
    distanceMaterial.displacementBias = 0.1;
    // 将 MeshDistanceMaterial 指定给自定义材质以确保阴影处理
    sphere.customDistanceMaterial = distanceMaterial;
    // 场景中添加灯光
    scene.add( pointLight );


    const meshCube = new THREE.Mesh( geometryCube, materialCube );
    // 接收投影
    meshCube.receiveShadow = true;
    // 产生投影
    meshCube.castShadow = true;
    scene.add( meshCube );

    const helper = new THREE.BoxHelper( meshCube, 0xffff00 );
    scene.add( helper );

    // 创建 OrbitControls
    const controls = new OrbitControls(camera, renderer.domElement);
    // 渲染循环
    function animate() {
        requestAnimationFrame(animate);
        controls.update();
        renderer.render(scene, camera);
    }
    animate();
});
</script>
<style lang="scss" scoped="scoped">

    #parkingLot {
        width: 940px;
        height: 940px;
        border: 1px solid #ccc;
        margin: 30px auto;
    }

</style>