void ChunkRenderer::renderChunkLocally(const Chunk& chunk, const RenderData& data) { ProgramObject* programObject = getActivatedProgramWithTileData( _localRenderingShaderProvider.get(), _localProgramUniformHandler, chunk); if (programObject == nullptr) { return; } using namespace glm; const Ellipsoid& ellipsoid = chunk.owner()->ellipsoid(); bool performAnyBlending = false; for (int i = 0; i < LayeredTextures::NUM_TEXTURE_CATEGORIES; ++i) { LayeredTextures::TextureCategory category = (LayeredTextures::TextureCategory)i; if (_tileProviderManager->getTileProviderGroup(i).levelBlendingEnabled && _tileProviderManager->getTileProviderGroup(category).getActiveTileProviders().size() > 0) { performAnyBlending = true; break; } } if (performAnyBlending) { float distanceScaleFactor = chunk.owner()->lodScaleFactor * chunk.owner()->ellipsoid().minimumRadius(); programObject->setUniform("distanceScaleFactor", distanceScaleFactor); programObject->setUniform("chunkLevel", chunk.index().level); } // Calculate other uniform variables needed for rendering dmat4 modelTransform = chunk.owner()->modelTransform(); dmat4 viewTransform = data.camera.combinedViewMatrix(); dmat4 modelViewTransform = viewTransform * modelTransform; std::vector<std::string> cornerNames = { "p01", "p11", "p00", "p10" }; std::vector<Vec3> cornersCameraSpace(4); for (int i = 0; i < 4; ++i) { Quad q = (Quad)i; Geodetic2 corner = chunk.surfacePatch().getCorner(q); Vec3 cornerModelSpace = ellipsoid.cartesianSurfacePosition(corner); Vec3 cornerCameraSpace = Vec3(dmat4(modelViewTransform) * glm::dvec4(cornerModelSpace, 1)); cornersCameraSpace[i] = cornerCameraSpace; programObject->setUniform(cornerNames[i], vec3(cornerCameraSpace)); } vec3 patchNormalCameraSpace = normalize( cross(cornersCameraSpace[Quad::SOUTH_EAST] - cornersCameraSpace[Quad::SOUTH_WEST], cornersCameraSpace[Quad::NORTH_EAST] - cornersCameraSpace[Quad::SOUTH_WEST])); programObject->setUniform("patchNormalCameraSpace", patchNormalCameraSpace); programObject->setUniform("projectionTransform", data.camera.projectionMatrix()); if (_tileProviderManager->getTileProviderGroup( LayeredTextures::NightTextures).getActiveTileProviders().size() > 0 || _tileProviderManager->getTileProviderGroup( LayeredTextures::WaterMasks).getActiveTileProviders().size() > 0) { glm::vec3 directionToSunWorldSpace = glm::normalize(-data.modelTransform.translation); glm::vec3 directionToSunCameraSpace = (viewTransform * glm::dvec4(directionToSunWorldSpace, 0)); data.modelTransform.translation; programObject->setUniform("lightDirectionCameraSpace", -directionToSunCameraSpace); } // OpenGL rendering settings glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); glCullFace(GL_BACK); // render _grid->geometry().drawUsingActiveProgram(); // disable shader programObject->deactivate(); }
ProgramObject* ChunkRenderer::getActivatedProgramWithTileData( LayeredTextureShaderProvider* layeredTextureShaderProvider, std::shared_ptr<LayeredTextureShaderUniformIdHandler> programUniformHandler, const Chunk& chunk) { const ChunkIndex& chunkIndex = chunk.index(); std::array<std::vector<std::shared_ptr<TileProvider> >, LayeredTextures::NUM_TEXTURE_CATEGORIES> tileProviders; LayeredTexturePreprocessingData layeredTexturePreprocessingData; for (size_t category = 0; category < LayeredTextures::NUM_TEXTURE_CATEGORIES; category++) { tileProviders[category] = _tileProviderManager->getTileProviderGroup(category).getActiveTileProviders(); LayeredTextureInfo layeredTextureInfo; layeredTextureInfo.lastLayerIdx = tileProviders[category].size() - 1; layeredTextureInfo.layerBlendingEnabled = _tileProviderManager->getTileProviderGroup(category).levelBlendingEnabled; layeredTexturePreprocessingData.layeredTextureInfo[category] = layeredTextureInfo; } layeredTexturePreprocessingData.keyValuePairs.push_back( std::pair<std::string, std::string>( "useAtmosphere", std::to_string(chunk.owner()->atmosphereEnabled))); layeredTexturePreprocessingData.keyValuePairs.push_back( std::pair<std::string, std::string>( "showChunkEdges", std::to_string(chunk.owner()->debugOptions.showChunkEdges))); layeredTexturePreprocessingData.keyValuePairs.push_back( std::pair<std::string, std::string>( "showHeightResolution", std::to_string(chunk.owner()->debugOptions.showHeightResolution))); layeredTexturePreprocessingData.keyValuePairs.push_back( std::pair<std::string, std::string>( "showHeightIntensities", std::to_string(chunk.owner()->debugOptions.showHeightIntensities))); layeredTexturePreprocessingData.keyValuePairs.push_back( std::pair<std::string, std::string>( "defaultHeight", std::to_string(Chunk::DEFAULT_HEIGHT))); // Now the shader program can be accessed ProgramObject* programObject = layeredTextureShaderProvider->getUpdatedShaderProgram( layeredTexturePreprocessingData); programUniformHandler->updateIdsIfNecessary(layeredTextureShaderProvider); // Activate the shader program programObject->activate(); // Initialize all texture units struct BlendTexUnits { ghoul::opengl::TextureUnit blendTexture0; ghoul::opengl::TextureUnit blendTexture1; ghoul::opengl::TextureUnit blendTexture2; }; std::array<std::vector<BlendTexUnits>, LayeredTextures::NUM_TEXTURE_CATEGORIES> texUnits; for (size_t category = 0; category < LayeredTextures::NUM_TEXTURE_CATEGORIES; category++) { texUnits[category].resize(tileProviders[category].size()); } // Go through all the categories for (size_t category = 0; category < LayeredTextures::NUM_TEXTURE_CATEGORIES; category++) { // Go through all the providers in this category int i = 0; for (auto it = tileProviders[category].begin(); it != tileProviders[category].end(); it++) { auto tileProvider = it->get(); // Get the texture that should be used for rendering TileAndTransform tileAndTransform = TileSelector::getHighestResolutionTile(tileProvider, chunkIndex); if (tileAndTransform.tile.status == Tile::Status::Unavailable) { tileAndTransform.tile = tileProvider->getDefaultTile(); tileAndTransform.uvTransform.uvOffset = { 0, 0 }; tileAndTransform.uvTransform.uvScale = { 1, 1 }; } activateTileAndSetTileUniforms( programUniformHandler, LayeredTextures::TextureCategory(category), LayeredTextureShaderUniformIdHandler::BlendLayerSuffixes::none, i, texUnits[category][i].blendTexture0, tileAndTransform); // If blending is enabled, two more textures are needed if (layeredTexturePreprocessingData.layeredTextureInfo[category].layerBlendingEnabled) { TileAndTransform tileAndTransformParent1 = TileSelector::getHighestResolutionTile(tileProvider, chunkIndex, 1); if (tileAndTransformParent1.tile.status == Tile::Status::Unavailable) { tileAndTransformParent1 = tileAndTransform; } activateTileAndSetTileUniforms( programUniformHandler, LayeredTextures::TextureCategory(category), LayeredTextureShaderUniformIdHandler::BlendLayerSuffixes::Parent1, i, texUnits[category][i].blendTexture1, tileAndTransformParent1); TileAndTransform tileAndTransformParent2 = TileSelector::getHighestResolutionTile(tileProvider, chunkIndex, 2); if (tileAndTransformParent2.tile.status == Tile::Status::Unavailable) { tileAndTransformParent2 = tileAndTransformParent1; } activateTileAndSetTileUniforms( programUniformHandler, LayeredTextures::TextureCategory(category), LayeredTextureShaderUniformIdHandler::BlendLayerSuffixes::Parent2, i, texUnits[category][i].blendTexture2, tileAndTransformParent2); } /* if (category == LayeredTextures::HeightMaps && tileAndTransform.tile.preprocessData) { //auto preprocessingData = tileAndTransform.tile.preprocessData; //float noDataValue = preprocessingData->noDataValues[0]; programObject->setUniform( "minimumValidHeight[" + std::to_string(i) + "]", -100000); } */ i++; } } // Go through all the height maps and set depth tranforms int i = 0; auto it = tileProviders[LayeredTextures::HeightMaps].begin(); auto end = tileProviders[LayeredTextures::HeightMaps].end(); for (; it != end; it++) { auto tileProvider = *it; TileDepthTransform depthTransform = tileProvider->depthTransform(); setDepthTransformUniforms( programUniformHandler, LayeredTextures::TextureCategory::HeightMaps, LayeredTextureShaderUniformIdHandler::BlendLayerSuffixes::none, i, depthTransform); i++; } // The length of the skirts is proportional to its size programObject->setUniform("skirtLength", min(static_cast<float>(chunk.surfacePatch().halfSize().lat * 1000000), 8700.0f)); programObject->setUniform("xSegments", _grid->xSegments()); if (chunk.owner()->debugOptions.showHeightResolution) { programObject->setUniform("vertexResolution", glm::vec2(_grid->xSegments(), _grid->ySegments())); } return programObject; }
void ChunkRenderer::renderChunkGlobally(const Chunk& chunk, const RenderData& data){ ProgramObject* programObject = getActivatedProgramWithTileData( _globalRenderingShaderProvider.get(), _globalProgramUniformHandler, chunk); if (programObject == nullptr) { return; } const Ellipsoid& ellipsoid = chunk.owner()->ellipsoid(); bool performAnyBlending = false; for (int i = 0; i < LayeredTextures::NUM_TEXTURE_CATEGORIES; ++i) { LayeredTextures::TextureCategory category = (LayeredTextures::TextureCategory)i; if(_tileProviderManager->getTileProviderGroup(i).levelBlendingEnabled && _tileProviderManager->getTileProviderGroup(category).getActiveTileProviders().size() > 0){ performAnyBlending = true; break; } } if (performAnyBlending) { // Calculations are done in the reference frame of the globe. Hence, the camera // position needs to be transformed with the inverse model matrix glm::dmat4 inverseModelTransform = chunk.owner()->inverseModelTransform(); glm::dvec3 cameraPosition = glm::dvec3(inverseModelTransform * glm::dvec4(data.camera.positionVec3(), 1)); float distanceScaleFactor = chunk.owner()->lodScaleFactor * ellipsoid.minimumRadius(); programObject->setUniform("cameraPosition", vec3(cameraPosition)); programObject->setUniform("distanceScaleFactor", distanceScaleFactor); programObject->setUniform("chunkLevel", chunk.index().level); } // Calculate other uniform variables needed for rendering Geodetic2 swCorner = chunk.surfacePatch().getCorner(Quad::SOUTH_WEST); auto patchSize = chunk.surfacePatch().size(); dmat4 modelTransform = chunk.owner()->modelTransform(); dmat4 viewTransform = data.camera.combinedViewMatrix(); mat4 modelViewTransform = mat4(viewTransform * modelTransform); mat4 modelViewProjectionTransform = data.camera.projectionMatrix() * modelViewTransform; // Upload the uniform variables programObject->setUniform("modelViewProjectionTransform", modelViewProjectionTransform); programObject->setUniform("minLatLon", vec2(swCorner.toLonLatVec2())); programObject->setUniform("lonLatScalingFactor", vec2(patchSize.toLonLatVec2())); programObject->setUniform("radiiSquared", vec3(ellipsoid.radiiSquared())); if (_tileProviderManager->getTileProviderGroup( LayeredTextures::NightTextures).getActiveTileProviders().size() > 0 || _tileProviderManager->getTileProviderGroup( LayeredTextures::WaterMasks).getActiveTileProviders().size() > 0) { glm::vec3 directionToSunWorldSpace = glm::normalize(-data.modelTransform.translation); glm::vec3 directionToSunCameraSpace = (viewTransform * glm::dvec4(directionToSunWorldSpace, 0)); data.modelTransform.translation; programObject->setUniform("modelViewTransform", modelViewTransform); programObject->setUniform("lightDirectionCameraSpace", -directionToSunCameraSpace); } // OpenGL rendering settings glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); glCullFace(GL_BACK); // render _grid->geometry().drawUsingActiveProgram(); // disable shader programObject->deactivate(); }
void DeferredLightingEffect::render(RenderArgs* args) { // perform deferred lighting, rendering to free fbo glDisable(GL_BLEND); glDisable(GL_LIGHTING); glDisable(GL_DEPTH_TEST); glDisable(GL_COLOR_MATERIAL); glDepthMask(false); auto textureCache = DependencyManager::get<TextureCache>(); glBindFramebuffer(GL_FRAMEBUFFER, 0 ); QSize framebufferSize = textureCache->getFrameBufferSize(); // binding the first framebuffer auto freeFBO = DependencyManager::get<GlowEffect>()->getFreeFramebuffer(); glBindFramebuffer(GL_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(freeFBO)); glClear(GL_COLOR_BUFFER_BIT); // glEnable(GL_FRAMEBUFFER_SRGB); // glBindTexture(GL_TEXTURE_2D, primaryFBO->texture()); glBindTexture(GL_TEXTURE_2D, textureCache->getPrimaryColorTextureID()); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, textureCache->getPrimaryNormalTextureID()); glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, textureCache->getPrimarySpecularTextureID()); glActiveTexture(GL_TEXTURE3); glBindTexture(GL_TEXTURE_2D, textureCache->getPrimaryDepthTextureID()); // get the viewport side (left, right, both) int viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); const int VIEWPORT_X_INDEX = 0; const int VIEWPORT_Y_INDEX = 1; const int VIEWPORT_WIDTH_INDEX = 2; const int VIEWPORT_HEIGHT_INDEX = 3; float sMin = viewport[VIEWPORT_X_INDEX] / (float)framebufferSize.width(); float sWidth = viewport[VIEWPORT_WIDTH_INDEX] / (float)framebufferSize.width(); float tMin = viewport[VIEWPORT_Y_INDEX] / (float)framebufferSize.height(); float tHeight = viewport[VIEWPORT_HEIGHT_INDEX] / (float)framebufferSize.height(); bool useSkyboxCubemap = (_skybox) && (_skybox->getCubemap()); // Fetch the ViewMatrix; glm::mat4 invViewMat; _viewState->getViewTransform().getMatrix(invViewMat); ProgramObject* program = &_directionalLight; const LightLocations* locations = &_directionalLightLocations; bool shadowsEnabled = _viewState->getShadowsEnabled(); if (shadowsEnabled) { glActiveTexture(GL_TEXTURE4); glBindTexture(GL_TEXTURE_2D, textureCache->getShadowDepthTextureID()); program = &_directionalLightShadowMap; locations = &_directionalLightShadowMapLocations; if (_viewState->getCascadeShadowsEnabled()) { program = &_directionalLightCascadedShadowMap; locations = &_directionalLightCascadedShadowMapLocations; if (useSkyboxCubemap) { program = &_directionalSkyboxLightCascadedShadowMap; locations = &_directionalSkyboxLightCascadedShadowMapLocations; } else if (_ambientLightMode > -1) { program = &_directionalAmbientSphereLightCascadedShadowMap; locations = &_directionalAmbientSphereLightCascadedShadowMapLocations; } program->bind(); program->setUniform(locations->shadowDistances, _viewState->getShadowDistances()); } else { if (useSkyboxCubemap) { program = &_directionalSkyboxLightShadowMap; locations = &_directionalSkyboxLightShadowMapLocations; } else if (_ambientLightMode > -1) { program = &_directionalAmbientSphereLightShadowMap; locations = &_directionalAmbientSphereLightShadowMapLocations; } program->bind(); } program->setUniformValue(locations->shadowScale, 1.0f / textureCache->getShadowFramebuffer()->getWidth()); } else { if (useSkyboxCubemap) { program = &_directionalSkyboxLight; locations = &_directionalSkyboxLightLocations; } else if (_ambientLightMode > -1) { program = &_directionalAmbientSphereLight; locations = &_directionalAmbientSphereLightLocations; } program->bind(); } { auto globalLight = _allocatedLights[_globalLights.front()]; if (locations->ambientSphere >= 0) { gpu::SphericalHarmonics sh = globalLight->getAmbientSphere(); if (useSkyboxCubemap && _skybox->getCubemap()->getIrradiance()) { sh = (*_skybox->getCubemap()->getIrradiance()); } for (int i =0; i <gpu::SphericalHarmonics::NUM_COEFFICIENTS; i++) { program->setUniformValue(locations->ambientSphere + i, *(((QVector4D*) &sh) + i)); } } if (useSkyboxCubemap) { glActiveTexture(GL_TEXTURE5); glBindTexture(GL_TEXTURE_CUBE_MAP, gpu::GLBackend::getTextureID(_skybox->getCubemap())); } if (locations->lightBufferUnit >= 0) { gpu::Batch batch; batch.setUniformBuffer(locations->lightBufferUnit, globalLight->getSchemaBuffer()); gpu::GLBackend::renderBatch(batch); } if (_atmosphere && (locations->atmosphereBufferUnit >= 0)) { gpu::Batch batch; batch.setUniformBuffer(locations->atmosphereBufferUnit, _atmosphere->getDataBuffer()); gpu::GLBackend::renderBatch(batch); } glUniformMatrix4fv(locations->invViewMat, 1, false, reinterpret_cast< const GLfloat* >(&invViewMat)); } float left, right, bottom, top, nearVal, farVal; glm::vec4 nearClipPlane, farClipPlane; _viewState->computeOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane); program->setUniformValue(locations->nearLocation, nearVal); float depthScale = (farVal - nearVal) / farVal; program->setUniformValue(locations->depthScale, depthScale); float nearScale = -1.0f / nearVal; float depthTexCoordScaleS = (right - left) * nearScale / sWidth; float depthTexCoordScaleT = (top - bottom) * nearScale / tHeight; float depthTexCoordOffsetS = left * nearScale - sMin * depthTexCoordScaleS; float depthTexCoordOffsetT = bottom * nearScale - tMin * depthTexCoordScaleT; program->setUniformValue(locations->depthTexCoordOffset, depthTexCoordOffsetS, depthTexCoordOffsetT); program->setUniformValue(locations->depthTexCoordScale, depthTexCoordScaleS, depthTexCoordScaleT); renderFullscreenQuad(sMin, sMin + sWidth, tMin, tMin + tHeight); program->release(); if (useSkyboxCubemap) { glBindTexture(GL_TEXTURE_CUBE_MAP, 0); if (!shadowsEnabled) { glActiveTexture(GL_TEXTURE3); } } if (shadowsEnabled) { glBindTexture(GL_TEXTURE_2D, 0); glActiveTexture(GL_TEXTURE3); } // additive blending glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glEnable(GL_CULL_FACE); glm::vec4 sCoefficients(sWidth / 2.0f, 0.0f, 0.0f, sMin + sWidth / 2.0f); glm::vec4 tCoefficients(0.0f, tHeight / 2.0f, 0.0f, tMin + tHeight / 2.0f); glTexGenfv(GL_S, GL_OBJECT_PLANE, (const GLfloat*)&sCoefficients); glTexGenfv(GL_T, GL_OBJECT_PLANE, (const GLfloat*)&tCoefficients); // enlarge the scales slightly to account for tesselation const float SCALE_EXPANSION = 0.05f; const glm::vec3& eyePoint = _viewState->getCurrentViewFrustum()->getPosition(); float nearRadius = glm::distance(eyePoint, _viewState->getCurrentViewFrustum()->getNearTopLeft()); auto geometryCache = DependencyManager::get<GeometryCache>(); if (!_pointLights.empty()) { _pointLight.bind(); _pointLight.setUniformValue(_pointLightLocations.nearLocation, nearVal); _pointLight.setUniformValue(_pointLightLocations.depthScale, depthScale); _pointLight.setUniformValue(_pointLightLocations.depthTexCoordOffset, depthTexCoordOffsetS, depthTexCoordOffsetT); _pointLight.setUniformValue(_pointLightLocations.depthTexCoordScale, depthTexCoordScaleS, depthTexCoordScaleT); for (auto lightID : _pointLights) { auto light = _allocatedLights[lightID]; if (_pointLightLocations.lightBufferUnit >= 0) { gpu::Batch batch; batch.setUniformBuffer(_pointLightLocations.lightBufferUnit, light->getSchemaBuffer()); gpu::GLBackend::renderBatch(batch); } glUniformMatrix4fv(_pointLightLocations.invViewMat, 1, false, reinterpret_cast< const GLfloat* >(&invViewMat)); glPushMatrix(); float expandedRadius = light->getMaximumRadius() * (1.0f + SCALE_EXPANSION); if (glm::distance(eyePoint, glm::vec3(light->getPosition())) < expandedRadius + nearRadius) { glLoadIdentity(); glTranslatef(0.0f, 0.0f, -1.0f); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); renderFullscreenQuad(); glPopMatrix(); glMatrixMode(GL_MODELVIEW); } else { glTranslatef(light->getPosition().x, light->getPosition().y, light->getPosition().z); geometryCache->renderSphere(expandedRadius, 32, 32, glm::vec4(1.0f, 1.0f, 1.0f, 1.0f)); } glPopMatrix(); } _pointLights.clear(); _pointLight.release(); } if (!_spotLights.empty()) { _spotLight.bind(); _spotLight.setUniformValue(_spotLightLocations.nearLocation, nearVal); _spotLight.setUniformValue(_spotLightLocations.depthScale, depthScale); _spotLight.setUniformValue(_spotLightLocations.depthTexCoordOffset, depthTexCoordOffsetS, depthTexCoordOffsetT); _spotLight.setUniformValue(_spotLightLocations.depthTexCoordScale, depthTexCoordScaleS, depthTexCoordScaleT); for (auto lightID : _spotLights) { auto light = _allocatedLights[lightID]; if (_spotLightLocations.lightBufferUnit >= 0) { gpu::Batch batch; batch.setUniformBuffer(_spotLightLocations.lightBufferUnit, light->getSchemaBuffer()); gpu::GLBackend::renderBatch(batch); } glUniformMatrix4fv(_spotLightLocations.invViewMat, 1, false, reinterpret_cast< const GLfloat* >(&invViewMat)); glPushMatrix(); float expandedRadius = light->getMaximumRadius() * (1.0f + SCALE_EXPANSION); float edgeRadius = expandedRadius / glm::cos(light->getSpotAngle()); if (glm::distance(eyePoint, glm::vec3(light->getPosition())) < edgeRadius + nearRadius) { glLoadIdentity(); glTranslatef(0.0f, 0.0f, -1.0f); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); renderFullscreenQuad(); glPopMatrix(); glMatrixMode(GL_MODELVIEW); } else { glTranslatef(light->getPosition().x, light->getPosition().y, light->getPosition().z); glm::quat spotRotation = rotationBetween(glm::vec3(0.0f, 0.0f, -1.0f), light->getDirection()); glm::vec3 axis = glm::axis(spotRotation); glRotatef(glm::degrees(glm::angle(spotRotation)), axis.x, axis.y, axis.z); glTranslatef(0.0f, 0.0f, -light->getMaximumRadius() * (1.0f + SCALE_EXPANSION * 0.5f)); geometryCache->renderCone(expandedRadius * glm::tan(light->getSpotAngle()), expandedRadius, 32, 1); } glPopMatrix(); } _spotLights.clear(); _spotLight.release(); } glBindTexture(GL_TEXTURE_2D, 0); glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, 0); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, 0); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, 0); // glDisable(GL_FRAMEBUFFER_SRGB); // End of the Lighting pass }