playcanvas
Version:
Open-source WebGL/WebGPU 3D engine for the web
83 lines (65 loc) • 2.69 kB
JavaScript
var skybox_default = (
/* wgsl */
`
// Attribute
attribute aPosition : vec4f;
uniform matrix_view : mat4x4f;
uniform matrix_projectionSkybox : mat4x4f;
uniform cubeMapRotationMatrix : mat3x3f;
varying vViewDir : vec3f;
varying vClipXYW : vec3f;
// when skydome renders depth during prepass, generate linear depth
varying vLinearDepth: f32;
uniform matrix_model : mat4x4f;
varying vWorldPos : vec3f;
@vertex
fn vertexMain(input : VertexInput) -> VertexOutput {
var output : VertexOutput;
var view : mat4x4f = uniform.matrix_view;
var worldPos : vec4f = uniform.matrix_model * input.aPosition;
output.vWorldPos = worldPos.xyz;
output.position = uniform.matrix_projectionSkybox * (view * worldPos);
// linear depth from the worldPosition, see getLinearDepth
output.vLinearDepth = -(uniform.matrix_view * vec4f(worldPos.xyz, 1.0)).z;
view[3][0] = 0.0;
view[3][1] = 0.0;
view[3][2] = 0.0;
output.vViewDir = input.aPosition.xyz * uniform.cubeMapRotationMatrix;
// Bypass matrix_projectionSkybox which degenerates at extreme FOVs.
// Use a fixed ~90\xB0 perspective (p00=p11=1) so the box always covers the
// screen. The fragment shader recomputes view direction from screen
// coordinates, so only rasterization coverage matters here.
var viewPos : vec4f = view * input.aPosition;
output.position = vec4f(viewPos.xy, 0.0, -viewPos.z);
output.vClipXYW = vec3f(output.position.xy, output.position.w);
output.position = uniform.matrix_projectionSkybox * (view * input.aPosition);
// for infinite skybox, use negative gl_Position.w to get positive linear depth
output.vLinearDepth = -pcPosition.w;
// Force skybox to far Z, regardless of the clip planes on the camera
// Subtract a tiny fudge factor to ensure floating point errors don't
// still push pixels beyond far Z. See:
// https://community.khronos.org/t/skybox-problem/61857
output.position.z = output.position.w - 1.0e-7;
return output;
}
`
);
export {
skybox_default as default
};