THREE.js Вторичная камера вращается с вращением головы в VR - PullRequest
0 голосов
/ 06 января 2019

Я использую THREE.js и Aframe (в Exokit) вместе, и у меня есть компонент для «селфи камеры». У меня странная проблема: когда я вхожу в виртуальную реальность, вращение камеры переключается на вращение головы. Я понимаю, как вращение камеры изменилось в последних версиях THREE.js (ArrayCamera), но я предположил, что это влияет только на основную камеру, а не на все камеры в сцене.

Ниже приведен мой хакерский компонент, который отлично работает в 2D-режиме, но в VR он не работает. Хуже всего то, что он хорошо связан с головкой, сама камера в любом случае является дочерним объектом основной камеры, поэтому при открытии она появляется перед лицом пользователя и перемещается при вращении головы - но она выключена. угол, когда в VR, как его направление вниз и влево немного.

Вот несколько скриншотов, которые, как мы надеемся, демонстрируют проблему:

Редактировать: нужно 10 повторений, чтобы публиковать изображения, поэтому здесь вместо URL-адресов

Режим 2D

Режим VR

Любая помощь высоко ценится!

AFRAME.registerComponent('selfie-camera', {
    schema:{
        resolution:{type:'int',default:512},
        fov:{type:'int',default:100},
        aspect:{type:'number',default:1.5},
        near:{type:'number',default:0.001},
        far:{type:'number',default:1000}
    },
    init() {
        this.el.addEventListener('loaded',()=>{
            this.renderTarget = new THREE.WebGLRenderTarget(this.data.resolution*1.5, this.data.resolution,{ antialias: true });
            this.el.getObject3D('mesh').material.map = this.renderTarget.texture;
            this.cameraContainer = new THREE.Object3D();
            this.el.object3D.add( this.cameraContainer );
            this.el.takePicture = this.takePicture.bind(this);
            this.el.setSide = this.setSide.bind(this);
            this.wider = 1.5;
            this.photoMultiplier = 2;
            this.canvas = document.createElement('canvas');
        });
        this.testQuat = new THREE.Quaternion();
        this.el.open = this.open.bind(this);
        this.el.close = this.close.bind(this);
    },
    open(){
        this.camera = new THREE.PerspectiveCamera( this.data.fov, this.data.aspect, this.data.near, this.data.far );
        this.cameraContainer.add(this.camera);
        new TWEEN.Tween(this.el.getAttribute('scale'))
            .to(new THREE.Vector3(1,1,1), 650)
            .easing(TWEEN.Easing.Exponential.Out).start();
    },
    close(){
        new TWEEN.Tween(this.el.getAttribute('scale'))
            .to(new THREE.Vector3(0.0000001,0.0000001,0.0000001), 200)
            .onComplete(()=>{
                this.cameraContainer.remove(this.camera);
                delete this.camera;
            })
            .easing(TWEEN.Easing.Exponential.Out).start();
    },
    tick(){
        if(this.camera){
            this.camera.getWorldQuaternion(this.testQuat);
            console.log(this.camera.quaternion);
        }
        this.el.getObject3D('mesh').material.visible = false;
        if(this.isTakingPicture) {
            this.renderTarget.setSize(this.data.resolution * this.wider * this.photoMultiplier, this.data.resolution * this.photoMultiplier);
        }
        this.el.sceneEl.renderer.render( this.el.sceneEl.object3D, this.camera, this.renderTarget );
        if(this.isTakingPicture){
            this.isTakingPicture = false;
            this.pictureResolve(this.createImageFromTexture());
            this.renderTarget.setSize(this.data.resolution * this.wider, this.data.resolution);
        }
        this.el.getObject3D('mesh').material.visible = true;
    },
    setSide(isFront){
        let _this = this;
        new TWEEN.Tween({y:this.cameraContainer.rotation.y})
            .to({y:isFront?Math.PI:0}, 350)
            .onUpdate(function(){
                _this.cameraContainer.rotation.y = this.y;
            })
            .easing(TWEEN.Easing.Exponential.Out).start();
    },
    takePicture(){
        return new Promise(resolve=>{
            this.isTakingPicture = true;
            this.pictureResolve = resolve;
        })
    },
    createImageFromTexture() {
        let width = this.data.resolution*this.wider*this.photoMultiplier,
            height = this.data.resolution*this.photoMultiplier;
        let pixels = new Uint8Array(4 * width * height);
        this.el.sceneEl.renderer.readRenderTargetPixels(this.renderTarget, 0, 0, width, height, pixels);
        pixels = this.flipPixelsVertically(pixels, width, height);
        let imageData = new ImageData(new Uint8ClampedArray(pixels), width, height);

        this.canvas.width = width;
        this.canvas.height = height;
        let context = this.canvas.getContext('2d');

        context.putImageData(imageData, 0, 0);
        return this.canvas.toDataURL('image/jpeg',100);
    },
    flipPixelsVertically: function (pixels, width, height) {
        let flippedPixels = pixels.slice(0);
        for (let x = 0; x < width; ++x) {
            for (let y = 0; y < height; ++y) {
                flippedPixels[x * 4 + y * width * 4] = pixels[x * 4 + (height - y) * width * 4];
                flippedPixels[x * 4 + 1 + y * width * 4] = pixels[x * 4 + 1 + (height - y) * width * 4];
                flippedPixels[x * 4 + 2 + y * width * 4] = pixels[x * 4 + 2 + (height - y) * width * 4];
                flippedPixels[x * 4 + 3 + y * width * 4] = pixels[x * 4 + 3 + (height - y) * width * 4];
            }
        }
        return flippedPixels;
    }
});

1 Ответ

0 голосов
/ 07 января 2019

Вы должны отключить VR перед рендерингом:

var renderer = this.el.sceneEl.renderer;
var vrEnabled = renderer.vr.enabled;
renderer.vr.enabled = false;
renderer.render(this.el.sceneEl.object3D, this.camera, this.renderTarget);
renderer.vr.enabled = vrEnabled;
...