/***************************************************************************************** * * * OpenSpace * * * * Copyright (c) 2014-2023 * * * * Permission is hereby granted, free of charge, to any person obtaining a copy of this * * software and associated documentation files (the "Software"), to deal in the Software * * without restriction, including without limitation the rights to use, copy, modify, * * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * * permit persons to whom the Software is furnished to do so, subject to the following * * conditions: * * * * The above copyright notice and this permission notice shall be included in all copies * * or substantial portions of the Software. * * * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { constexpr std::string_view _loggerCat = "RenderableSkyTarget"; enum BlendMode { Normal = 0, Additive }; constexpr openspace::properties::Property::PropertyInfo crossHairSizeInfo = { "CrosshairSize", "Crosshair Size", "Determines the size of the crosshair. The size is determined in fov (degrees)" }; constexpr openspace::properties::Property::PropertyInfo RectangleThresholdInfo = { "RectangleThreshold", "Rectangle Threshold", "When the field of view is larger than the rectangle threshold, a rectangle will " "be rendered in the target" }; constexpr openspace::properties::Property::PropertyInfo LineWidthInfo = { "LineWidth", "Line Width", "The thickness of the line of the target. The larger number, the thicker line" }; constexpr openspace::properties::Property::PropertyInfo VerticalFovInfo = { "VerticalFov", "Vertical Field Of View", "The vertical field of view of the target." }; constexpr openspace::properties::Property::PropertyInfo ApplyRollInfo = { "ApplyRoll", "Apply Roll", "Always rotate the target to have it's up direction aligned with the up direction " "of the camera" }; struct [[codegen::Dictionary(RenderableSkyTarget)]] Parameters { // [[codegen::verbatim(crossHairSizeInfo.description)]] std::optional crossHairSize; // [[codegen::verbatim(RectangleThresholdInfo.description)]] std::optional rectangleThreshold; // [[codegen::verbatim(LineWidthInfo.description)]] std::optional lineWidth; // [[codegen::verbatim(VerticalFovInfo.description)]] std::optional verticalFov; // [[codegen::verbatim(ApplyRollInfo.description)]] std::optional applyRoll; }; #include "renderableskytarget_codegen.cpp" } //namespace namespace openspace { documentation::Documentation RenderableSkyTarget::Documentation() { return codegen::doc("skybrowser_renderableskytarget"); } RenderableSkyTarget::RenderableSkyTarget(const ghoul::Dictionary& dictionary) : RenderablePlane(dictionary) , _crossHairSize(crossHairSizeInfo, 2.f, 1.f, 10.f) , _showRectangleThreshold(RectangleThresholdInfo, 5.f, 0.1f, 70.f) , _lineWidth(LineWidthInfo, 13.f, 1.f, 100.f) , _verticalFov(VerticalFovInfo, 10.0, 0.00000000001, 70.0) , _borderColor(220, 220, 220) , _applyRoll(ApplyRollInfo, true) { // Handle target dimension property const Parameters p = codegen::bake(dictionary); _crossHairSize = p.crossHairSize.value_or(_crossHairSize); addProperty(_crossHairSize); _showRectangleThreshold = p.rectangleThreshold.value_or(_showRectangleThreshold); addProperty(_showRectangleThreshold); _lineWidth = p.lineWidth.value_or(_lineWidth); addProperty(_lineWidth); _verticalFov= p.verticalFov.value_or(_verticalFov); _verticalFov.setReadOnly(true); addProperty(_verticalFov); addProperty(_applyRoll); } void RenderableSkyTarget::bindTexture() {} void RenderableSkyTarget::initializeGL() { glGenVertexArrays(1, &_quad); // generate array glGenBuffers(1, &_vertexPositionBuffer); // generate buffer createPlane(); std::string ProgramName = identifier() + "Shader"; _shader = BaseModule::ProgramObjectManager.request( ProgramName, [&]() -> std::unique_ptr { return global::renderEngine->buildRenderProgram( ProgramName, absPath("${MODULE_SKYBROWSER}/shaders/target_vs.glsl"), absPath("${MODULE_SKYBROWSER}/shaders/target_fs.glsl") ); } ); } void RenderableSkyTarget::setColor(glm::ivec3 color) { _borderColor = std::move(color); } glm::ivec3 RenderableSkyTarget::borderColor() const { return _borderColor; } glm::dvec3 RenderableSkyTarget::rightVector() const { double scaling = (_verticalFov / 70)* static_cast(_size.value()); return scaling * _rightVector; } glm::dvec3 RenderableSkyTarget::upVector() const { double scaling = (_verticalFov / 70) * static_cast(_size.value()); return scaling * _upVector; } void RenderableSkyTarget::applyRoll() { Camera* camera = global::navigationHandler->camera(); glm::dvec3 normal = glm::normalize(camera->positionVec3() - _worldPosition); _rightVector = glm::normalize( glm::cross(camera->lookUpVectorWorldSpace(), normal) ); _upVector = glm::cross(normal, _rightVector); } void RenderableSkyTarget::render(const RenderData& data, RendererTasks&) { ZoneScoped const bool showRectangle = _verticalFov > _showRectangleThreshold; glm::vec4 color = glm::vec4(glm::vec3(_borderColor) / 255.f, 1.0); _shader->activate(); _shader->setUniform("opacity", opacity()); _shader->setUniform("crossHairSize", _crossHairSize); _shader->setUniform("showRectangle", showRectangle); _shader->setUniform("lineWidth", _lineWidth * 0.0001f); _shader->setUniform("ratio", _ratio); _shader->setUniform("lineColor", color); _shader->setUniform("fov", static_cast(_verticalFov)); _shader->setUniform("borderRadius", static_cast(_borderRadius)); _worldPosition = glm::dvec3( glm::translate( glm::dmat4(1.0), data.modelTransform.translation) * glm::dvec4(0.0, 0.0, 0.0, 1.0) ); glm::dvec3 normal = glm::normalize(data.camera.positionVec3() - _worldPosition); // There are two modes - 1) target rolls to have its up vector parallel to the // cameras up vector or 2) it is decoupled from the camera, in which case it needs to // be initialized once if (!_isInitialized || _applyRoll) { applyRoll(); _isInitialized = true; } else { // Use last frames vector for right and don't apply any roll _upVector = glm::cross(normal, _rightVector); _rightVector = glm::normalize( glm::cross(_upVector, normal) ); } glm::dmat4 cameraOrientedRotation = glm::dmat4(1.0); cameraOrientedRotation[0] = glm::dvec4(_rightVector, 0.0); cameraOrientedRotation[1] = glm::dvec4(_upVector, 0.0); cameraOrientedRotation[2] = glm::dvec4(normal, 0.0); const glm::dmat4 rotationTransform = _billboard ? cameraOrientedRotation : glm::dmat4(data.modelTransform.rotation); const glm::dmat4 modelTransform = glm::translate(glm::dmat4(1.0), data.modelTransform.translation) * rotationTransform * glm::scale(glm::dmat4(1.0), glm::dvec3(data.modelTransform.scale)) * glm::dmat4(1.0); const glm::dmat4 modelViewTransform = data.camera.combinedViewMatrix() * modelTransform; _shader->setUniform( "modelViewProjectionTransform", data.camera.projectionMatrix() * glm::mat4(modelViewTransform) ); _shader->setUniform( "modelViewTransform", glm::mat4(data.camera.combinedViewMatrix() * glm::dmat4(modelViewTransform)) ); _shader->setUniform("multiplyColor", _multiplyColor); bool additiveBlending = (_blendMode == static_cast(BlendMode::Additive)); if (additiveBlending) { glDepthMask(false); glBlendFunc(GL_SRC_ALPHA, GL_ONE); } glBindVertexArray(_quad); glEnable(GL_LINE_SMOOTH); glDrawArrays(GL_TRIANGLES, 0, 6); glDisable(GL_LINE_SMOOTH); glBindVertexArray(0); if (additiveBlending) { glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDepthMask(true); } _shader->deactivate(); } void RenderableSkyTarget::setRatio(float ratio) { // To avoid flooring of the size of the target, multiply by factor of 100 // Object size is really the pixel size so this calculation is not exact _ratio = ratio; } void RenderableSkyTarget::highlight(const glm::ivec3& addition) { _borderColor += addition; } void RenderableSkyTarget::removeHighlight(const glm::ivec3& removal) { _borderColor -= removal; } void RenderableSkyTarget::setVerticalFov(double fov) { _verticalFov = fov; } void RenderableSkyTarget::setBorderRadius(double radius) { _borderRadius = radius; } } // namespace openspace