Three.js - 将平面缩放至全屏

7
我这样向场景中添加一个飞机:
// Camera
this.three.camera = new THREE.PerspectiveCamera(45, window.innerWidth/window.innerHeight, 0.1, 60);
// Plane
const planeGeometry = new THREE.PlaneBufferGeometry(1,1,this.options.planeSegments,this.options.planeSegments);
const planeMat = new THREE.ShaderMaterial( ... )
this.three.plane = new THREE.Mesh(planeGeometry,planeMat);
this.three.scene.add(this.three.plane);

基本的操作。我正在尝试找出如何在Z轴上移动平面以填充浏览器视口。为此,
// See attachment "solving for this" is closeZ
const closeZ = 0.5 / Math.tan((this.three.camera.fov/2.0) * Math.PI / 180.0);
this.uniforms.uZMax = new THREE.Uniform(this.three.camera.position.z - closeZ);

enter image description here

现在我知道在我的着色器中,我可以添加多少Z值来使平面填满视口。顶点着色器如下:

uniform float uZMax;

void main() {   
    vec3 pos = (position.xy, uZMax);
    gl_Position = projectionMatrix * modelViewMatrix * vec4( pos, 1 );
}

这实际上是将平面放大以填充视口,但是在Y轴上而不是X轴上。

enter image description here

我想了解为什么我的数学是参考Y轴的,以及如何进行转换,使平面填充视口宽度而不是高度?
编辑:
我想实现类似于这个https://tympanus.net/Tutorials/GridToFullscreenAnimations/index4.html的效果。但是在给定的示例中,他们只是缩放x和y像素以填充屏幕,因此没有实际的3D - 因此也没有发生任何光照。
我想实际上使用不同的z值将平面向相机移动,以便我可以计算表面法线,然后再通过片段着色器计算光照,方法是根据法线与光方向的对齐程度来计算,就像在射线追踪中所做的那样。

this.uniforms.uZMax = ..., seems it has to be this.uniforms.uZMax.value = ... - prisoner849
1
确实,如果您不使用 new THREE.Uniform 构造函数,那是正确的。但是 Three Uniform 类会负责添加具有正确参数的对象。 - marks
1
啊,没错 :) 我的错。 - prisoner849
2个回答

6
你可以通过以下设置轻松实现全屏效果:
const camera = new THREE.OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );

const geometry = new THREE.PlaneBufferGeometry( 2, 2 );

使用此几何体和自定义着色器材质创建网格时,正交相机将确保预期的全屏效果。这种方法在所有后处理示例中都使用,其中整个视口必须填充一个单一的四边形。


谢谢,但我实际上正在尝试用飞机替换点击的图像,然后将其缩放到全屏以获得网格全屏效果。虽然我可能会尝试使用正交方法进行翻转,但我仍然对如何将数学引用到x轴感兴趣。有任何想法吗? - marks

5

我弄清楚了,正如我所猜测的,这与传递给相机的纵横比有关。对于那些在我之后寻找解决方案的人,以下是它的工作原理:

我错误地认为相机的视场范围在所有方向上都相同。但是FOV指的是Y轴FOV,因此我们还必须将相机FOV转换为X轴:

function getXFOV() {
        // Convert angle to radiant
        const FOV = this.three.camera.fov;
        let yFovRadiant = FOV * Math.PI/180;
        // Calculate X-FOV Radiant
        let xFovRadiant = 2 * Math.atan( Math.tan(yFovRadiant/2) * (window.innerWidth / window.innerHeight));
        // Convert back to angle
        let xFovAngle = xFovRadiant * 180/Math.PI;
        return xFovAngle;

}

然后我们只需将该角度用于closeZ计算,而不是相机的视场角。现在它会自动对齐到窗口宽度。

const closeZ = 0.5 / Math.tan((this.getXFOV()) * Math.PI / 180.0);
this.uniforms.uZMax = new THREE.Uniform(this.three.camera.position.z - closeZ);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接