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

mar*_*rks 5 javascript shader vector glsl three.js

我正在向场景中添加一架飞机,如下所示:

// 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);
Run Code Online (Sandbox Code Playgroud)

很基本。我不是试图找出如何在 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);
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

所以现在我知道在我的着色器中我可以向 Z 添加多少来使平面填充视口。顶点着色器看起来像这样:

uniform float uZMax;

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

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

在此处输入图片说明

我想知道为什么我的数学是指 Y 轴以及我需要如何转换它,所以平面将填充视口宽度而不是高度?

编辑:

我正在尝试实现这样的东西https://tympanus.net/Tutorials/GridToFullscreenAnimations/index4.html - 但在给定的例子中,他们只是缩放 x 和 y 像素以填充屏幕,因此没有实际3d - 因此再次没有照明正在进行。

我想使用不同的 z 值实际将平面移向相机,以便我可以计算表面法线,然后通过法线与光方向的对齐方式再次计算片段着色器中的照明 - 就像它在光线行进中完成的那样。

Mug*_*n87 6

您可以通过使用以下设置轻松实现这样的全屏效果:

const camera = new THREE.OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );

const geometry = new THREE.PlaneBufferGeometry( 2, 2 );
Run Code Online (Sandbox Code Playgroud)

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


mar*_*rks 5

我想通了,正如怀疑的那样,这与传递给相机的长宽比有关。对于在我之后寻找解决方案的人来说,它的工作原理如下:

我错误地认为相机的视场在所有方向上都是相同的。但 FOV 指的是 Y 轴 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;

}
Run Code Online (Sandbox Code Playgroud)

然后我们只需在计算中使用该角度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);
Run Code Online (Sandbox Code Playgroud)