Мягкая тень имеет непреднамеренное смещение - PullRequest
1 голос
/ 13 марта 2019

В настоящее время я работаю над эффектом мягкой / размытой тени, который накладывается на плоскость прямо под моим объектом (просто для придания ему большей глубины).Источник света (DirectionalLight) имеет общие координаты центра объекта, но со смещением по Y, так что он находится прямо над ним.Он направлен вниз к центру объекта.

Я немного поэкспериментировал с параметрами тени света и обнаружил, что уменьшение размера карты теней дает мне довольно хороший эффект мягкой тени, которого было бы достаточнодля меня.Например:

light.shadow.mapSize.width = 32;
light.shadow.mapSize.height = 32;

Однако я заметил, что есть тень на тень, которая позволяет наблюдателю предположить, что источник света не исходит непосредственно сверху:

enter image description here

Я создал эту скрипку, из которой я создал изображение.В качестве типа тени я использую PCFSoftShadowMap.

При такой настройке я бы предположил, что эффект тени одинаково накладывается на все четыре стороны куба, но это явно не так.Я также заметил, что это «смещение» становится меньше при увеличении размера карты теней и едва заметно при использовании, например, таких размеров, как 512 или 1024.

Этот метод был бы простым и эффективным решением для желаемого эффекта,поэтому я действительно ценю любую помощь в этом

РЕДАКТИРОВАТЬ:

Как указано в комментариях, настройка радиуса LightShadow не является удовлетворительным решением, потому что теньградиент имеет жесткие края вместо мягких.

Ответы [ 2 ]

3 голосов
/ 13 марта 2019

Я думаю, что ваша карта теней имеет достаточно низкое разрешение, и вы видите ошибку округления.Если вы переключитесь обратно на THREE.BasicShadowMap, я думаю, вы увидите, что пиксели физической карты освещения, попадающие под удар, оказываются на той стороне объекта, которую вы видите большим краем, и когда вы перемещаете объект, тень будет двигатьсяшаг за шагом размер пикселей на карте.

Как правило, на практике вы хотите использовать карту освещения с более высоким разрешением и сохранять зону покрытия как можно ближе к фокальной точке вашей сцены, чтобы дать вамнаибольшее разрешение из карты освещения.Затем вы можете настроить .ради из LightShadow, чтобы получить нужную мягкость.

0 голосов
/ 14 марта 2019

Одно решение, которое я придумал, - это использование четырех источников света с очень небольшим позиционным смещением, чтобы «теневое смещение» приходило с четырех разных направлений (http://jsfiddle.net/683049eb/):

// a basic three.js scene

var container, renderer, scene, camera, controls, light, light2, light3, light4, cubeCenter, cube;

init();
animate();

function init() {

    // renderer
    renderer = new THREE.WebGLRenderer({
        antialias: true
    });
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.setClearColor(0xccccff);
    renderer.shadowMap.enabled = true;
    renderer.shadowMap.type = THREE.PCFSoftShadowMap;
    
    container = document.createElement('div');
    document.body.appendChild(container);
    container.appendChild(renderer.domElement);

    // scene
    scene = new THREE.Scene();

    // camera
    camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 10000);
    camera.position.set(0, 200, 800);
    camera.lookAt(scene.position);

    // (camera) controls
    // mouse controls: left button to rotate, 
    // mouse wheel to zoom, right button to pan
    controls = new THREE.OrbitControls(camera, renderer.domElement);

		var size = 100;
    
    // ambient light
    var ambient = new THREE.AmbientLight(0xffffff, 0.333);
    scene.add(ambient);

    // mesh
    var cubeGeometry = new THREE.BoxGeometry(size, size, size);
    var cubeMaterial = new THREE.MeshLambertMaterial({
        color: 0xff0000
    });
    
    cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
    cube.position.y = size / 2.0;
    cube.castShadow = true;
    cube.receiveShadow = false;
    scene.add(cube);
    
    // Get bounding box center
    var boundingBox = new THREE.Box3().setFromObject(cube);
    cubeCenter = new THREE.Vector3();
    boundingBox.getCenter(cubeCenter);
    
    var position1 = new THREE.Vector3(0, size * 2, 0.0000001);
    createDirectionalLight(scene, 0.15, position1, size, cubeCenter);
    var position2 = new THREE.Vector3(0, size * 2, -0.0000001);
    createDirectionalLight(scene, 0.15, position2, size, cubeCenter);
    var position3 = new THREE.Vector3(0.0000001, size * 2, 0);
    createDirectionalLight(scene, 0.15, position3, size, cubeCenter);
    var position4 = new THREE.Vector3(-0.0000001, size * 2, 0);
    createDirectionalLight(scene, 0.15, position4, size, cubeCenter);
    
		// shadow plane
    var planeGeometry = new THREE.PlaneGeometry(500, 500, 100, 100);
    var planeMaterial = new THREE.MeshLambertMaterial({
        // opacity: 0.6,
        color: 0x65bf32,
        side: THREE.FrontSide
    });
    var plane = new THREE.Mesh(planeGeometry, planeMaterial);
    plane.receiveShadow = true;
    plane.rotation.x = -Math.PI / 2;
    scene.add(plane);

    // events
    window.addEventListener('resize', onWindowResize, false);

}

function onWindowResize(event) {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
}

function animate() {
    controls.update();
    renderer.render(scene, camera);
    requestAnimationFrame(animate);
}

function createDirectionalLight(scene, intensity, position, cameraSize, targetPosition) {
    var light = new THREE.DirectionalLight(0xffffff, intensity);
    light.position.set(position.x, position.y, position.z);
    light.target.position.set(targetPosition.x, targetPosition.y, targetPosition.z);
    light.target.updateMatrixWorld(true);
    light.castShadow = true;
    scene.add(light);
    
    light.shadow.mapSize.width = 32;
    light.shadow.mapSize.height = 32;
    light.shadow.camera.left = -cameraSize;
    light.shadow.camera.right = cameraSize;
    light.shadow.camera.bottom = -cameraSize;
    light.shadow.camera.top = cameraSize;
    light.shadow.camera.near = 1.0;
    light.shadow.camera.far = cameraSize * 3;
    light.shadow.bias = 0.0001;
    scene.add(new THREE.CameraHelper(light.shadow.camera));
}
<script src="http://threejs.org/build/three.js"></script>
<script src="http://threejs.org/examples/js/controls/OrbitControls.js"></script>

enter image description here

...