THREE.js辅助摄像机随着VR中的头部旋转而旋转

时间:2019-01-06 10:29:38

标签: three.js camera aframe

我一起使用THREE.js和Aframe(在Exokit中),并且有一个用于“自拍相机”的组件。我有一个奇怪的问题,当我进入VR时,摄像头旋转由头部旋转接管。我了解相机的旋转方式在THREE.js(ArrayCamera)的最新版本中已发生了变化,但我认为这仅影响主相机,而不影响场景中的所有相机。

下面是我的hacky组件,在2D模式下可以正常工作,但在VR中会混乱。最糟糕的事情是它与头部相连是很好的,照相机本身还是主照相机的子对象,因此打开时它会出现在用户面部的前面,并随着头部旋转而移动-但它会关闭在VR中的角度,例如其指向下方和向左一点。

以下是一些有望证明该问题的屏幕截图:

编辑:需要10个代表才能发布图片,因此这里是网址

2D Mode

VR Mode

非常感谢任何帮助!

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 :(得分:0)

渲染之前必须禁用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;