in src/esp/gfx/PbrDrawable.cpp [87:215]
void PbrDrawable::draw(const Mn::Matrix4& transformationMatrix,
Mn::SceneGraph::Camera3D& camera) {
CORRADE_ASSERT(glMeshExists(),
"PbrDrawable::draw() : GL mesh doesn't exist", );
updateShader()
.updateShaderLightParameters()
.updateShaderLightDirectionParameters(transformationMatrix, camera);
// ABOUT PbrShader::Flag::DoubleSided:
//
// "Specifies whether the material is double sided. When this value is false,
// back-face culling is enabled. When this value is true, back-face culling is
// disabled and double sided lighting is enabled. The back-face must have its
// normals reversed before the lighting equation is evaluated."
// See here:
// https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/schema/material.schema.json
// HOWEVER, WE CANNOT DISABLE BACK FACE CULLING (that is why the following
// code is commented out) since it causes lighting artifacts ("dashed lines")
// on hard edges. (maybe due to potential numerical issues? we do not know
// yet.)
/*
if ((flags_ & PbrShader::Flag::DoubleSided) && glIsEnabled(GL_CULL_FACE)) {
Mn::GL::Renderer::disable(Mn::GL::Renderer::Feature::FaceCulling);
}
*/
Mn::Matrix4 modelMatrix =
camera.cameraMatrix().inverted() * transformationMatrix;
(*shader_)
// e.g., semantic mesh has its own per vertex annotation, which has been
// uploaded to GPU so simply pass 0 to the uniform "objectId" in the
// fragment shader
.setObjectId(
static_cast<RenderCamera&>(camera).useDrawableIds()
? drawableId_
: (materialData_->perVertexObjectId ? 0 : node_.getSemanticId()))
.setProjectionMatrix(camera.projectionMatrix())
.setViewMatrix(camera.cameraMatrix())
.setModelMatrix(modelMatrix) // NOT modelview matrix!
.setNormalMatrix(modelMatrix.normalMatrix())
.setCameraWorldPosition(
camera.object().absoluteTransformationMatrix().translation())
.setBaseColor(materialData_->baseColor)
.setRoughness(materialData_->roughness)
.setMetallic(materialData_->metallic)
.setEmissiveColor(materialData_->emissiveColor);
// TODO:
// IN PbrShader class, we set the resonable defaults for the
// PbrShader::PbrEquationScales. Here we need a smart way to reset it
// just in case user would like to do so during the run-time.
if ((flags_ & PbrShader::Flag::BaseColorTexture) &&
(materialData_->baseColorTexture != nullptr)) {
shader_->bindBaseColorTexture(*materialData_->baseColorTexture);
}
if (flags_ &
(PbrShader::Flag::RoughnessTexture | PbrShader::Flag::MetallicTexture)) {
Magnum::GL::Texture2D* metallicRoughnessTexture =
materialData_->roughnessTexture;
if (!metallicRoughnessTexture) {
metallicRoughnessTexture = materialData_->metallicTexture;
}
CORRADE_ASSERT(metallicRoughnessTexture,
"PbrDrawable::draw(): texture pointer cannot be nullptr if "
"RoughnessTexture or MetallicTexture is enabled.", );
shader_->bindMetallicRoughnessTexture(*metallicRoughnessTexture);
}
if ((flags_ & PbrShader::Flag::NormalTexture) &&
(materialData_->normalTexture != nullptr)) {
shader_->bindNormalTexture(*materialData_->normalTexture);
}
if ((flags_ & PbrShader::Flag::EmissiveTexture) &&
(materialData_->emissiveTexture != nullptr)) {
shader_->bindEmissiveTexture(*materialData_->emissiveTexture);
}
if ((flags_ & PbrShader::Flag::TextureTransformation) &&
(materialData_->textureMatrix != Mn::Matrix3{})) {
shader_->setTextureMatrix(materialData_->textureMatrix);
}
// setup image based lighting for the shader
if (flags_ & PbrShader::Flag::ImageBasedLighting) {
CORRADE_INTERNAL_ASSERT(pbrIbl_);
shader_->bindIrradianceCubeMap( // TODO: HDR Color
pbrIbl_->getIrradianceMap().getTexture(CubeMap::TextureType::Color));
shader_->bindBrdfLUT(pbrIbl_->getBrdfLookupTable());
shader_->bindPrefilteredMap(
// TODO: HDR Color
pbrIbl_->getPrefilteredMap().getTexture(CubeMap::TextureType::Color));
shader_->setPrefilteredMapMipLevels(
pbrIbl_->getPrefilteredMap().getMipmapLevels());
}
if (flags_ & PbrShader::Flag::ShadowsVSM) {
CORRADE_INTERNAL_ASSERT(shadowMapManger_ && shadowMapKeys_);
CORRADE_ASSERT(shadowMapKeys_->size() <= 3,
"PbrDrawable::draw: the number of shadow maps exceeds the "
"maximum (current it is 3).", );
for (int iShadow = 0; iShadow < shadowMapKeys_->size(); ++iShadow) {
Mn::Resource<CubeMap> shadowMap =
(*shadowMapManger_).get<CubeMap>((*shadowMapKeys_)[iShadow]);
CORRADE_INTERNAL_ASSERT(shadowMap);
if (flags_ & PbrShader::Flag::ShadowsVSM) {
shader_->bindPointShadowMap(
iShadow,
shadowMap->getTexture(CubeMap::TextureType::VarianceShadowMap));
}
}
}
shader_->draw(getMesh());
// WE stopped supporting doubleSided material due to lighting artifacts on
// hard edges. See comments at the beginning of this function.
/*
if ((flags_ & PbrShader::Flag::DoubleSided) && !glIsEnabled(GL_CULL_FACE)) {
Mn::GL::Renderer::enable(Mn::GL::Renderer::Feature::FaceCulling);
}
*/
}