From 0efc684992f44fadd687de16a90984b5225f7671 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 11 Jul 2016 14:19:27 -0700 Subject: [PATCH 1/2] Add glow to the termination point of UI pointers --- .../display-plugins/hmd/HmdDisplayPlugin.cpp | 253 ++++++++++++++++-- .../display-plugins/hmd/HmdDisplayPlugin.h | 18 ++ 2 files changed, 244 insertions(+), 27 deletions(-) diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp index c2497e5740..2dc7df341a 100644 --- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp @@ -12,6 +12,8 @@ #include #include +#include +#include #include #include @@ -34,6 +36,9 @@ static const QString REPROJECTION = "Allow Reprojection"; static const QString FRAMERATE = DisplayPlugin::MENU_PATH() + ">Framerate"; static const QString DEVELOPER_MENU_PATH = "Developer>" + DisplayPlugin::MENU_PATH(); static const bool DEFAULT_MONO_VIEW = true; +static const int NUMBER_OF_HANDS = 2; +static const glm::mat4 IDENTITY_MATRIX; + glm::uvec2 HmdDisplayPlugin::getRecommendedUiSize() const { return CompositorHelper::VIRTUAL_SCREEN_SIZE; @@ -241,6 +246,9 @@ void main() { )VS"; +static const char * LASER_GS = R"GS( +)GS"; + static const char * LASER_FS = R"FS(#version 410 core uniform vec4 color = vec4(1.0, 1.0, 1.0, 1.0); @@ -254,6 +262,85 @@ void main() { )FS"; + +static const char * LASER_GLOW_VS = R"VS(#version 410 core + +uniform mat4 mvp = mat4(1); + +in vec3 Position; +in vec2 TexCoord; + +out vec3 vPosition; +out vec2 vTexCoord; + +void main() { + gl_Position = mvp * vec4(Position, 1); + vTexCoord = TexCoord; + vPosition = Position; +} + +)VS"; + +static const char * LASER_GLOW_FS = R"FS(#version 410 core +#line 286 +uniform sampler2D sampler; +uniform float alpha = 1.0; +uniform vec4 glowPoints = vec4(-1); +uniform vec4 glowColor1 = vec4(0.01, 0.7, 0.9, 1.0); +uniform vec4 glowColor2 = vec4(0.9, 0.7, 0.01, 1.0); +uniform vec2 resolution = vec2(3960.0, 1188.0); +uniform float radius = 0.005; + +in vec3 vPosition; +in vec2 vTexCoord; +in vec4 vGlowPoints; + +out vec4 FragColor; + +float easeInOutCubic(float f) { + const float d = 1.0; + const float b = 0.0; + const float c = 1.0; + float t = f; + if ((t /= d / 2.0) < 1.0) return c / 2.0 * t * t * t + b; + return c / 2.0 * ((t -= 2.0) * t * t + 2.0) + b; +} + +void main() { + vec2 aspect = resolution; + aspect /= resolution.x; + FragColor = texture(sampler, vTexCoord); + + float glowIntensity = 0.0; + float dist1 = distance(vTexCoord * aspect, glowPoints.xy * aspect); + float dist2 = distance(vTexCoord * aspect, glowPoints.zw * aspect); + float dist = min(dist1, dist2); + vec3 glowColor = glowColor1.rgb; + if (dist2 < dist1) { + glowColor = glowColor2.rgb; + } + + if (dist <= radius) { + glowIntensity = 1.0 - (dist / radius); + glowColor.rgb = pow(glowColor, vec3(1.0 - glowIntensity)); + glowIntensity = easeInOutCubic(glowIntensity); + glowIntensity = pow(glowIntensity, 0.5); + } + + if (alpha <= 0.0) { + if (glowIntensity <= 0.0) { + discard; + } + + FragColor = vec4(glowColor, glowIntensity); + return; + } + + FragColor.rgb = mix(FragColor.rgb, glowColor.rgb, glowIntensity); + FragColor.a *= alpha; +} +)FS"; + void HmdDisplayPlugin::customizeContext() { Parent::customizeContext(); // Only enable mirroring if we know vsync is disabled @@ -263,7 +350,6 @@ void HmdDisplayPlugin::customizeContext() { #endif _enablePreview = !isVsyncEnabled(); _sphereSection = loadSphereSection(_program, CompositorHelper::VIRTUAL_UI_TARGET_FOV.y, CompositorHelper::VIRTUAL_UI_ASPECT_RATIO); - using namespace oglplus; if (!_enablePreview) { const std::string version("#version 410 core\n"); @@ -271,6 +357,7 @@ void HmdDisplayPlugin::customizeContext() { PREVIEW_TEXTURE_LOCATION = Uniform(*_previewProgram, "colorMap").Location(); } + updateGlowProgram(); compileProgram(_laserProgram, LASER_VS, LASER_FS); _laserGeometry = loadLaser(_laserProgram); @@ -280,7 +367,67 @@ void HmdDisplayPlugin::customizeContext() { PROJECTION_MATRIX_LOCATION = Uniform(*_reprojectionProgram, "projections").Location(); } +#if 0 +static QString readFile(const char* filename) { + QFile file(filename); + file.open(QFile::Text | QFile::ReadOnly); + QString result; + result.append(QTextStream(&file).readAll()); + return result; +} +#endif + + +void HmdDisplayPlugin::updateGlowProgram() { +#if 0 + static qint64 vsBuiltAge = 0; + static qint64 fsBuiltAge = 0; + static const char* vsFile = "H:/glow_vert.glsl"; + static const char* fsFile = "H:/glow_frag.glsl"; + QFileInfo vsInfo(vsFile); + QFileInfo fsInfo(fsFile); + auto vsAge = vsInfo.lastModified().toMSecsSinceEpoch(); + auto fsAge = fsInfo.lastModified().toMSecsSinceEpoch(); + if (!_overlayProgram || vsAge > vsBuiltAge || fsAge > fsBuiltAge) { + QString vsSource = readFile(vsFile); + QString fsSource = readFile(fsFile); + ProgramPtr newOverlayProgram; + compileProgram(newOverlayProgram, vsSource.toLocal8Bit().toStdString(), fsSource.toLocal8Bit().toStdString()); + if (newOverlayProgram) { + using namespace oglplus; + _overlayProgram = newOverlayProgram; + auto uniforms = _overlayProgram->ActiveUniforms(); + _overlayUniforms.mvp = Uniform(*_overlayProgram, "mvp").Location(); + _overlayUniforms.alpha = Uniform(*_overlayProgram, "alpha").Location(); + _overlayUniforms.glowPoints = Uniform(*_overlayProgram, "glowPoints").Location(); + _overlayUniforms.resolution = Uniform(*_overlayProgram, "resolution").Location(); + _overlayUniforms.radius = Uniform(*_overlayProgram, "radius").Location(); + useProgram(_overlayProgram); + Uniform(*_overlayProgram, _overlayUniforms.resolution).Set(CompositorHelper::VIRTUAL_SCREEN_SIZE); + } + vsBuiltAge = vsAge; + fsBuiltAge = fsAge; + + } +#else + if (!_overlayProgram) { + compileProgram(_overlayProgram, LASER_GLOW_VS, LASER_GLOW_FS); + using namespace oglplus; + auto uniforms = _overlayProgram->ActiveUniforms(); + _overlayUniforms.mvp = Uniform(*_overlayProgram, "mvp").Location(); + _overlayUniforms.alpha = Uniform(*_overlayProgram, "alpha").Location(); + _overlayUniforms.glowPoints = Uniform(*_overlayProgram, "glowPoints").Location(); + _overlayUniforms.resolution = Uniform(*_overlayProgram, "resolution").Location(); + _overlayUniforms.radius = Uniform(*_overlayProgram, "radius").Location(); + useProgram(_overlayProgram); + Uniform(*_overlayProgram, _overlayUniforms.resolution).Set(CompositorHelper::VIRTUAL_SCREEN_SIZE); + } + +#endif +} + void HmdDisplayPlugin::uncustomizeContext() { + _overlayProgram.reset(); _sphereSection.reset(); _compositeFramebuffer.reset(); _previewProgram.reset(); @@ -327,19 +474,83 @@ void HmdDisplayPlugin::compositeOverlay() { auto compositorHelper = DependencyManager::get(); glm::mat4 modelMat = compositorHelper->getModelTransform().getMatrix(); - useProgram(_program); - // set the alpha - Uniform(*_program, _alphaUniform).Set(_compositeOverlayAlpha); + withPresentThreadLock([&] { + _presentHandLasers = _handLasers; + _presentHandPoses = _handPoses; + _presentUiModelTransform = _uiModelTransform; + }); + std::array handGlowPoints { { vec2(-1), vec2(-1) } }; + + // compute the glow point interesections + for (int i = 0; i < NUMBER_OF_HANDS; ++i) { + if (_presentHandPoses[i] == IDENTITY_MATRIX) { + continue; + } + const auto& handLaser = _presentHandLasers[i]; + if (!handLaser.valid()) { + continue; + } + + const auto& laserDirection = handLaser.direction; + auto model = _presentHandPoses[i]; + auto castDirection = glm::quat_cast(model) * laserDirection; + if (glm::abs(glm::length2(castDirection) - 1.0f) > EPSILON) { + castDirection = glm::normalize(castDirection); + castDirection = glm::inverse(_presentUiModelTransform.getRotation()) * castDirection; + } + + // FIXME fetch the actual UI radius from... somewhere? + float uiRadius = 1.0f; + + // Find the intersection of the laser with he UI and use it to scale the model matrix + float distance; + if (!glm::intersectRaySphere(vec3(_presentHandPoses[i][3]), castDirection, _presentUiModelTransform.getTranslation(), uiRadius * uiRadius, distance)) { + continue; + } + + vec3 intersectionPosition = vec3(_presentHandPoses[i][3]) + (castDirection * distance) - _presentUiModelTransform.getTranslation(); + intersectionPosition = glm::inverse(_presentUiModelTransform.getRotation()) * intersectionPosition; + + // Take the interesection normal and convert it to a texture coordinate + vec2 yawPitch; + { + vec2 xdir = glm::normalize(vec2(intersectionPosition.x, -intersectionPosition.z)); + yawPitch.x = glm::atan(xdir.x, xdir.y); + yawPitch.y = (acosf(intersectionPosition.y) * -1.0f) + M_PI_2; + } + vec2 halfFov = CompositorHelper::VIRTUAL_UI_TARGET_FOV / 2.0f; + + // Are we out of range + if (glm::any(glm::greaterThan(glm::abs(yawPitch), halfFov))) { + continue; + } + + yawPitch /= CompositorHelper::VIRTUAL_UI_TARGET_FOV; + yawPitch += 0.5f; + handGlowPoints[i] = yawPitch; + } + + updateGlowProgram(); + useProgram(_overlayProgram); + // Setup the uniforms + { + if (_overlayUniforms.alpha >= 0) { + Uniform(*_overlayProgram, _overlayUniforms.alpha).Set(_compositeOverlayAlpha); + } + if (_overlayUniforms.glowPoints >= 0) { + vec4 glowPoints(handGlowPoints[0], handGlowPoints[1]); + Uniform(*_overlayProgram, _overlayUniforms.glowPoints).Set(glowPoints); + } + } + _sphereSection->Use(); for_each_eye([&](Eye eye) { eyeViewport(eye); auto modelView = glm::inverse(_currentPresentFrameInfo.presentPose * getEyeToHeadTransform(eye)) * modelMat; auto mvp = _eyeProjections[eye] * modelView; - Uniform(*_program, _mvpUniform).Set(mvp); + Uniform(*_overlayProgram, _overlayUniforms.mvp).Set(mvp); _sphereSection->Draw(); }); - // restore the alpha - Uniform(*_program, _alphaUniform).Set(1.0); } void HmdDisplayPlugin::compositePointer() { @@ -478,23 +689,12 @@ bool HmdDisplayPlugin::setHandLaser(uint32_t hands, HandLaserMode mode, const ve } void HmdDisplayPlugin::compositeExtra() { - const int NUMBER_OF_HANDS = 2; - std::array handLasers; - std::array renderHandPoses; - Transform uiModelTransform; - withPresentThreadLock([&] { - handLasers = _handLasers; - renderHandPoses = _handPoses; - uiModelTransform = _uiModelTransform; - }); - // If neither hand laser is activated, exit - if (!handLasers[0].valid() && !handLasers[1].valid()) { + if (!_presentHandLasers[0].valid() && !_presentHandLasers[1].valid()) { return; } - static const glm::mat4 identity; - if (renderHandPoses[0] == identity && renderHandPoses[1] == identity) { + if (_presentHandPoses[0] == IDENTITY_MATRIX && _presentHandPoses[1] == IDENTITY_MATRIX) { return; } @@ -505,16 +705,16 @@ void HmdDisplayPlugin::compositeExtra() { std::array handLaserModelMatrices; for (int i = 0; i < NUMBER_OF_HANDS; ++i) { - if (renderHandPoses[i] == identity) { + if (_presentHandPoses[i] == IDENTITY_MATRIX) { continue; } - const auto& handLaser = handLasers[i]; + const auto& handLaser = _presentHandLasers[i]; if (!handLaser.valid()) { continue; } const auto& laserDirection = handLaser.direction; - auto model = renderHandPoses[i]; + auto model = _presentHandPoses[i]; auto castDirection = glm::quat_cast(model) * laserDirection; if (glm::abs(glm::length2(castDirection) - 1.0f) > EPSILON) { castDirection = glm::normalize(castDirection); @@ -525,7 +725,7 @@ void HmdDisplayPlugin::compositeExtra() { // Find the intersection of the laser with he UI and use it to scale the model matrix float distance; - if (!glm::intersectRaySphere(vec3(renderHandPoses[i][3]), castDirection, uiModelTransform.getTranslation(), uiRadius * uiRadius, distance)) { + if (!glm::intersectRaySphere(vec3(_presentHandPoses[i][3]), castDirection, _presentUiModelTransform.getTranslation(), uiRadius * uiRadius, distance)) { continue; } @@ -545,13 +745,12 @@ void HmdDisplayPlugin::compositeExtra() { auto view = glm::inverse(eyePose); const auto& projection = _eyeProjections[eye]; for (int i = 0; i < NUMBER_OF_HANDS; ++i) { - if (handLaserModelMatrices[i] == identity) { + if (handLaserModelMatrices[i] == IDENTITY_MATRIX) { continue; } Uniform(*_laserProgram, "mvp").Set(projection * view * handLaserModelMatrices[i]); - Uniform(*_laserProgram, "color").Set(handLasers[i].color); + Uniform(*_laserProgram, "color").Set(_presentHandLasers[i].color); _laserGeometry->Draw(); - // TODO render some kind of visual indicator at the intersection point with the UI. } }); } diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h index 8e48690fd1..be2811076d 100644 --- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h @@ -61,13 +61,29 @@ protected: } }; + ProgramPtr _overlayProgram; + struct OverlayUniforms { + int32_t mvp { -1 }; + int32_t alpha { -1 }; + int32_t glowPoints { -1 }; + int32_t resolution { -1 }; + int32_t radius { -1 }; + } _overlayUniforms; + Transform _uiModelTransform; std::array _handLasers; std::array _handPoses; + + Transform _presentUiModelTransform; + std::array _presentHandLasers; + std::array _presentHandPoses; + std::array _eyeOffsets; std::array _eyeProjections; std::array _eyeInverseProjections; + + glm::mat4 _cullingProjection; glm::uvec2 _renderTargetSize; float _ipd { 0.064f }; @@ -87,6 +103,8 @@ protected: FrameInfo _currentRenderFrameInfo; private: + void updateGlowProgram(); + bool _enablePreview { false }; bool _monoPreview { true }; bool _enableReprojection { true }; From 6242816f68b47c74f20479bcc5fdabac5188f21f Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 11 Jul 2016 18:59:22 -0700 Subject: [PATCH 2/2] Adding glow to hand lasers --- .../resources/shaders/hmd_hand_lasers.frag | 35 ++ .../resources/shaders/hmd_hand_lasers.geom | 70 +++ .../resources/shaders/hmd_hand_lasers.vert | 15 + .../resources/shaders/hmd_reproject.frag | 78 ++++ .../resources/shaders/hmd_reproject.vert | 20 + interface/resources/shaders/hmd_ui_glow.frag | 65 +++ interface/resources/shaders/hmd_ui_glow.vert | 23 + .../display-plugins/hmd/HmdDisplayPlugin.cpp | 425 ++++++------------ .../display-plugins/hmd/HmdDisplayPlugin.h | 39 +- libraries/gl/src/gl/OglplusHelpers.cpp | 30 ++ libraries/gl/src/gl/OglplusHelpers.h | 2 + 11 files changed, 493 insertions(+), 309 deletions(-) create mode 100644 interface/resources/shaders/hmd_hand_lasers.frag create mode 100644 interface/resources/shaders/hmd_hand_lasers.geom create mode 100644 interface/resources/shaders/hmd_hand_lasers.vert create mode 100644 interface/resources/shaders/hmd_reproject.frag create mode 100644 interface/resources/shaders/hmd_reproject.vert create mode 100644 interface/resources/shaders/hmd_ui_glow.frag create mode 100644 interface/resources/shaders/hmd_ui_glow.vert diff --git a/interface/resources/shaders/hmd_hand_lasers.frag b/interface/resources/shaders/hmd_hand_lasers.frag new file mode 100644 index 0000000000..6fffb1c521 --- /dev/null +++ b/interface/resources/shaders/hmd_hand_lasers.frag @@ -0,0 +1,35 @@ +// +// Created by Bradley Austin Davis on 2016/07/11 +// Copyright 2013-2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#version 410 core + +uniform vec4 color = vec4(1.0, 1.0, 1.0, 1.0); + +layout(location = 0) in vec3 inLineDistance; + +out vec4 FragColor; + +void main() { + vec2 d = inLineDistance.xy; + d.y = abs(d.y); + d.x = abs(d.x); + if (d.x > 1.0) { + d.x = (d.x - 1.0) / 0.02; + } else { + d.x = 0.0; + } + float alpha = 1.0 - length(d); + if (alpha <= 0.0) { + discard; + } + alpha = pow(alpha, 10.0); + if (alpha < 0.05) { + discard; + } + FragColor = vec4(color.rgb, alpha); +} diff --git a/interface/resources/shaders/hmd_hand_lasers.geom b/interface/resources/shaders/hmd_hand_lasers.geom new file mode 100644 index 0000000000..16b5dafadd --- /dev/null +++ b/interface/resources/shaders/hmd_hand_lasers.geom @@ -0,0 +1,70 @@ +// +// Created by Bradley Austin Davis on 2016/07/11 +// Copyright 2013-2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#version 410 core +#extension GL_EXT_geometry_shader4 : enable + +layout(location = 0) out vec3 outLineDistance; + +layout(lines) in; +layout(triangle_strip, max_vertices = 24) out; + +vec3[2] getOrthogonals(in vec3 n, float scale) { + float yDot = abs(dot(n, vec3(0, 1, 0))); + + vec3 result[2]; + if (yDot < 0.9) { + result[0] = normalize(cross(n, vec3(0, 1, 0))); + } else { + result[0] = normalize(cross(n, vec3(1, 0, 0))); + } + // The cross of result[0] and n is orthogonal to both, which are orthogonal to each other + result[1] = cross(result[0], n); + result[0] *= scale; + result[1] *= scale; + return result; +} + + +vec2 orthogonal(vec2 v) { + vec2 result = v.yx; + result.y *= -1.0; + return result; +} + +void main() { + vec2 endpoints[2]; + for (int i = 0; i < 2; ++i) { + endpoints[i] = gl_PositionIn[i].xy / gl_PositionIn[i].w; + } + vec2 lineNormal = normalize(endpoints[1] - endpoints[0]); + vec2 lineOrthogonal = orthogonal(lineNormal); + lineNormal *= 0.02; + lineOrthogonal *= 0.02; + + gl_Position = gl_PositionIn[0]; + gl_Position.xy -= lineOrthogonal; + outLineDistance = vec3(-1.02, -1, gl_Position.z); + EmitVertex(); + + gl_Position = gl_PositionIn[0]; + gl_Position.xy += lineOrthogonal; + outLineDistance = vec3(-1.02, 1, gl_Position.z); + EmitVertex(); + + gl_Position = gl_PositionIn[1]; + gl_Position.xy -= lineOrthogonal; + outLineDistance = vec3(1.02, -1, gl_Position.z); + EmitVertex(); + + gl_Position = gl_PositionIn[1]; + gl_Position.xy += lineOrthogonal; + outLineDistance = vec3(1.02, 1, gl_Position.z); + EmitVertex(); + + EndPrimitive(); +} diff --git a/interface/resources/shaders/hmd_hand_lasers.vert b/interface/resources/shaders/hmd_hand_lasers.vert new file mode 100644 index 0000000000..db5c7c1ecd --- /dev/null +++ b/interface/resources/shaders/hmd_hand_lasers.vert @@ -0,0 +1,15 @@ +// +// Created by Bradley Austin Davis on 2016/07/11 +// Copyright 2013-2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#version 410 core +uniform mat4 mvp = mat4(1); + +in vec3 Position; + +void main() { + gl_Position = mvp * vec4(Position, 1); +} diff --git a/interface/resources/shaders/hmd_reproject.frag b/interface/resources/shaders/hmd_reproject.frag new file mode 100644 index 0000000000..adda0315a3 --- /dev/null +++ b/interface/resources/shaders/hmd_reproject.frag @@ -0,0 +1,78 @@ +// +// Created by Bradley Austin Davis on 2016/07/11 +// Copyright 2013-2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#version 410 core + +uniform sampler2D sampler; +uniform mat3 reprojection = mat3(1); +uniform mat4 inverseProjections[2]; +uniform mat4 projections[2]; + +in vec2 vTexCoord; +in vec3 vPosition; + +out vec4 FragColor; + +void main() { + vec2 uv = vTexCoord; + + mat4 eyeInverseProjection; + mat4 eyeProjection; + + float xoffset = 1.0; + vec2 uvmin = vec2(0.0); + vec2 uvmax = vec2(1.0); + // determine the correct projection and inverse projection to use. + if (vTexCoord.x < 0.5) { + uvmax.x = 0.5; + eyeInverseProjection = inverseProjections[0]; + eyeProjection = projections[0]; + } else { + xoffset = -1.0; + uvmin.x = 0.5; + uvmax.x = 1.0; + eyeInverseProjection = inverseProjections[1]; + eyeProjection = projections[1]; + } + + // Account for stereo in calculating the per-eye NDC coordinates + vec4 ndcSpace = vec4(vPosition, 1.0); + ndcSpace.x *= 2.0; + ndcSpace.x += xoffset; + + // Convert from NDC to eyespace + vec4 eyeSpace = eyeInverseProjection * ndcSpace; + eyeSpace /= eyeSpace.w; + + // Convert to a noramlized ray + vec3 ray = eyeSpace.xyz; + ray = normalize(ray); + + // Adjust the ray by the rotation + ray = reprojection * ray; + + // Project back on to the texture plane + ray *= eyeSpace.z / ray.z; + + // Update the eyespace vector + eyeSpace.xyz = ray; + + // Reproject back into NDC + ndcSpace = eyeProjection * eyeSpace; + ndcSpace /= ndcSpace.w; + ndcSpace.x -= xoffset; + ndcSpace.x /= 2.0; + + // Calculate the new UV coordinates + uv = (ndcSpace.xy / 2.0) + 0.5; + if (any(greaterThan(uv, uvmax)) || any(lessThan(uv, uvmin))) { + FragColor = vec4(0.0, 0.0, 0.0, 1.0); + } else { + FragColor = texture(sampler, uv); + } +} \ No newline at end of file diff --git a/interface/resources/shaders/hmd_reproject.vert b/interface/resources/shaders/hmd_reproject.vert new file mode 100644 index 0000000000..923375613a --- /dev/null +++ b/interface/resources/shaders/hmd_reproject.vert @@ -0,0 +1,20 @@ +// +// Created by Bradley Austin Davis on 2016/07/11 +// Copyright 2013-2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#version 410 core +in vec3 Position; +in vec2 TexCoord; + +out vec3 vPosition; +out vec2 vTexCoord; + +void main() { + gl_Position = vec4(Position, 1); + vTexCoord = TexCoord; + vPosition = Position; +} diff --git a/interface/resources/shaders/hmd_ui_glow.frag b/interface/resources/shaders/hmd_ui_glow.frag new file mode 100644 index 0000000000..733f32d718 --- /dev/null +++ b/interface/resources/shaders/hmd_ui_glow.frag @@ -0,0 +1,65 @@ +// +// Created by Bradley Austin Davis on 2016/07/11 +// Copyright 2013-2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#version 410 core + +uniform sampler2D sampler; +uniform float alpha = 1.0; +uniform vec4 glowPoints = vec4(-1); +uniform vec4 glowColors[2]; +uniform vec2 resolution = vec2(3960.0, 1188.0); +uniform float radius = 0.005; + +in vec3 vPosition; +in vec2 vTexCoord; +in vec4 vGlowPoints; + +out vec4 FragColor; + +float easeInOutCubic(float f) { + const float d = 1.0; + const float b = 0.0; + const float c = 1.0; + float t = f; + if ((t /= d / 2.0) < 1.0) return c / 2.0 * t * t * t + b; + return c / 2.0 * ((t -= 2.0) * t * t + 2.0) + b; +} + +void main() { + vec2 aspect = resolution; + aspect /= resolution.x; + FragColor = texture(sampler, vTexCoord); + + float glowIntensity = 0.0; + float dist1 = distance(vTexCoord * aspect, glowPoints.xy * aspect); + float dist2 = distance(vTexCoord * aspect, glowPoints.zw * aspect); + float dist = min(dist1, dist2); + vec3 glowColor = glowColors[0].rgb; + if (dist2 < dist1) { + glowColor = glowColors[1].rgb; + } + + if (dist <= radius) { + glowIntensity = 1.0 - (dist / radius); + glowColor.rgb = pow(glowColor, vec3(1.0 - glowIntensity)); + glowIntensity = easeInOutCubic(glowIntensity); + glowIntensity = pow(glowIntensity, 0.5); + } + + if (alpha <= 0.0) { + if (glowIntensity <= 0.0) { + discard; + } + + FragColor = vec4(glowColor, glowIntensity); + return; + } + + FragColor.rgb = mix(FragColor.rgb, glowColor.rgb, glowIntensity); + FragColor.a *= alpha; +} \ No newline at end of file diff --git a/interface/resources/shaders/hmd_ui_glow.vert b/interface/resources/shaders/hmd_ui_glow.vert new file mode 100644 index 0000000000..5defec085f --- /dev/null +++ b/interface/resources/shaders/hmd_ui_glow.vert @@ -0,0 +1,23 @@ +// +// Created by Bradley Austin Davis on 2016/07/11 +// Copyright 2013-2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#version 410 core + +uniform mat4 mvp = mat4(1); + +in vec3 Position; +in vec2 TexCoord; + +out vec3 vPosition; +out vec2 vTexCoord; + +void main() { + gl_Position = mvp * vec4(Position, 1); + vTexCoord = TexCoord; + vPosition = Position; +} diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp index 2dc7df341a..1bfa6c7921 100644 --- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp @@ -95,252 +95,6 @@ void HmdDisplayPlugin::internalDeactivate() { Parent::internalDeactivate(); } - -static const char * REPROJECTION_VS = R"VS(#version 410 core -in vec3 Position; -in vec2 TexCoord; - -out vec3 vPosition; -out vec2 vTexCoord; - -void main() { - gl_Position = vec4(Position, 1); - vTexCoord = TexCoord; - vPosition = Position; -} - -)VS"; - -static GLint REPROJECTION_MATRIX_LOCATION = -1; -static GLint INVERSE_PROJECTION_MATRIX_LOCATION = -1; -static GLint PROJECTION_MATRIX_LOCATION = -1; -static const char * REPROJECTION_FS = R"FS(#version 410 core - -uniform sampler2D sampler; -uniform mat3 reprojection = mat3(1); -uniform mat4 inverseProjections[2]; -uniform mat4 projections[2]; - -in vec2 vTexCoord; -in vec3 vPosition; - -out vec4 FragColor; - -void main() { - vec2 uv = vTexCoord; - - mat4 eyeInverseProjection; - mat4 eyeProjection; - - float xoffset = 1.0; - vec2 uvmin = vec2(0.0); - vec2 uvmax = vec2(1.0); - // determine the correct projection and inverse projection to use. - if (vTexCoord.x < 0.5) { - uvmax.x = 0.5; - eyeInverseProjection = inverseProjections[0]; - eyeProjection = projections[0]; - } else { - xoffset = -1.0; - uvmin.x = 0.5; - uvmax.x = 1.0; - eyeInverseProjection = inverseProjections[1]; - eyeProjection = projections[1]; - } - - // Account for stereo in calculating the per-eye NDC coordinates - vec4 ndcSpace = vec4(vPosition, 1.0); - ndcSpace.x *= 2.0; - ndcSpace.x += xoffset; - - // Convert from NDC to eyespace - vec4 eyeSpace = eyeInverseProjection * ndcSpace; - eyeSpace /= eyeSpace.w; - - // Convert to a noramlized ray - vec3 ray = eyeSpace.xyz; - ray = normalize(ray); - - // Adjust the ray by the rotation - ray = reprojection * ray; - - // Project back on to the texture plane - ray *= eyeSpace.z / ray.z; - - // Update the eyespace vector - eyeSpace.xyz = ray; - - // Reproject back into NDC - ndcSpace = eyeProjection * eyeSpace; - ndcSpace /= ndcSpace.w; - ndcSpace.x -= xoffset; - ndcSpace.x /= 2.0; - - // Calculate the new UV coordinates - uv = (ndcSpace.xy / 2.0) + 0.5; - if (any(greaterThan(uv, uvmax)) || any(lessThan(uv, uvmin))) { - FragColor = vec4(0.0, 0.0, 0.0, 1.0); - } else { - FragColor = texture(sampler, uv); - } -} -)FS"; - -#ifdef DEBUG_REPROJECTION_SHADER -#include -#include -#include -#include - -static const QString REPROJECTION_FS_FILE = "c:/Users/bdavis/Git/hifi/interface/resources/shaders/reproject.frag"; - -static ProgramPtr getReprojectionProgram() { - static ProgramPtr _currentProgram; - uint64_t now = usecTimestampNow(); - static uint64_t _lastFileCheck = now; - - bool modified = false; - if ((now - _lastFileCheck) > USECS_PER_MSEC * 100) { - QFileInfo info(REPROJECTION_FS_FILE); - QDateTime lastModified = info.lastModified(); - static QDateTime _lastModified = lastModified; - qDebug() << lastModified.toTime_t(); - qDebug() << _lastModified.toTime_t(); - if (lastModified > _lastModified) { - _lastModified = lastModified; - modified = true; - } - } - - if (!_currentProgram || modified) { - _currentProgram.reset(); - try { - QFile shaderFile(REPROJECTION_FS_FILE); - shaderFile.open(QIODevice::ReadOnly); - QString fragment = shaderFile.readAll(); - compileProgram(_currentProgram, REPROJECTION_VS, fragment.toLocal8Bit().data()); - } catch (const std::runtime_error& error) { - qDebug() << "Failed to build: " << error.what(); - } - if (!_currentProgram) { - _currentProgram = loadDefaultShader(); - } - } - return _currentProgram; -} -#endif - -static GLint PREVIEW_TEXTURE_LOCATION = -1; - -static const char * LASER_VS = R"VS(#version 410 core -uniform mat4 mvp = mat4(1); - -in vec3 Position; - -out vec3 vPosition; - -void main() { - gl_Position = mvp * vec4(Position, 1); - vPosition = Position; -} - -)VS"; - -static const char * LASER_GS = R"GS( -)GS"; - -static const char * LASER_FS = R"FS(#version 410 core - -uniform vec4 color = vec4(1.0, 1.0, 1.0, 1.0); -in vec3 vPosition; - -out vec4 FragColor; - -void main() { - FragColor = color; -} - -)FS"; - - -static const char * LASER_GLOW_VS = R"VS(#version 410 core - -uniform mat4 mvp = mat4(1); - -in vec3 Position; -in vec2 TexCoord; - -out vec3 vPosition; -out vec2 vTexCoord; - -void main() { - gl_Position = mvp * vec4(Position, 1); - vTexCoord = TexCoord; - vPosition = Position; -} - -)VS"; - -static const char * LASER_GLOW_FS = R"FS(#version 410 core -#line 286 -uniform sampler2D sampler; -uniform float alpha = 1.0; -uniform vec4 glowPoints = vec4(-1); -uniform vec4 glowColor1 = vec4(0.01, 0.7, 0.9, 1.0); -uniform vec4 glowColor2 = vec4(0.9, 0.7, 0.01, 1.0); -uniform vec2 resolution = vec2(3960.0, 1188.0); -uniform float radius = 0.005; - -in vec3 vPosition; -in vec2 vTexCoord; -in vec4 vGlowPoints; - -out vec4 FragColor; - -float easeInOutCubic(float f) { - const float d = 1.0; - const float b = 0.0; - const float c = 1.0; - float t = f; - if ((t /= d / 2.0) < 1.0) return c / 2.0 * t * t * t + b; - return c / 2.0 * ((t -= 2.0) * t * t + 2.0) + b; -} - -void main() { - vec2 aspect = resolution; - aspect /= resolution.x; - FragColor = texture(sampler, vTexCoord); - - float glowIntensity = 0.0; - float dist1 = distance(vTexCoord * aspect, glowPoints.xy * aspect); - float dist2 = distance(vTexCoord * aspect, glowPoints.zw * aspect); - float dist = min(dist1, dist2); - vec3 glowColor = glowColor1.rgb; - if (dist2 < dist1) { - glowColor = glowColor2.rgb; - } - - if (dist <= radius) { - glowIntensity = 1.0 - (dist / radius); - glowColor.rgb = pow(glowColor, vec3(1.0 - glowIntensity)); - glowIntensity = easeInOutCubic(glowIntensity); - glowIntensity = pow(glowIntensity, 0.5); - } - - if (alpha <= 0.0) { - if (glowIntensity <= 0.0) { - discard; - } - - FragColor = vec4(glowColor, glowIntensity); - return; - } - - FragColor.rgb = mix(FragColor.rgb, glowColor.rgb, glowIntensity); - FragColor.a *= alpha; -} -)FS"; - void HmdDisplayPlugin::customizeContext() { Parent::customizeContext(); // Only enable mirroring if we know vsync is disabled @@ -354,76 +108,139 @@ void HmdDisplayPlugin::customizeContext() { if (!_enablePreview) { const std::string version("#version 410 core\n"); compileProgram(_previewProgram, version + DrawUnitQuadTexcoord_vert, version + DrawTexture_frag); - PREVIEW_TEXTURE_LOCATION = Uniform(*_previewProgram, "colorMap").Location(); + _previewUniforms.previewTexture = Uniform(*_previewProgram, "colorMap").Location(); } - updateGlowProgram(); - compileProgram(_laserProgram, LASER_VS, LASER_FS); + updateReprojectionProgram(); + updateOverlayProgram(); + updateLaserProgram(); + _laserGeometry = loadLaser(_laserProgram); - - compileProgram(_reprojectionProgram, REPROJECTION_VS, REPROJECTION_FS); - REPROJECTION_MATRIX_LOCATION = Uniform(*_reprojectionProgram, "reprojection").Location(); - INVERSE_PROJECTION_MATRIX_LOCATION = Uniform(*_reprojectionProgram, "inverseProjections").Location(); - PROJECTION_MATRIX_LOCATION = Uniform(*_reprojectionProgram, "projections").Location(); } +//#define LIVE_SHADER_RELOAD 1 -#if 0 -static QString readFile(const char* filename) { +static QString readFile(const QString& filename) { QFile file(filename); file.open(QFile::Text | QFile::ReadOnly); QString result; result.append(QTextStream(&file).readAll()); return result; } -#endif - -void HmdDisplayPlugin::updateGlowProgram() { -#if 0 +void HmdDisplayPlugin::updateReprojectionProgram() { + static const QString vsFile = PathUtils::resourcesPath() + "/shaders/hmd_reproject.vert"; + static const QString fsFile = PathUtils::resourcesPath() + "/shaders/hmd_reproject.frag"; +#if LIVE_SHADER_RELOAD + static qint64 vsBuiltAge = 0; + static qint64 fsBuiltAge = 0; + QFileInfo vsInfo(vsFile); + QFileInfo fsInfo(fsFile); + auto vsAge = vsInfo.lastModified().toMSecsSinceEpoch(); + auto fsAge = fsInfo.lastModified().toMSecsSinceEpoch(); + if (!_reprojectionProgram || vsAge > vsBuiltAge || fsAge > fsBuiltAge) { + vsBuiltAge = vsAge; + fsBuiltAge = fsAge; +#else + if (!_reprojectionProgram) { +#endif + QString vsSource = readFile(vsFile); + QString fsSource = readFile(fsFile); + ProgramPtr program; + try { + compileProgram(program, vsSource.toLocal8Bit().toStdString(), fsSource.toLocal8Bit().toStdString()); + if (program) { + using namespace oglplus; + _reprojectionUniforms.reprojectionMatrix = Uniform(*program, "reprojection").Location(); + _reprojectionUniforms.inverseProjectionMatrix = Uniform(*program, "inverseProjections").Location(); + _reprojectionUniforms.projectionMatrix = Uniform(*program, "projections").Location(); + _reprojectionProgram = program; + } + } catch (std::runtime_error& error) { + qWarning() << "Error building reprojection shader " << error.what(); + } + } + +} + +void HmdDisplayPlugin::updateLaserProgram() { + static const QString vsFile = PathUtils::resourcesPath() + "/shaders/hmd_hand_lasers.vert"; + static const QString gsFile = PathUtils::resourcesPath() + "/shaders/hmd_hand_lasers.geom"; + static const QString fsFile = PathUtils::resourcesPath() + "/shaders/hmd_hand_lasers.frag"; + +#if LIVE_SHADER_RELOAD + static qint64 vsBuiltAge = 0; + static qint64 gsBuiltAge = 0; + static qint64 fsBuiltAge = 0; + QFileInfo vsInfo(vsFile); + QFileInfo fsInfo(fsFile); + QFileInfo gsInfo(fsFile); + auto vsAge = vsInfo.lastModified().toMSecsSinceEpoch(); + auto fsAge = fsInfo.lastModified().toMSecsSinceEpoch(); + auto gsAge = gsInfo.lastModified().toMSecsSinceEpoch(); + if (!_laserProgram || vsAge > vsBuiltAge || fsAge > fsBuiltAge || gsAge > gsBuiltAge) { + vsBuiltAge = vsAge; + gsBuiltAge = gsAge; + fsBuiltAge = fsAge; +#else + if (!_laserProgram) { +#endif + + QString vsSource = readFile(vsFile); + QString fsSource = readFile(fsFile); + QString gsSource = readFile(gsFile); + ProgramPtr program; + try { + compileProgram(program, vsSource.toLocal8Bit().toStdString(), gsSource.toLocal8Bit().toStdString(), fsSource.toLocal8Bit().toStdString()); + if (program) { + using namespace oglplus; + _laserUniforms.color = Uniform(*program, "color").Location(); + _laserUniforms.mvp = Uniform(*program, "mvp").Location(); + _laserProgram = program; + } + } catch (std::runtime_error& error) { + qWarning() << "Error building hand laser composite shader " << error.what(); + } + } +} + +void HmdDisplayPlugin::updateOverlayProgram() { + static const QString vsFile = PathUtils::resourcesPath() + "/shaders/hmd_ui_glow.vert"; + static const QString fsFile = PathUtils::resourcesPath() + "/shaders/hmd_ui_glow.frag"; + +#if LIVE_SHADER_RELOAD static qint64 vsBuiltAge = 0; static qint64 fsBuiltAge = 0; - static const char* vsFile = "H:/glow_vert.glsl"; - static const char* fsFile = "H:/glow_frag.glsl"; QFileInfo vsInfo(vsFile); QFileInfo fsInfo(fsFile); auto vsAge = vsInfo.lastModified().toMSecsSinceEpoch(); auto fsAge = fsInfo.lastModified().toMSecsSinceEpoch(); if (!_overlayProgram || vsAge > vsBuiltAge || fsAge > fsBuiltAge) { - QString vsSource = readFile(vsFile); - QString fsSource = readFile(fsFile); - ProgramPtr newOverlayProgram; - compileProgram(newOverlayProgram, vsSource.toLocal8Bit().toStdString(), fsSource.toLocal8Bit().toStdString()); - if (newOverlayProgram) { - using namespace oglplus; - _overlayProgram = newOverlayProgram; - auto uniforms = _overlayProgram->ActiveUniforms(); - _overlayUniforms.mvp = Uniform(*_overlayProgram, "mvp").Location(); - _overlayUniforms.alpha = Uniform(*_overlayProgram, "alpha").Location(); - _overlayUniforms.glowPoints = Uniform(*_overlayProgram, "glowPoints").Location(); - _overlayUniforms.resolution = Uniform(*_overlayProgram, "resolution").Location(); - _overlayUniforms.radius = Uniform(*_overlayProgram, "radius").Location(); - useProgram(_overlayProgram); - Uniform(*_overlayProgram, _overlayUniforms.resolution).Set(CompositorHelper::VIRTUAL_SCREEN_SIZE); - } vsBuiltAge = vsAge; fsBuiltAge = fsAge; - - } #else if (!_overlayProgram) { - compileProgram(_overlayProgram, LASER_GLOW_VS, LASER_GLOW_FS); - using namespace oglplus; - auto uniforms = _overlayProgram->ActiveUniforms(); - _overlayUniforms.mvp = Uniform(*_overlayProgram, "mvp").Location(); - _overlayUniforms.alpha = Uniform(*_overlayProgram, "alpha").Location(); - _overlayUniforms.glowPoints = Uniform(*_overlayProgram, "glowPoints").Location(); - _overlayUniforms.resolution = Uniform(*_overlayProgram, "resolution").Location(); - _overlayUniforms.radius = Uniform(*_overlayProgram, "radius").Location(); - useProgram(_overlayProgram); - Uniform(*_overlayProgram, _overlayUniforms.resolution).Set(CompositorHelper::VIRTUAL_SCREEN_SIZE); - } - #endif + QString vsSource = readFile(vsFile); + QString fsSource = readFile(fsFile); + ProgramPtr program; + try { + compileProgram(program, vsSource.toLocal8Bit().toStdString(), fsSource.toLocal8Bit().toStdString()); + if (program) { + using namespace oglplus; + _overlayUniforms.mvp = Uniform(*program, "mvp").Location(); + _overlayUniforms.alpha = Uniform(*program, "alpha").Location(); + _overlayUniforms.glowColors = Uniform(*program, "glowColors").Location(); + _overlayUniforms.glowPoints = Uniform(*program, "glowPoints").Location(); + _overlayUniforms.resolution = Uniform(*program, "resolution").Location(); + _overlayUniforms.radius = Uniform(*program, "radius").Location(); + _overlayProgram = program; + useProgram(_overlayProgram); + Uniform(*_overlayProgram, _overlayUniforms.resolution).Set(CompositorHelper::VIRTUAL_SCREEN_SIZE); + } + } catch (std::runtime_error& error) { + qWarning() << "Error building overlay composite shader " << error.what(); + } + } } void HmdDisplayPlugin::uncustomizeContext() { @@ -459,12 +276,12 @@ void HmdDisplayPlugin::compositeScene() { using namespace oglplus; Texture::MinFilter(TextureTarget::_2D, TextureMinFilter::Linear); Texture::MagFilter(TextureTarget::_2D, TextureMagFilter::Linear); - Uniform(*_reprojectionProgram, REPROJECTION_MATRIX_LOCATION).Set(_currentPresentFrameInfo.presentReprojection); + Uniform(*_reprojectionProgram, _reprojectionUniforms.reprojectionMatrix).Set(_currentPresentFrameInfo.presentReprojection); //Uniform(*_reprojectionProgram, PROJECTION_MATRIX_LOCATION).Set(_eyeProjections); //Uniform(*_reprojectionProgram, INVERSE_PROJECTION_MATRIX_LOCATION).Set(_eyeInverseProjections); // FIXME what's the right oglplus mechanism to do this? It's not that ^^^ ... better yet, switch to a uniform buffer - glUniformMatrix4fv(INVERSE_PROJECTION_MATRIX_LOCATION, 2, GL_FALSE, &(_eyeInverseProjections[0][0][0])); - glUniformMatrix4fv(PROJECTION_MATRIX_LOCATION, 2, GL_FALSE, &(_eyeProjections[0][0][0])); + glUniformMatrix4fv(_reprojectionUniforms.inverseProjectionMatrix, 2, GL_FALSE, &(_eyeInverseProjections[0][0][0])); + glUniformMatrix4fv(_reprojectionUniforms.projectionMatrix, 2, GL_FALSE, &(_eyeProjections[0][0][0])); _plane->UseInProgram(*_reprojectionProgram); _plane->Draw(); } @@ -530,7 +347,11 @@ void HmdDisplayPlugin::compositeOverlay() { handGlowPoints[i] = yawPitch; } - updateGlowProgram(); + updateOverlayProgram(); + if (!_overlayProgram) { + return; + } + useProgram(_overlayProgram); // Setup the uniforms { @@ -541,6 +362,12 @@ void HmdDisplayPlugin::compositeOverlay() { vec4 glowPoints(handGlowPoints[0], handGlowPoints[1]); Uniform(*_overlayProgram, _overlayUniforms.glowPoints).Set(glowPoints); } + if (_overlayUniforms.glowColors >= 0) { + std::array glowColors; + glowColors[0] = _presentHandLasers[0].color; + glowColors[1] = _presentHandLasers[1].color; + glProgramUniform4fv(GetName(*_overlayProgram), _overlayUniforms.glowColors, 2, &glowColors[0].r); + } } _sphereSection->Use(); @@ -634,7 +461,7 @@ void HmdDisplayPlugin::internalPresent() { glClearColor(0, 0, 0, 1); glClear(GL_COLOR_BUFFER_BIT); glViewport(targetViewportPosition.x, targetViewportPosition.y, targetViewportSize.x, targetViewportSize.y); - glUniform1i(PREVIEW_TEXTURE_LOCATION, 0); + glUniform1i(_previewUniforms.previewTexture, 0); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, _previewTextureID); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); @@ -698,6 +525,8 @@ void HmdDisplayPlugin::compositeExtra() { return; } + updateLaserProgram(); + // Render hand lasers using namespace oglplus; useProgram(_laserProgram); @@ -739,6 +568,7 @@ void HmdDisplayPlugin::compositeExtra() { handLaserModelMatrices[i] = model; } + glEnable(GL_BLEND); for_each_eye([&](Eye eye) { eyeViewport(eye); auto eyePose = _currentPresentFrameInfo.presentPose * getEyeToHeadTransform(eye); @@ -753,4 +583,5 @@ void HmdDisplayPlugin::compositeExtra() { _laserGeometry->Draw(); } }); + glDisable(GL_BLEND); } diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h index be2811076d..f168ec9607 100644 --- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h @@ -61,15 +61,6 @@ protected: } }; - ProgramPtr _overlayProgram; - struct OverlayUniforms { - int32_t mvp { -1 }; - int32_t alpha { -1 }; - int32_t glowPoints { -1 }; - int32_t resolution { -1 }; - int32_t radius { -1 }; - } _overlayUniforms; - Transform _uiModelTransform; std::array _handLasers; std::array _handPoses; @@ -82,8 +73,6 @@ protected: std::array _eyeProjections; std::array _eyeInverseProjections; - - glm::mat4 _cullingProjection; glm::uvec2 _renderTargetSize; float _ipd { 0.064f }; @@ -103,23 +92,49 @@ protected: FrameInfo _currentRenderFrameInfo; private: - void updateGlowProgram(); + void updateOverlayProgram(); + void updateLaserProgram(); + void updateReprojectionProgram(); bool _enablePreview { false }; bool _monoPreview { true }; bool _enableReprojection { true }; bool _firstPreview { true }; + ProgramPtr _overlayProgram; + struct OverlayUniforms { + int32_t mvp { -1 }; + int32_t alpha { -1 }; + int32_t glowColors { -1 }; + int32_t glowPoints { -1 }; + int32_t resolution { -1 }; + int32_t radius { -1 }; + } _overlayUniforms; + ProgramPtr _previewProgram; + struct PreviewUniforms { + int32_t previewTexture { -1 }; + } _previewUniforms; + float _previewAspect { 0 }; GLuint _previewTextureID { 0 }; glm::uvec2 _prevWindowSize { 0, 0 }; qreal _prevDevicePixelRatio { 0 }; ProgramPtr _reprojectionProgram; + struct ReprojectionUniforms { + int32_t reprojectionMatrix { -1 }; + int32_t inverseProjectionMatrix { -1 }; + int32_t projectionMatrix { -1 }; + } _reprojectionUniforms; + ShapeWrapperPtr _sphereSection; ProgramPtr _laserProgram; + struct LaserUniforms { + int32_t mvp { -1 }; + int32_t color { -1 }; + } _laserUniforms; ShapeWrapperPtr _laserGeometry; }; diff --git a/libraries/gl/src/gl/OglplusHelpers.cpp b/libraries/gl/src/gl/OglplusHelpers.cpp index 7a535a806d..1154042b4a 100644 --- a/libraries/gl/src/gl/OglplusHelpers.cpp +++ b/libraries/gl/src/gl/OglplusHelpers.cpp @@ -87,6 +87,36 @@ ProgramPtr loadCubemapShader() { return result; } +void compileProgram(ProgramPtr & result, const std::string& vs, const std::string& gs, const std::string& fs) { + using namespace oglplus; + try { + result = std::make_shared(); + // attach the shaders to the program + result->AttachShader( + VertexShader() + .Source(GLSLSource(vs)) + .Compile() + ); + result->AttachShader( + GeometryShader() + .Source(GLSLSource(gs)) + .Compile() + ); + result->AttachShader( + FragmentShader() + .Source(GLSLSource(fs)) + .Compile() + ); + result->Link(); + } catch (ProgramBuildError& err) { + Q_UNUSED(err); + qWarning() << err.Log().c_str(); + Q_ASSERT_X(false, "compileProgram", "Failed to build shader program"); + qFatal("%s", (const char*)err.Message); + result.reset(); + } +} + void compileProgram(ProgramPtr & result, const std::string& vs, const std::string& fs) { using namespace oglplus; try { diff --git a/libraries/gl/src/gl/OglplusHelpers.h b/libraries/gl/src/gl/OglplusHelpers.h index 8940205b21..c453fbad28 100644 --- a/libraries/gl/src/gl/OglplusHelpers.h +++ b/libraries/gl/src/gl/OglplusHelpers.h @@ -62,6 +62,8 @@ using Mat4Uniform = oglplus::Uniform; ProgramPtr loadDefaultShader(); ProgramPtr loadCubemapShader(); void compileProgram(ProgramPtr & result, const std::string& vs, const std::string& fs); +void compileProgram(ProgramPtr & result, const std::string& vs, const std::string& gs, const std::string& fs); + ShapeWrapperPtr loadSkybox(ProgramPtr program); ShapeWrapperPtr loadPlane(ProgramPtr program, float aspect = 1.0f); ShapeWrapperPtr loadSphereSection(ProgramPtr program, float fov = PI / 3.0f * 2.0f, float aspect = 16.0f / 9.0f, int slices = 128, int stacks = 128);