///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2011-2012 Statoil ASA, Ceetron AS // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. // // See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// #include "RIStdInclude.h" #include "RivCellEdgeEffectGenerator.h" #include "cvfBase.h" #include "cvfAssert.h" #include "cvfDrawableGeo.h" #include "cvfVertexAttribute.h" #include "cvfStructGridGeometryGenerator.h" #include "cvfScalarMapperUniformLevels.h" #include "cvfShaderProgramGenerator.h" #include "cvfShaderSourceProvider.h" #include "cvfqtUtils.h" #include "cvfShaderProgram.h" #include "cvfRenderStateCullFace.h" #include "cvfTextureImage.h" #include "cvfTexture.h" #include "cvfSampler.h" #include "cvfScalarMapper.h" #include "cafEffectGenerator.h" #include #include #include #include "RimReservoirView.h" #include "RimResultSlot.h" #include "RigGridBase.h" #include "RigMainGrid.h" #include "RigReservoirCellResults.h" #include "RigEclipseCase.h" #include "RigActiveCellInfo.h" //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivCellEdgeGeometryGenerator::addCellEdgeResultsToDrawableGeo( size_t timeStepIndex, RimResultSlot* cellResultSlot, RimCellEdgeResultSlot* cellEdgeResultSlot, cvf::StructGridGeometryGenerator* generator, cvf::DrawableGeo* geo) { const std::vector& quadToCell = generator->quadToGridCellIndices(); const std::vector& quadToFace = generator->quadToFace(); size_t vertexCount = geo->vertexArray()->size(); size_t quadCount = vertexCount / 4; cvf::ref localCoords = new cvf::Vec2fArray; localCoords->resize(vertexCount); cvf::ref faceIndexArray = new cvf::IntArray; faceIndexArray->resize(vertexCount); cvf::ref cellColorTextureCoordArray = new cvf::FloatArray; cellColorTextureCoordArray->resize(vertexCount); // Build six cell face color arrays cvf::Collection cellEdgeColorTextureCoordsArrays; size_t idx; for (idx = 0; idx < 6; idx++) { cvf::ref colorArray = new cvf::FloatArray; colorArray->resize(vertexCount); cellEdgeColorTextureCoordsArrays.push_back(colorArray.p()); } cvf::ScalarMapper* cellResultScalarMapper = cellResultSlot->legendConfig()->scalarMapper(); cvf::ScalarMapper* edgeResultScalarMapper = cellEdgeResultSlot->legendConfig()->scalarMapper(); const RigGridBase* grid = dynamic_cast(generator->activeGrid()); CVF_ASSERT(grid != NULL); RigEclipseCase* eclipseCase = cellResultSlot->reservoirView()->eclipseCase()->reservoirData(); CVF_ASSERT(eclipseCase != NULL); cvf::ref cellCenterDataAccessObject = NULL; if (cellResultSlot->hasResult()) { if (!cellResultSlot->hasDynamicResult()) { // Static result values are located at time step 0 timeStepIndex = 0; } RifReaderInterface::PorosityModelResultType porosityModel = RigReservoirCellResults::convertFromProjectModelPorosityModel(cellResultSlot->porosityModel()); cellCenterDataAccessObject = eclipseCase->dataAccessObject(grid, porosityModel, timeStepIndex, cellResultSlot->gridScalarIndex()); } CVF_ASSERT(cellEdgeResultSlot->hasResult()); size_t resultIndices[6]; cellEdgeResultSlot->gridScalarIndices(resultIndices); cvf::Collection cellEdgeDataAccessObjects; size_t cubeFaceIdx; for (cubeFaceIdx = 0; cubeFaceIdx < 6; cubeFaceIdx++) { cvf::ref daObj; if (resultIndices[cubeFaceIdx] != cvf::UNDEFINED_SIZE_T) { // Assuming static values to be mapped onto cell edge, always using time step zero // TODO: Now hardcoded matrix results, should it be possible to use fracture results? daObj = eclipseCase->dataAccessObject(grid, RifReaderInterface::MATRIX_RESULTS, 0, resultIndices[cubeFaceIdx]); } cellEdgeDataAccessObjects.push_back(daObj.p()); } double ignoredScalarValue = cellEdgeResultSlot->ignoredScalarValue(); #pragma omp parallel for for (int quadIdx = 0; quadIdx < static_cast(quadCount); quadIdx++) { localCoords->set(quadIdx * 4 + 0, cvf::Vec2f(0, 0)); localCoords->set(quadIdx * 4 + 1, cvf::Vec2f(1, 0)); localCoords->set(quadIdx * 4 + 2, cvf::Vec2f(1, 1)); localCoords->set(quadIdx * 4 + 3, cvf::Vec2f(0, 1)); faceIndexArray->set(quadIdx * 4 + 0, quadToFace[quadIdx] ); faceIndexArray->set(quadIdx * 4 + 1, quadToFace[quadIdx] ); faceIndexArray->set(quadIdx * 4 + 2, quadToFace[quadIdx] ); faceIndexArray->set(quadIdx * 4 + 3, quadToFace[quadIdx] ); float cellColorTextureCoord = 0.5f; // If no results exists, the texture will have a special color size_t cellIndex = quadToCell[quadIdx]; { double scalarValue = HUGE_VAL; if (cellCenterDataAccessObject.notNull()) { scalarValue = cellCenterDataAccessObject->cellScalar(cellIndex); } if (scalarValue != HUGE_VAL) { cellColorTextureCoord = cellResultScalarMapper->mapToTextureCoord(scalarValue)[0]; } else { cellColorTextureCoord = -1.0f; // Undefined texture coord. Shader handles this. } } cellColorTextureCoordArray->set(quadIdx * 4 + 0, cellColorTextureCoord); cellColorTextureCoordArray->set(quadIdx * 4 + 1, cellColorTextureCoord); cellColorTextureCoordArray->set(quadIdx * 4 + 2, cellColorTextureCoord); cellColorTextureCoordArray->set(quadIdx * 4 + 3, cellColorTextureCoord); size_t cubeFaceIdx; float edgeColor; for (cubeFaceIdx = 0; cubeFaceIdx < 6; cubeFaceIdx++) { edgeColor = -1.0f; // Undefined texture coord. Shader handles this. double scalarValue = HUGE_VAL; if (cellEdgeDataAccessObjects[cubeFaceIdx].notNull()) { scalarValue = cellEdgeDataAccessObjects[cubeFaceIdx]->cellScalar(cellIndex); } if (scalarValue != HUGE_VAL && scalarValue != ignoredScalarValue) { edgeColor = edgeResultScalarMapper->mapToTextureCoord(scalarValue)[0]; } cvf::FloatArray* colArr = cellEdgeColorTextureCoordsArrays.at(cubeFaceIdx); colArr->set(quadIdx * 4 + 0, edgeColor); colArr->set(quadIdx * 4 + 1, edgeColor); colArr->set(quadIdx * 4 + 2, edgeColor); colArr->set(quadIdx * 4 + 3, edgeColor); } } geo->setVertexAttribute(new cvf::Vec2fVertexAttribute("a_localCoord", localCoords.p())); geo->setVertexAttribute(new cvf::FloatVertexAttribute("a_colorCell", cellColorTextureCoordArray.p())); cvf::ref faceIntAttribute = new cvf::IntVertexAttributeDirect("a_face", faceIndexArray.p()); //faceIntAttribute->setIntegerTypeConversion(cvf::VertexAttribute::DIRECT_FLOAT); geo->setVertexAttribute(faceIntAttribute.p()); geo->setVertexAttribute(new cvf::FloatVertexAttribute("a_colorPosI", cellEdgeColorTextureCoordsArrays.at(0))); geo->setVertexAttribute(new cvf::FloatVertexAttribute("a_colorNegI", cellEdgeColorTextureCoordsArrays.at(1))); geo->setVertexAttribute(new cvf::FloatVertexAttribute("a_colorPosJ", cellEdgeColorTextureCoordsArrays.at(2))); geo->setVertexAttribute(new cvf::FloatVertexAttribute("a_colorNegJ", cellEdgeColorTextureCoordsArrays.at(3))); geo->setVertexAttribute(new cvf::FloatVertexAttribute("a_colorPosK", cellEdgeColorTextureCoordsArrays.at(4))); geo->setVertexAttribute(new cvf::FloatVertexAttribute("a_colorNegK", cellEdgeColorTextureCoordsArrays.at(5))); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- CellEdgeEffectGenerator::CellEdgeEffectGenerator(const cvf::ScalarMapper* edgeScalarMapper, const cvf::ScalarMapper* cellScalarMapper) { CVF_ASSERT(edgeScalarMapper != NULL); m_cellScalarMapper = cellScalarMapper; m_edgeScalarMapper = edgeScalarMapper; m_cullBackfaces = false; m_opacityLevel = 1.0f; m_defaultCellColor = cvf::Color3f(cvf::Color3::WHITE); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool CellEdgeEffectGenerator::isEqual(const EffectGenerator* other) const { const CellEdgeEffectGenerator* otherCellFaceEffectGenerator = dynamic_cast(other); if (otherCellFaceEffectGenerator && m_cellScalarMapper.p() == otherCellFaceEffectGenerator->m_cellScalarMapper.p() && m_edgeScalarMapper.p() == otherCellFaceEffectGenerator->m_edgeScalarMapper.p() && m_cullBackfaces == otherCellFaceEffectGenerator->m_cullBackfaces && m_opacityLevel == otherCellFaceEffectGenerator->m_opacityLevel && m_undefinedColor == otherCellFaceEffectGenerator->m_undefinedColor && m_defaultCellColor == otherCellFaceEffectGenerator->m_defaultCellColor ) { cvf::ref texImg2 = new cvf::TextureImage; if (otherCellFaceEffectGenerator->m_edgeScalarMapper.notNull()) { otherCellFaceEffectGenerator->m_edgeScalarMapper->updateTexture(texImg2.p()); if (!caf::ScalarMapperEffectGenerator::isImagesEqual(m_edgeTextureImage.p(), texImg2.p())) return false; } if (otherCellFaceEffectGenerator->m_cellScalarMapper.notNull()) { otherCellFaceEffectGenerator->m_cellScalarMapper->updateTexture(texImg2.p()); if (!caf::ScalarMapperEffectGenerator::isImagesEqual(m_cellTextureImage.p(), texImg2.p())) return false; } return true; } else { return false; } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- caf::EffectGenerator* CellEdgeEffectGenerator::copy() const { CellEdgeEffectGenerator * newEffect = new CellEdgeEffectGenerator(m_edgeScalarMapper.p(), m_cellScalarMapper.p()); newEffect->m_edgeTextureImage = m_edgeTextureImage; newEffect->m_cellTextureImage = m_cellTextureImage; newEffect->setOpacityLevel(m_opacityLevel); newEffect->setCullBackfaces(m_cullBackfaces); newEffect->setUndefinedColor(m_undefinedColor); newEffect->setDefaultCellColor(m_defaultCellColor); return newEffect; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void CellEdgeEffectGenerator::updateForShaderBasedRendering(cvf::Effect* effect) const { cvf::ref eff = effect; // Set up shader program cvf::ShaderProgramGenerator shaderGen("CellEdgeFaceShaderProgramGenerator", cvf::ShaderSourceProvider::instance()); { QFile data(":/Shader/fs_CellFace.glsl"); if (data.open(QFile::ReadOnly)) { QTextStream in(&data); QString data = in.readAll(); cvf::String cvfString = cvfqt::Utils::fromQString(data); shaderGen.addFragmentCode(cvfString); } } { QFile data(":/Shader/vs_CellFace.glsl"); if (data.open(QFile::ReadOnly)) { QTextStream in(&data); QString data = in.readAll(); cvf::String cvfString = cvfqt::Utils::fromQString(data); shaderGen.addVertexCode(cvfString); } } shaderGen.addFragmentCode(caf::CommonShaderSources::light_AmbientDiffuse()); shaderGen.addFragmentCode(cvf::ShaderSourceRepository::fs_Standard); cvf::ref prog = shaderGen.generate(); eff->setShaderProgram(prog.p()); // Set up textures m_edgeTextureImage = new cvf::TextureImage; m_cellTextureImage = new cvf::TextureImage; cvf::ref modifiedCellTextImage; m_edgeScalarMapper->updateTexture(m_edgeTextureImage.p()); if (m_cellScalarMapper.notNull()) { m_cellScalarMapper->updateTexture(m_cellTextureImage.p()); modifiedCellTextImage = caf::ScalarMapperEffectGenerator::addAlphaAndUndefStripes(m_cellTextureImage.p(), m_undefinedColor, m_opacityLevel); } else { modifiedCellTextImage = new cvf::TextureImage; modifiedCellTextImage->allocate(2,1); modifiedCellTextImage->fill(cvf::Color4ub(cvf::Color4f(m_defaultCellColor, m_opacityLevel))); } cvf::ref edgeTexture = new cvf::Texture(m_edgeTextureImage.p()); cvf::ref cellTexture = new cvf::Texture(modifiedCellTextImage.p()); cvf::ref sampler = new cvf::Sampler; sampler->setWrapMode(cvf::Sampler::CLAMP_TO_EDGE); sampler->setMinFilter(cvf::Sampler::NEAREST); sampler->setMagFilter(cvf::Sampler::NEAREST); cvf::ref texBind = new cvf::RenderStateTextureBindings; texBind->addBinding(edgeTexture.p(), sampler.p(), "u_edgeTexture2D"); texBind->addBinding(cellTexture.p(), sampler.p(), "u_cellTexture2D"); eff->setRenderState(texBind.p()); // Polygon offset if (true) { cvf::ref polyOffset = new cvf::RenderStatePolygonOffset; polyOffset->configurePolygonPositiveOffset(); eff->setRenderState(polyOffset.p()); } // Simple transparency if (m_opacityLevel < 1.0f) { cvf::ref blender = new cvf::RenderStateBlending; blender->configureTransparencyBlending(); eff->setRenderState(blender.p()); } // Backface culling if (m_cullBackfaces) { cvf::ref faceCulling = new cvf::RenderStateCullFace; eff->setRenderState(faceCulling.p()); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void CellEdgeEffectGenerator::updateForFixedFunctionRendering(cvf::Effect* effect) const { caf::SurfaceEffectGenerator surfaceGen(cvf::Color4f(cvf::Color3f::CRIMSON), true); surfaceGen.updateEffect(effect); }