0
$\begingroup$

I built a gltf-viewer on my own, but the functionality for loading glf was implemented by referencing gltf-viewer-tutorial, the result is not correct. Below is my ouput for ToyCar.gltf my result. The ouput of that tutorial code looks like this: tutorial I think maybe I didn't bind the right texture? Here is my main render loop:

  for (const auto& model : info.scene->m_models) {
    for (const auto& mesh : model->get_meshes()) {
      // model ubo
      m_model_data.mvp_matrix    = m_camera_data.proj_view * mesh.model_matrix;
      m_model_data.mv_matrix     = m_camera_data.view * mesh.model_matrix;
      m_model_data.normal_matrix = glm::transpose(glm::inverse(m_model_data.mv_matrix));
      m_model_ubo->set_data(&m_model_data, sizeof(ModelData));
      // bind textures
      mesh.material.bind_all_textures();
      forward_shader.set_uniform("uBaseColorFactor", mesh.material.base_color_factor);
      if (mesh.material.has_component(PBRComponent::MetallicRoughness)) {
        forward_shader.set_uniform("uRoughnessFactor", (float)mesh.material.roughness_factor);
        forward_shader.set_uniform("uMetallicFactor", (float)mesh.material.metallic_factor);
      }
      if (mesh.material.has_component(PBRComponent::Emissive)) {
        forward_shader.set_uniform("uEmissiveFactor", mesh.material.emissive_factor);
      }
      if (mesh.material.has_component(PBRComponent::Occlusion)) {
        forward_shader.set_uniform("uOcclusionStrength", (float)mesh.material.occlusion_strength);
      }
      RenderAPI::draw_mesh(mesh);
    }
  }

And here is my texture binding logic:

  textures.at(PBRComponent::BaseColor)->bind(3);
  if (textures.contains(PBRComponent::MetallicRoughness))
    textures.at(PBRComponent::MetallicRoughness)->bind(4);
  if (textures.contains(PBRComponent::Emissive))
    textures.at(PBRComponent::Emissive)->bind(5);
  if (textures.contains(PBRComponent::Occlusion))
    textures.at(PBRComponent::Occlusion)->bind(6);

  void Texture2D::bind(GLenum slot) const {
    glBindTextureUnit(slot, m_id);
  }

Finally, here is my fragment shader:

#version 450

// A reference implementation can be found here:
// https://github.com/KhronosGroup/glTF-Sample-Viewer/blob/master/src/shaders/metallic-roughness.frag
// Here we implement a simpler version handling only one directional light and
// no normal map/opacity map

in vec3 vViewSpacePosition;
in vec3 vViewSpaceNormal;
in vec2 vTexCoords;
// Here we use vTexCoords but we should use vTexCoords1 or vTexCoords2 depending
// on the material because glTF can handle two texture coordinates sets per
// object see
// https://github.com/KhronosGroup/glTF-Sample-Viewer/blob/master/src/shaders/textures.glsl
// for a reference implementation

uniform vec3 uLightDirection;
uniform vec3 uLightIntensity;


uniform vec4 uBaseColorFactor;
uniform float uMetallicFactor;
uniform float uRoughnessFactor;
uniform vec3 uEmissiveFactor;
uniform float uOcclusionStrength;

layout(binding = 3) uniform sampler2D uBaseColorTexture;
layout(binding = 4) uniform sampler2D uMetallicRoughnessTexture;
layout(binding = 5) uniform sampler2D uEmissiveTexture;
layout(binding = 6) uniform sampler2D uOcclusionTexture;

uniform int uApplyOcclusion;

out vec3 fColor;

// Constants
const float GAMMA = 2.2;
const float INV_GAMMA = 1. / GAMMA;
const float M_PI = 3.141592653589793;
const float M_1_PI = 1.0 / M_PI;

// We need some simple tone mapping functions
// Basic gamma = 2.2 implementation
// Stolen here:
// https://github.com/KhronosGroup/glTF-Sample-Viewer/blob/master/src/shaders/tonemapping.glsl

