Fix issues when rendering panoramic sky in stereoscopic

This commit is contained in:
Bastiaan Olij 2017-10-09 23:27:20 +11:00 committed by BastiaanOlij
parent 18d3ba0c50
commit 179f483782
2 changed files with 64 additions and 27 deletions

View file

@ -2349,22 +2349,7 @@ void RasterizerSceneGLES3::_draw_sky(RasterizerStorageGLES3::Sky *p_sky, const C
glDepthFunc(GL_LEQUAL);
glColorMask(1, 1, 1, 1);
float flip_sign = p_vflip ? -1 : 1;
Vector3 vertices[8] = {
Vector3(-1, -1 * flip_sign, 1),
Vector3(0, 1, 0),
Vector3(1, -1 * flip_sign, 1),
Vector3(1, 1, 0),
Vector3(1, 1 * flip_sign, 1),
Vector3(1, 0, 0),
Vector3(-1, 1 * flip_sign, 1),
Vector3(0, 0, 0)
};
//sky uv vectors
float vw, vh, zn;
// Camera
CameraMatrix camera;
if (p_custom_fov) {
@ -2379,17 +2364,39 @@ void RasterizerSceneGLES3::_draw_sky(RasterizerStorageGLES3::Sky *p_sky, const C
camera = p_projection;
}
camera.get_viewport_size(vw, vh);
zn = p_projection.get_z_near();
float flip_sign = p_vflip ? -1 : 1;
for (int i = 0; i < 4; i++) {
/*
If matrix[2][0] or matrix[2][1] we're dealing with an asymmetrical projection matrix. This is the case for stereoscopic rendering (i.e. VR).
To ensure the image rendered is perspective correct we need to move some logic into the shader. For this the USE_ASYM_PANO option is introduced.
It also means the uv coordinates are ignored in this mode and we don't need our loop.
*/
bool asymmetrical = ((camera.matrix[2][0] != 0.0) || (camera.matrix[2][1] != 0.0));
Vector3 uv = vertices[i * 2 + 1];
uv.x = (uv.x * 2.0 - 1.0) * vw;
uv.y = -(uv.y * 2.0 - 1.0) * vh;
uv.z = -zn;
vertices[i * 2 + 1] = p_transform.basis.xform(uv).normalized();
vertices[i * 2 + 1].z = -vertices[i * 2 + 1].z;
Vector3 vertices[8] = {
Vector3(-1, -1 * flip_sign, 1),
Vector3(0, 1, 0),
Vector3(1, -1 * flip_sign, 1),
Vector3(1, 1, 0),
Vector3(1, 1 * flip_sign, 1),
Vector3(1, 0, 0),
Vector3(-1, 1 * flip_sign, 1),
Vector3(0, 0, 0)
};
if (!asymmetrical) {
float vw, vh, zn;
camera.get_viewport_size(vw, vh);
zn = p_projection.get_z_near();
for (int i = 0; i < 4; i++) {
Vector3 uv = vertices[i * 2 + 1];
uv.x = (uv.x * 2.0 - 1.0) * vw;
uv.y = -(uv.y * 2.0 - 1.0) * vh;
uv.z = -zn;
vertices[i * 2 + 1] = p_transform.basis.xform(uv).normalized();
vertices[i * 2 + 1].z = -vertices[i * 2 + 1].z;
}
}
glBindBuffer(GL_ARRAY_BUFFER, state.sky_verts);
@ -2398,16 +2405,24 @@ void RasterizerSceneGLES3::_draw_sky(RasterizerStorageGLES3::Sky *p_sky, const C
glBindVertexArray(state.sky_array);
storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_PANORAMA, true);
storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_ASYM_PANO, asymmetrical);
storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_PANORAMA, !asymmetrical);
storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_MULTIPLIER, true);
storage->shaders.copy.bind();
storage->shaders.copy.set_uniform(CopyShaderGLES3::MULTIPLIER, p_energy);
if (asymmetrical) {
// pack the bits we need from our projection matrix
storage->shaders.copy.set_uniform(CopyShaderGLES3::ASYM_PROJ, camera.matrix[2][0], camera.matrix[0][0], camera.matrix[2][1], camera.matrix[1][1]);
///@TODO I couldn't get mat3 + p_transform.basis to work, that would be better here.
storage->shaders.copy.set_uniform(CopyShaderGLES3::PANO_TRANSFORM, p_transform);
}
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glBindVertexArray(0);
glColorMask(1, 1, 1, 1);
storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_ASYM_PANO, false);
storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_MULTIPLIER, false);
storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_PANORAMA, false);
}

View file

@ -27,6 +27,8 @@ void main() {
#if defined(USE_CUBEMAP) || defined(USE_PANORAMA)
cube_interp = cube_in;
#elif defined(USE_ASYM_PANO)
uv_interp = vertex_attrib.xy;
#else
uv_interp = uv_in;
#ifdef V_FLIP
@ -59,6 +61,11 @@ in vec3 cube_interp;
in vec2 uv_interp;
#endif
#ifdef USE_ASYM_PANO
uniform highp mat4 pano_transform;
uniform highp vec4 asym_proj;
#endif
#ifdef USE_CUBEMAP
uniform samplerCube source_cube; //texunit:0
#else
@ -70,7 +77,7 @@ uniform sampler2D source; //texunit:0
uniform float multiplier;
#endif
#ifdef USE_PANORAMA
#if defined(USE_PANORAMA) || defined(USE_ASYM_PANO)
vec4 texturePanorama(vec3 normal,sampler2D pano ) {
@ -122,6 +129,21 @@ void main() {
vec4 color = texturePanorama( normalize(cube_interp), source );
#elif defined(USE_ASYM_PANO)
// When an assymetrical projection matrix is used (applicable for stereoscopic rendering i.e. VR) we need to do this calculation per fragment to get a perspective correct result.
// Note that we're ignoring the x-offset for IPD, with Z sufficiently in the distance it becomes neglectible, as a result we could probably just set cube_normal.z to -1.
// The Matrix[2][0] (= asym_proj.x) and Matrix[2][1] (= asym_proj.z) values are what provide the right shift in the image.
vec3 cube_normal;
cube_normal.z = -1000000.0;
cube_normal.x = (cube_normal.z * (-uv_interp.x - asym_proj.x)) / asym_proj.y;
cube_normal.y = (cube_normal.z * (-uv_interp.y - asym_proj.z)) / asym_proj.a;
cube_normal = mat3(pano_transform) * cube_normal;
cube_normal.z = -cube_normal.z;
vec4 color = texturePanorama( normalize(cube_normal.xyz), source );
#elif defined(USE_CUBEMAP)
vec4 color = texture( source_cube, normalize(cube_interp) );