// linear to sRGB approximation
// see http://chilliant.blogspot.com/2012/08/srgb-approximations-for-hlsl.html
vec3 linearTosRGB(vec3 color) { return pow(color, vec3(INV_GAMMA)); }

// sRGB to linear approximation
// see http://chilliant.blogspot.com/2012/08/srgb-approximations-for-hlsl.html

vec4 sRGBToLinear(vec4 srgbIn)
{
    return vec4(pow(srgbIn.xyz, vec3(GAMMA)), srgbIn.w);
}

// The model is mathematically described here
// https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#appendix-b-brdf-implementation
// We try to use the same or similar names for variables
// One thing that is not descibed in the documentation is that the BRDF value
// "f" must be multiplied by NdotL at the end.

void main()
{
    vec3 N = normalize(vViewSpaceNormal);
    vec3 V = normalize(-vViewSpacePosition);
    vec3 L = uLightDirection;
    vec3 H = normalize(L + V);

    vec4 baseColorFromTexture =
    sRGBToLinear(texture(uBaseColorTexture, vTexCoords));
    vec4 metallicRougnessFromTexture =
    texture(uMetallicRoughnessTexture, vTexCoords);

    vec4 baseColor = uBaseColorFactor * baseColorFromTexture;
    vec3 metallic = vec3(uMetallicFactor * metallicRougnessFromTexture.b);
    float roughness = uRoughnessFactor * metallicRougnessFromTexture.g;

    // https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#pbrmetallicroughnessmetallicroughnesstexture
    // "The metallic-roughness texture.The metalness values are sampled from the B
    // channel.The roughness values are sampled from the G channel."

    vec3 dielectricSpecular = vec3(0.04);
    vec3 black = vec3(0.);

    vec3 c_diff =
    mix(baseColor.rgb * (1 - dielectricSpecular.r), black, metallic);
    vec3 F_0 = mix(vec3(dielectricSpecular), baseColor.rgb, metallic);
    float alpha = roughness * roughness;

    float VdotH = clamp(dot(V, H), 0., 1.);
    float baseShlickFactor = 1 - VdotH;
    float shlickFactor = baseShlickFactor * baseShlickFactor; // power 2
    shlickFactor *= shlickFactor;                             // power 4
    shlickFactor *= baseShlickFactor;                         // power 5
    vec3 F = F_0 + (vec3(1) - F_0) * shlickFactor;

    float sqrAlpha = alpha * alpha;
    float NdotL = clamp(dot(N, L), 0., 1.);
    float NdotV = clamp(dot(N, V), 0., 1.);
    float visDenominator =
    NdotL * sqrt(NdotV * NdotV * (1 - sqrAlpha) + sqrAlpha) +
    NdotV * sqrt(NdotL * NdotL * (1 - sqrAlpha) + sqrAlpha);
    float Vis = visDenominator > 0. ? 0.5 / visDenominator : 0.0;

    float NdotH = clamp(dot(N, H), 0., 1.);
    float baseDenomD = (NdotH * NdotH * (sqrAlpha - 1.) + 1.);
    float D = M_1_PI * sqrAlpha / (baseDenomD * baseDenomD);

    vec3 f_specular = F * Vis * D;

    vec3 diffuse = c_diff * M_1_PI;

    vec3 f_diffuse = (1. - F) * diffuse;
    vec3 emissive = sRGBToLinear(texture(uEmissiveTexture, vTexCoords)).rgb * uEmissiveFactor;

    vec3 color = (f_diffuse + f_specular) * uLightIntensity * NdotL;
    color += emissive;

    if (1 == uApplyOcclusion) {
        float ao = texture(uOcclusionTexture, vTexCoords).r;
        color = mix(color, color * ao, uOcclusionStrength);
    }

    fColor = linearTosRGB(color);
}

I have been struggling with this bug for days and I still couldn't get it right. Here is my github repo for this project: My gltf-viewer

$\endgroup$

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Browse other questions tagged or ask your own question.