OpenB3D PBR Shader Demo

Started by Krischan, January 02, 2020, 00:03:18

Previous topic - Next topic

Krischan

#30
Yes the code has been reviewed and I tried to make it look like the Preview in Substance Player, Substance Painter or even Blender. I think it should be correct, at least visually. And Version 130 is minimum.

I tried to comment as much as possible, as it is a quite complex code. And there are still too many If...Then clauses in the Shader, this could be also optimized further. There is no self-shadowing implemented yet, a Relief Occlusion Mapping would look better then Parallax Occlusion (but also caused a system freeze here in Wireframe mode - I have to figure out what is wrong) and the reflections are static/generic (a cloud scene), but you can capture once a cubemap at the object's position and apply it that you have realistic per-object reflections.

One addition: in general, the combined PBR-Texture like Sketchfab and other tools use it is: R/G/B = AO/Roughness/Metallic plus a separate Heightmap texture. But I've decided to use the Heightmap instead of Metallic as the third one as not all textures are metallic, but all have a height. And so I can determine by the pure existence of a Metallic Texture that is is a Metal, which has a different reflection than a non-metal.

An alternative to that concept would be: add the Heightmap as the Alpha channel in the Basecolor Texture and use for the PBR the standard R/G/B = AO/Roughness/Metallic and always perform a quick check on loading (for example: sample points) over the Metallic Texture if it is black or "not so black". If it is black, it is not a metal (pure black also gives an awful reflection). This would save an additional texture to load.

But for now, I'm happy that it works so well in Blitzmax NG and OpenB3D.
Kind regards
Krischan

Windows 10 Pro | i7 9700K@ 3.6GHz | RTX 2080 8GB]
Metaverse | Blitzbasic Archive | My Github projects

Krischan

#31
I've found a bug in my Parallax Occlusion Mapping shader and fixed it (download link stays the same). I've also added a third small demo to show the Parallax Occlusion Mapping effect on a rounded cube only. You can play with the "POmulti" variable in the PBR.frag shader to intensify the effect.

ShaderExample_POM.jpg
Fixed pbr.vert shader:
#version 130

#define NUM_LIGHTS 8

// ----------------------------------------------------------------------------

struct FloatArray {
float Float;
};

// ----------------------------------------------------------------------------

// input variables
uniform float ambFactor;
uniform FloatArray lightradius[NUM_LIGHTS];

// ----------------------------------------------------------------------------

// output variables to fragment shader
out vec2 Vertex_UV;
out vec4 Vertex_Color;
out vec4 Vertex_Position;
out vec3 Vertex_View_Vector;
out vec3 Vertex_Surface_to_Viewer_Direction;
out vec3 Vertex_Normal;
out vec3 Vertex_Ambient_Color;
out vec3 Vertex_LightDir[NUM_LIGHTS];
out vec3 Vertex_LightColor[NUM_LIGHTS];
out float Vertex_LightRange[NUM_LIGHTS];
out float Vertex_LightDir_Length[NUM_LIGHTS];

// ----------------------------------------------------------------------------

void main()
{
Vertex_Color = gl_Color;
Vertex_Normal = normalize(gl_NormalMatrix * gl_Normal);
Vertex_Position = gl_ModelViewMatrix * gl_Vertex;

for (int i = 0; i < NUM_LIGHTS; ++i)
{
Vertex_LightDir[i] = gl_LightSource[i].position.xyz - Vertex_Position.xyz;
Vertex_LightDir_Length[i] = length(normalize(Vertex_LightDir[i]));
Vertex_LightColor[i] = gl_LightSource[i].diffuse.rgb;
Vertex_LightRange[i] = lightradius[i].Float;
}

Vertex_UV = gl_MultiTexCoord0.xy;
Vertex_Ambient_Color = gl_LightModel.ambient.rgb * ambFactor;
Vertex_View_Vector = -Vertex_Position.xyz;

vec3 vViewModelPosition = vec3(gl_ModelViewMatrixInverse * vec4(0, 0, 0, 1.0));
vec3 vLocalSurfaceToViewerDirection = normalize(vViewModelPosition-gl_Vertex.xyz);
vec3 vvLocalSurfaceNormal = normalize(gl_Normal);

Vertex_Surface_to_Viewer_Direction = normalize(reflect(vLocalSurfaceToViewerDirection, vvLocalSurfaceNormal)) ;

gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}

 Fixed pbr.frag shader:
#version 130

#define NUM_LIGHTS 8

// ----------------------------------------------------------------------------

struct FloatArray {
    float Float;
};

// ----------------------------------------------------------------------------

const float PI = 3.14159265359;
const float POscale = 0.05;
const float POmin = 8;
const float POmax = 32;
const float POmulti = 1.0;

// ----------------------------------------------------------------------------

uniform sampler2D albedoMap;
uniform sampler2D normalMap;
uniform sampler2D propMap;
uniform sampler2D metallicMap;
uniform sampler2D emissionMap;
uniform samplerCube envMap;

// ----------------------------------------------------------------------------

in vec2 Vertex_UV;
in vec2 Vertex_UVB;
in vec4 Vertex_Color;
in vec3 Vertex_Normal;
in vec3 Vertex_NormalCube;
in vec3 Vertex_Ambient_Color;
in vec3 Vertex_View_Vector;
in vec3 Vertex_Surface_to_Viewer_Direction;
in vec4 Vertex_Position;
in vec3 Vertex_LightDir[NUM_LIGHTS];
in vec3 Vertex_LightColor[NUM_LIGHTS];
in float Vertex_LightRange[NUM_LIGHTS];
in float Vertex_LightDir_Length[NUM_LIGHTS];

out vec4 FragColor;

// ----------------------------------------------------------------------------

// fixed values
uniform float levelscale;
uniform float gamma;
uniform vec2 texscale;
uniform vec2 texoffset;
uniform vec3 envPos;

// variable values
uniform FloatArray lightradius[NUM_LIGHTS];

// ----------------------------------------------------------------------------

// variable Flags
uniform int flagPB;
uniform int flagPM;
uniform int flagEN;
uniform int flagEM;
uniform int setENV;
uniform int isMetal;

// ----------------------------------------------------------------------------

// texture existance flags
uniform int texAL;
uniform int texNM;
uniform int texPR;
uniform int texME;
uniform int texEM;

// ----------------------------------------------------------------------------

// light attenuation variables
uniform float A;
uniform float B;

// ----------------------------------------------------------------------------

mat3 cotangent_frame(vec3 N, vec3 p, vec2 uv)
{
vec3 dp1 = dFdx(p);
vec3 dp2 = dFdy(p);
vec2 duv1 = dFdx(uv);
vec2 duv = dFdy(uv);
 
vec3 dp2perp = cross(dp2, N);
vec3 dp1perp = cross(N, dp1);
vec3 T = dp2perp * duv1.x + dp1perp * duv.x;
vec3 B = dp2perp * duv1.y + dp1perp * duv.y;
 
float invmax = inversesqrt(max(dot(T, T), dot(B, B)));
return mat3(T * invmax, B * invmax, N);
}

// ----------------------------------------------------------------------------

vec3 perturb_normal(vec3 N, vec3 V, vec3 map, vec2 texcoord)
{
map = map * 255.0 / 127.0 - 128.0 / 127.0;

mat3 TBN = cotangent_frame(N, -V, texcoord);
return normalize(TBN * map);
}

// ----------------------------------------------------------------------------

vec3 ToneMapPBR(vec3 color)
{
// HDR tonemapping and gamma correction
color = color / (color + vec3(1.0));
color = pow(color, vec3(1.0 / gamma));

return color;
}

// ----------------------------------------------------------------------------

float DistributionGGX(vec3 N, vec3 H, float roughness)
{
float a = roughness * roughness;
float a2 = a * a;
float NdotH = max(dot(N, H), 0.0);
float NdotH2 = NdotH * NdotH;

float nom = a2;
float denom = (NdotH2 * (a2 - 1.0) + 1.0);
denom = PI * denom * denom;

return nom / denom;
}

// ----------------------------------------------------------------------------

float GeometrySchlickGGX(float NdotV, float roughness)
{
float r = (roughness + 1.0);
float k = (r * r) / 8.0;

float nom = NdotV;
float denom = NdotV * (1.0 - k) + k;

return nom / denom;
}

// ----------------------------------------------------------------------------

float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness)
{
float NdotV = max(dot(N, V), 0.0);
float NdotL = max(dot(N, L), 0.0);
float ggx2 = GeometrySchlickGGX(NdotV, roughness);
float ggx1 = GeometrySchlickGGX(NdotL, roughness);

return ggx1 * ggx2;
}

// ----------------------------------------------------------------------------

vec3 fresnelSchlick(float cosTheta, vec3 F0)
{
if(cosTheta > 1.0)
cosTheta = 1.0;
float p = pow(1.0 - cosTheta,5.0);
return F0 + (1.0 - F0) * p;
}

// ----------------------------------------------------------------------------

float CalcAtt(float distance, float range, float a, float b)
{
return 1.0 / (1.0 + a * distance + b * distance * distance);
}

// ----------------------------------------------------------------------------

// Contrast Matrix
mat4 contrastMatrix(float contrast)
{
float t = ( 1.0 - contrast ) / 2.0;
   
return mat4(contrast, 0, 0, 0,
0, contrast, 0, 0,
0, 0, contrast, 0,
t, t, t, 1);

}

// ----------------------------------------------------------------------------

vec2 ParallaxOcclusionMapping(vec2 texCoords, vec3 viewDir)
{
    // number of depth layers
    float numLayers = mix(POmax, POmin, abs(dot(vec3(0.0, 0.0, 1.0), viewDir)));

    // calculate the size of each layer
    float layerDepth = 1.0 / numLayers;

    // depth of current layer
    float currentLayerDepth = 0.0;

    // the amount to shift the texture coordinates per layer (from vector P)
    vec2 P = viewDir.xy / viewDir.z * POscale * POmulti;
    vec2 deltaTexCoords = P / numLayers;

    // get initial values
    vec2  currentTexCoords     = texCoords;
    float currentDepthMapValue = texture(propMap, currentTexCoords).b;

    while(currentLayerDepth < currentDepthMapValue)
    {
        // shift texture coordinates along direction of P
        currentTexCoords -= deltaTexCoords;

        // get depthmap value at current texture coordinates
        currentDepthMapValue = texture(propMap, currentTexCoords).b;

        // get depth of next layer
        currentLayerDepth += layerDepth;
    }

    // get texture coordinates before collision (reverse operations)
    vec2 prevTexCoords = currentTexCoords + deltaTexCoords;

    // get depth after and before collision for linear interpolation
    float afterDepth  = currentDepthMapValue - currentLayerDepth;
    float beforeDepth = texture(propMap, prevTexCoords).b - currentLayerDepth + layerDepth;

    // interpolation of texture coordinates
    float weight = afterDepth / (afterDepth - beforeDepth);
    vec2 finalTexCoords = prevTexCoords * weight + currentTexCoords * (1.0 - weight);

    return finalTexCoords;
}

mat3 computeTBN(vec2 tempUv, vec3 worldPos, vec3 worldNormal){
    vec3 Q1  = dFdx(worldPos);
    vec3 Q2  = dFdy(worldPos);
    vec2 st1 = dFdx(tempUv);
    vec2 st2 = dFdy(tempUv);

    vec3 n   = normalize(worldNormal);
    vec3 t  = normalize(Q1*st2.t - Q2*st1.t);

    // or directly compute from the equation
    vec3 b = normalize(-Q1*st2.s + Q2*st1.s);

    mat3 tbn = mat3(t, b, n);

    return tbn;
}

// ----------------------------------------------------------------------------

void main()
{
// Texture coordinates
vec2 ts=texscale;
vec2 uv = Vertex_UV;
//ts.y=-ts.y;
uv = (uv * ts) + texoffset;

// TBN Matrix
vec3 VN = normalize(Vertex_Normal);
vec3 VV = Vertex_View_Vector;
//mat3 TBN = computeTBN(uv.st,-VV,Vertex_Normal);
mat3 TBN = cotangent_frame(VN, VV, uv.st);

// Parallax Mapping
if(flagPM > 0)
{
uv = ParallaxOcclusionMapping(uv, normalize(-VV * TBN));

}

// Albedo Texture
vec4 albedo = vec4(0.5, 0.5, 0.5, 1.0);
if(texAL > 0)
{
albedo = texture(albedoMap, uv);
albedo.rgb = pow(albedo.rgb, vec3(2.2));
}

// Normalmap Texture
vec3 nrm = Vertex_Normal;
if(texNM > 0)
{
nrm = texture(normalMap, uv).rgb;
//nrm.y=1.0-nrm.y;
}

// 3. Perturbated Normals
vec3 N = Vertex_Normal.xyz;
vec3 V = normalize(Vertex_View_Vector);
vec3 PN;
vec3 PNC;
if(texNM == 0)
{
PN = N;
nrm = vec3(0.0, 0.0, 1.0);
}
else
{
vec3 VN = normalize(N);
vec3 VV = normalize(Vertex_View_Vector);
//mat3 TBN = cotangent_frame(VN, -VV, uv.st);

PN = perturb_normal(VN, VV, nrm, uv);
PNC = perturb_normal(Vertex_NormalCube, VV, nrm, uv);
}

// PBR Texture
float ao = 1.0;
float roughness = 0.5;
float metallic = 0.5;

// Roughness
if(texPR > 0)
{
vec3 pbr = texture(propMap, uv).rgb;

ao = pbr.r;
roughness = pbr.g;
}

// Metallic
if(texME > 0)
{
metallic = texture(metallicMap, uv).r;
}

// Emissive
vec3 emission = vec3(0.0);
if(texEM > 0){emission = texture(emissionMap, uv).rgb * 2.0;}

// Ambient
vec3 ambient = Vertex_Ambient_Color * albedo.rgb;

// PBR Lighting
vec3 Lo = vec3(0.0);
vec3 irradiance;
vec3 diffuse=albedo.rgb;
vec3 reflectDir;

// Reflection
vec3 NormalizedRSTVD = normalize(Vertex_Surface_to_Viewer_Direction);

if(flagPB > 0)
{
// calculate reflectance at normal incidence; if dia-electric (like plastic) use F0
// of 0.04 and if it's a metal, use the albedo color as F0 (metallic workflow)   
vec3 F0 = vec3(0.04);
F0 = mix(F0, albedo.rgb, metallic);

for(int i = 0; i < NUM_LIGHTS; ++i)
{
// calculate per-light radiance
vec3 L = normalize(Vertex_LightDir[i]);
vec3 H = normalize(V + L);
float distance = Vertex_LightDir_Length[i];
float attenuation = CalcAtt(distance, Vertex_LightRange[i], A, B);
vec3 radiance = Vertex_LightColor[i] * attenuation;

// Cook-Torrance BRDF
float NDF = DistributionGGX(PN, H, roughness);
float G = GeometrySmith(PN, V, L, roughness);
vec3 F = fresnelSchlick(max(dot(H, V), 0.0), F0);
          
// specularity
vec3 nominator = NDF * G * F;
float denominator = 4.0 * max(dot(PN, V), 0.0) * max(dot(PN, L), 0.0) + 0.001;
vec3 specular = nominator / denominator;

// kS is equal to Fresnel
vec3 kS = F;

// for energy conservation, the diffuse and specular light can't
// be above 1.0 (unless the surface emits light); to preserve this
// relationship the diffuse component (kD) should equal 1.0 - kS.
vec3 kD = vec3(1.0) - kS;

// multiply kD by the inverse metalness such that only non-metals
// have diffuse lighting, or a linear blend if partly metal (pure metals
// have no diffuse light).
kD *= 1.0-metallic;

// Metallic Reflection --------------------------------------------

diffuse=albedo.rgb;

if(isMetal==1 && flagEN==1 && setENV==1)
{
vec3 v=NormalizedRSTVD;
irradiance = textureCube(envMap, vec3(-v.x,v.y,-v.z)).rgb;
diffuse = (albedo.rgb * (0.0 + (irradiance * 1.0)));
}

// check backface lighting
float NdotL = max(dot(PN, L), 0.0);

Lo += (kD * diffuse.rgb / PI + (specular)) * Vertex_LightRange[i] * radiance * NdotL;
}
}
// PBR off
else
{
for(int i = 0; i < NUM_LIGHTS; ++i)
{
float distance = Vertex_LightDir_Length[i];
float attenuation = CalcAtt(distance, Vertex_LightRange[i], A, B);
vec3 radiance = Vertex_LightColor[i] * attenuation;

vec3 L = normalize(Vertex_LightDir[i]);
vec3 N = Vertex_Normal.xyz;

float NdotL = max(dot(N, L), 0.0);
Lo += (diffuse.rgb / PI) * Vertex_LightRange[i] * radiance * NdotL;
}
}

// mix final lighting with ambient
vec3 color=(Lo+ambient);

// Ambient Occlusion
color *= ao;

// more contrast using normals and contrast matrix
float NL = max(dot(PN, normalize(Vertex_View_Vector)), 0.0);
color*=NL;
color.rgb*=(vec4(1.0) * contrastMatrix(2.0)).rgb;

// Tonemapping
color = ToneMapPBR(color);

// Gamma correction
color = pow(color, vec3(1.0/2.2));

if(flagEM==0){emission=vec3(0.0);}

// Final olor plus Emissive with Alpha
FragColor = vec4(color+emission, albedo.a);

}
Kind regards
Krischan

Windows 10 Pro | i7 9700K@ 3.6GHz | RTX 2080 8GB]
Metaverse | Blitzbasic Archive | My Github projects

markcwm

#32
Thanks again Krischan. Is 'Parallax occlusion' a type of bump mapping?

I've just tested in Windows 8.1 using OGL 4.3 and there is unfortunately an issue that makes the triple PBR example and POM example surfaces almost black, the minimal example shows as metallic red reflecting clouds but I'm not sure what it is supposed to look like. Here are some screenies.




As you can see there is a reflective surface in the POM example but only at certain angles but the triple PBR example is black at all angles.

It's likely that one of the GLSL commands doesn't work on my graphics card inputing zero data at some point. So here is the output of hardwareinfo.bmx to check if something is missing.

Hardwareinfo:

Width:  1366
Height: 768
Depth:  32
Hertz:  60

Vendor:         Intel
Renderer:       Intel(R) HD Graphics 4400
OpenGL-Version: 4.3.0 - Build 10.18.14.4414

Max Texture Units: 8
Max Texture Size:  16384
Max Lights:        8

OpenGL Extensions:
GL_EXT_blend_minmax
GL_EXT_blend_subtract
GL_EXT_blend_color
GL_EXT_abgr
GL_EXT_texture3D
GL_EXT_clip_volume_hint
GL_EXT_compiled_vertex_array
GL_SGIS_texture_edge_clamp
GL_SGIS_generate_mipmap
GL_EXT_draw_range_elements
GL_SGIS_texture_lod
GL_EXT_rescale_normal
GL_EXT_packed_pixels
GL_EXT_texture_edge_clamp
GL_EXT_separate_specular_color
GL_ARB_multitexture
GL_ARB_map_buffer_alignment
GL_ARB_conservative_depth
GL_EXT_texture_env_combine
GL_EXT_bgra
GL_EXT_blend_func_separate
GL_EXT_secondary_color
GL_EXT_fog_coord
GL_EXT_texture_env_add
GL_ARB_texture_cube_map
GL_ARB_transpose_matrix
GL_ARB_internalformat_query
GL_ARB_internalformat_query2
GL_ARB_texture_env_add
GL_IBM_texture_mirrored_repeat
GL_EXT_multi_draw_arrays
GL_SUN_multi_draw_arrays
GL_NV_blend_square
GL_ARB_texture_compression
GL_3DFX_texture_compression_FXT1
GL_EXT_texture_filter_anisotropic
GL_ARB_texture_border_clamp
GL_ARB_point_parameters
GL_ARB_texture_env_combine
GL_ARB_texture_env_dot3
GL_ARB_texture_env_crossbar
GL_EXT_texture_compression_s3tc
GL_ARB_shadow
GL_ARB_window_pos
GL_EXT_shadow_funcs
GL_EXT_stencil_wrap
GL_ARB_vertex_program
GL_EXT_texture_rectangle
GL_ARB_fragment_program
GL_EXT_stencil_two_side
GL_ATI_separate_stencil
GL_ARB_vertex_buffer_object
GL_EXT_texture_lod_bias
GL_ARB_occlusion_query
GL_ARB_fragment_shader
GL_ARB_shader_objects
GL_ARB_shading_language_100
GL_ARB_texture_non_power_of_two
GL_ARB_vertex_shader
GL_NV_texgen_reflection
GL_ARB_point_sprite
GL_ARB_fragment_program_shadow
GL_EXT_blend_equation_separate
GL_ARB_depth_texture
GL_ARB_texture_rectangle
GL_ARB_draw_buffers
GL_ARB_color_buffer_float
GL_ARB_half_float_pixel
GL_ARB_texture_float
GL_ARB_pixel_buffer_object
GL_EXT_framebuffer_object
GL_ARB_draw_instanced
GL_ARB_half_float_vertex
GL_ARB_occlusion_query2
GL_EXT_draw_buffers2
GL_WIN_swap_hint
GL_EXT_texture_sRGB
GL_ARB_multisample
GL_EXT_packed_float
GL_EXT_texture_shared_exponent
GL_ARB_texture_rg
GL_ARB_texture_compression_rgtc
GL_NV_conditional_render
GL_ARB_texture_swizzle
GL_EXT_texture_swizzle
GL_ARB_texture_gather
GL_ARB_sync
GL_ARB_cl_event
GL_ARB_framebuffer_sRGB
GL_EXT_packed_depth_stencil
GL_ARB_depth_buffer_float
GL_EXT_transform_feedback
GL_ARB_transform_feedback2
GL_ARB_draw_indirect
GL_EXT_framebuffer_blit
GL_EXT_framebuffer_multisample
GL_ARB_framebuffer_object
GL_ARB_framebuffer_no_attachments
GL_EXT_texture_array
GL_EXT_texture_integer
GL_ARB_map_buffer_range
GL_ARB_texture_buffer_range
GL_EXT_texture_snorm
GL_ARB_blend_func_extended
GL_INTEL_performance_query
GL_ARB_copy_buffer
GL_ARB_sampler_objects
GL_NV_primitive_restart
GL_ARB_seamless_cube_map
GL_ARB_uniform_buffer_object
GL_ARB_depth_clamp
GL_ARB_vertex_array_bgra
GL_ARB_shader_bit_encoding
GL_ARB_draw_buffers_blend
GL_ARB_geometry_shader4
GL_EXT_geometry_shader4
GL_ARB_texture_query_lod
GL_ARB_explicit_attrib_location
GL_ARB_draw_elements_base_vertex
GL_ARB_instanced_arrays
GL_ARB_base_instance
GL_ARB_fragment_coord_conventions
GL_EXT_gpu_program_parameters
GL_ARB_texture_buffer_object_rgb32
GL_ARB_compatibility
GL_ARB_texture_rgb10_a2ui
GL_ARB_texture_multisample
GL_ARB_vertex_type_2_10_10_10_rev
GL_ARB_timer_query
GL_ARB_tessellation_shader
GL_ARB_vertex_array_object
GL_ARB_provoking_vertex
GL_ARB_sample_shading
GL_ARB_texture_cube_map_array
GL_EXT_gpu_shader4
GL_ARB_gpu_shader5
GL_ARB_gpu_shader_fp64
GL_INTEL_fragment_shader_ordering
GL_ARB_fragment_shader_interlock
GL_ARB_clip_control
GL_ARB_shader_subroutine
GL_ARB_transform_feedback3
GL_ARB_get_program_binary
GL_ARB_separate_shader_objects
GL_ARB_shader_precision
GL_ARB_vertex_attrib_64bit
GL_ARB_viewport_array
GL_ARB_transform_feedback_instanced
GL_ARB_compressed_texture_pixel_storage
GL_ARB_shader_atomic_counters
GL_ARB_shading_language_packing
GL_ARB_shader_image_load_store
GL_ARB_shading_language_420pack
GL_ARB_texture_storage
GL_EXT_texture_storage
GL_ARB_compute_shader
GL_ARB_vertex_attrib_binding
GL_ARB_texture_view
GL_ARB_fragment_layer_viewport
GL_ARB_multi_draw_indirect
GL_ARB_program_interface_query
GL_ARB_shader_image_size
GL_ARB_shader_storage_buffer_object
GL_ARB_texture_storage_multisample
GL_ARB_buffer_storage
GL_AMD_vertex_shader_layer
GL_AMD_vertex_shader_viewport_index
GL_ARB_query_buffer_object
GL_EXT_polygon_offset_clamp
GL_ARB_debug_output
GL_KHR_debug
GL_ARB_arrays_of_arrays
GL_ARB_texture_query_levels
GL_ARB_invalidate_subdata
GL_ARB_clear_buffer_object
GL_ARB_texture_mirror_clamp_to_edge
GL_INTEL_map_texture
GL_ARB_texture_compression_bptc
GL_ARB_ES2_compatibility
GL_ARB_ES3_compatibility
GL_ARB_robustness
GL_ARB_robust_buffer_access_behavior
GL_EXT_texture_sRGB_decode
GL_ARB_copy_image
GL_KHR_blend_equation_advanced
GL_EXT_direct_state_access
GL_ARB_stencil_texturing
GL_ARB_texture_stencil8
GL_ARB_explicit_uniform_location

- Ready -

Process complete

Krischan

Hmm you are using a Intel graphics card, this may not work correct there. On my Nvidia it looks like that (and has two times the extensions like the Intel)

Hardwareinfo:

Width:  3840
Height: 1600
Depth:  32
Hertz:  75

Vendor:         NVIDIA Corporation
Renderer:       NVIDIA GeForce RTX 2080/PCIe/SSE2
OpenGL-Version: 4.6.0 NVIDIA 528.49

Max Texture Units: 4
Max Texture Size:  32768
Max Lights:        8

OpenGL Extensions:
GL_AMD_multi_draw_indirect
GL_AMD_seamless_cubemap_per_texture
GL_AMD_vertex_shader_viewport_index
GL_AMD_vertex_shader_layer
GL_ARB_arrays_of_arrays
GL_ARB_base_instance
GL_ARB_bindless_texture
GL_ARB_blend_func_extended
GL_ARB_buffer_storage
GL_ARB_clear_buffer_object
GL_ARB_clear_texture
GL_ARB_clip_control
GL_ARB_color_buffer_float
GL_ARB_compatibility
GL_ARB_compressed_texture_pixel_storage
GL_ARB_conservative_depth
GL_ARB_compute_shader
GL_ARB_compute_variable_group_size
GL_ARB_conditional_render_inverted
GL_ARB_copy_buffer
GL_ARB_copy_image
GL_ARB_cull_distance
GL_ARB_debug_output
GL_ARB_depth_buffer_float
GL_ARB_depth_clamp
GL_ARB_depth_texture
GL_ARB_derivative_control
GL_ARB_direct_state_access
GL_ARB_draw_buffers
GL_ARB_draw_buffers_blend
GL_ARB_draw_indirect
GL_ARB_draw_elements_base_vertex
GL_ARB_draw_instanced
GL_ARB_enhanced_layouts
GL_ARB_ES2_compatibility
GL_ARB_ES3_compatibility
GL_ARB_ES3_1_compatibility
GL_ARB_ES3_2_compatibility
GL_ARB_explicit_attrib_location
GL_ARB_explicit_uniform_location
GL_ARB_fragment_coord_conventions
GL_ARB_fragment_layer_viewport
GL_ARB_fragment_program
GL_ARB_fragment_program_shadow
GL_ARB_fragment_shader
GL_ARB_fragment_shader_interlock
GL_ARB_framebuffer_no_attachments
GL_ARB_framebuffer_object
GL_ARB_framebuffer_sRGB
GL_ARB_geometry_shader4
GL_ARB_get_program_binary
GL_ARB_get_texture_sub_image
GL_ARB_gl_spirv
GL_ARB_gpu_shader5
GL_ARB_gpu_shader_fp64
GL_ARB_gpu_shader_int64
GL_ARB_half_float_pixel
GL_ARB_half_float_vertex
GL_ARB_imaging
GL_ARB_indirect_parameters
GL_ARB_instanced_arrays
GL_ARB_internalformat_query
GL_ARB_internalformat_query2
GL_ARB_invalidate_subdata
GL_ARB_map_buffer_alignment
GL_ARB_map_buffer_range
GL_ARB_multi_bind
GL_ARB_multi_draw_indirect
GL_ARB_multisample
GL_ARB_multitexture
GL_ARB_occlusion_query
GL_ARB_occlusion_query2
GL_ARB_parallel_shader_compile
GL_ARB_pipeline_statistics_query
GL_ARB_pixel_buffer_object
GL_ARB_point_parameters
GL_ARB_point_sprite
GL_ARB_polygon_offset_clamp
GL_ARB_post_depth_coverage
GL_ARB_program_interface_query
GL_ARB_provoking_vertex
GL_ARB_query_buffer_object
GL_ARB_robust_buffer_access_behavior
GL_ARB_robustness
GL_ARB_sample_locations
GL_ARB_sample_shading
GL_ARB_sampler_objects
GL_ARB_seamless_cube_map
GL_ARB_seamless_cubemap_per_texture
GL_ARB_separate_shader_objects
GL_ARB_shader_atomic_counter_ops
GL_ARB_shader_atomic_counters
GL_ARB_shader_ballot
GL_ARB_shader_bit_encoding
GL_ARB_shader_clock
GL_ARB_shader_draw_parameters
GL_ARB_shader_group_vote
GL_ARB_shader_image_load_store
GL_ARB_shader_image_size
GL_ARB_shader_objects
GL_ARB_shader_precision
GL_ARB_shader_storage_buffer_object
GL_ARB_shader_subroutine
GL_ARB_shader_texture_image_samples
GL_ARB_shader_texture_lod
GL_ARB_shading_language_100
GL_ARB_shader_viewport_layer_array
GL_ARB_shading_language_420pack
GL_ARB_shading_language_include
GL_ARB_shading_language_packing
GL_ARB_shadow
GL_ARB_sparse_buffer
GL_ARB_sparse_texture
GL_ARB_sparse_texture2
GL_ARB_sparse_texture_clamp
GL_ARB_spirv_extensions
GL_ARB_stencil_texturing
GL_ARB_sync
GL_ARB_tessellation_shader
GL_ARB_texture_barrier
GL_ARB_texture_border_clamp
GL_ARB_texture_buffer_object
GL_ARB_texture_buffer_object_rgb32
GL_ARB_texture_buffer_range
GL_ARB_texture_compression
GL_ARB_texture_compression_bptc
GL_ARB_texture_compression_rgtc
GL_ARB_texture_cube_map
GL_ARB_texture_cube_map_array
GL_ARB_texture_env_add
GL_ARB_texture_env_combine
GL_ARB_texture_env_crossbar
GL_ARB_texture_env_dot3
GL_ARB_texture_filter_anisotropic
GL_ARB_texture_filter_minmax
GL_ARB_texture_float
GL_ARB_texture_gather
GL_ARB_texture_mirror_clamp_to_edge
GL_ARB_texture_mirrored_repeat
GL_ARB_texture_multisample
GL_ARB_texture_non_power_of_two
GL_ARB_texture_query_levels
GL_ARB_texture_query_lod
GL_ARB_texture_rectangle
GL_ARB_texture_rg
GL_ARB_texture_rgb10_a2ui
GL_ARB_texture_stencil8
GL_ARB_texture_storage
GL_ARB_texture_storage_multisample
GL_ARB_texture_swizzle
GL_ARB_texture_view
GL_ARB_timer_query
GL_ARB_transform_feedback2
GL_ARB_transform_feedback3
GL_ARB_transform_feedback_instanced
GL_ARB_transform_feedback_overflow_query
GL_ARB_transpose_matrix
GL_ARB_uniform_buffer_object
GL_ARB_vertex_array_bgra
GL_ARB_vertex_array_object
GL_ARB_vertex_attrib_64bit
GL_ARB_vertex_attrib_binding
GL_ARB_vertex_buffer_object
GL_ARB_vertex_program
GL_ARB_vertex_shader
GL_ARB_vertex_type_10f_11f_11f_rev
GL_ARB_vertex_type_2_10_10_10_rev
GL_ARB_viewport_array
GL_ARB_window_pos
GL_ATI_draw_buffers
GL_ATI_texture_float
GL_ATI_texture_mirror_once
GL_S3_s3tc
GL_EXT_texture_env_add
GL_EXT_abgr
GL_EXT_bgra
GL_EXT_bindable_uniform
GL_EXT_blend_color
GL_EXT_blend_equation_separate
GL_EXT_blend_func_separate
GL_EXT_blend_minmax
GL_EXT_blend_subtract
GL_EXT_compiled_vertex_array
GL_EXT_Cg_shader
GL_EXT_depth_bounds_test
GL_EXT_direct_state_access
GL_EXT_draw_buffers2
GL_EXT_draw_instanced
GL_EXT_draw_range_elements
GL_EXT_fog_coord
GL_EXT_framebuffer_blit
GL_EXT_framebuffer_multisample
GL_EXTX_framebuffer_mixed_formats
GL_EXT_framebuffer_multisample_blit_scaled
GL_EXT_framebuffer_object
GL_EXT_framebuffer_sRGB
GL_EXT_geometry_shader4
GL_EXT_gpu_program_parameters
GL_EXT_gpu_shader4
GL_EXT_multi_draw_arrays
GL_EXT_multiview_texture_multisample
GL_EXT_multiview_timer_query
GL_EXT_packed_depth_stencil
GL_EXT_packed_float
GL_EXT_packed_pixels
GL_EXT_pixel_buffer_object
GL_EXT_point_parameters
GL_EXT_polygon_offset_clamp
GL_EXT_post_depth_coverage
GL_EXT_provoking_vertex
GL_EXT_raster_multisample
GL_EXT_rescale_normal
GL_EXT_secondary_color
GL_EXT_separate_shader_objects
GL_EXT_separate_specular_color
GL_EXT_shader_image_load_formatted
GL_EXT_shader_image_load_store
GL_EXT_shader_integer_mix
GL_EXT_shadow_funcs
GL_EXT_sparse_texture2
GL_EXT_stencil_two_side
GL_EXT_stencil_wrap
GL_EXT_texture3D
GL_EXT_texture_array
GL_EXT_texture_buffer_object
GL_EXT_texture_compression_dxt1
GL_EXT_texture_compression_latc
GL_EXT_texture_compression_rgtc
GL_EXT_texture_compression_s3tc
GL_EXT_texture_cube_map
GL_EXT_texture_edge_clamp
GL_EXT_texture_env_combine
GL_EXT_texture_env_dot3
GL_EXT_texture_filter_anisotropic
GL_EXT_texture_filter_minmax
GL_EXT_texture_integer
GL_EXT_texture_lod
GL_EXT_texture_lod_bias
GL_EXT_texture_mirror_clamp
GL_EXT_texture_object
GL_EXT_texture_shadow_lod
GL_EXT_texture_shared_exponent
GL_EXT_texture_sRGB
GL_EXT_texture_sRGB_R8
GL_EXT_texture_sRGB_decode
GL_EXT_texture_storage
GL_EXT_texture_swizzle
GL_EXT_timer_query
GL_EXT_transform_feedback2
GL_EXT_vertex_array
GL_EXT_vertex_array_bgra
GL_EXT_vertex_attrib_64bit
GL_EXT_window_rectangles
GL_EXT_import_sync_object
GL_IBM_rasterpos_clip
GL_IBM_texture_mirrored_repeat
GL_KHR_context_flush_control
GL_KHR_debug
GL_EXT_memory_object
GL_EXT_memory_object_win32
GL_NV_memory_object_sparse
GL_EXT_win32_keyed_mutex
GL_KHR_parallel_shader_compile
GL_KHR_no_error
GL_KHR_robust_buffer_access_behavior
GL_KHR_robustness
GL_EXT_semaphore
GL_EXT_semaphore_win32
GL_NV_timeline_semaphore
GL_KHR_shader_subgroup
GL_KTX_buffer_region
GL_NV_alpha_to_coverage_dither_control
GL_NV_bindless_multi_draw_indirect
GL_NV_bindless_multi_draw_indirect_count
GL_NV_bindless_texture
GL_NV_blend_equation_advanced
GL_NV_blend_equation_advanced_coherent
GL_NVX_blend_equation_advanced_multi_draw_buffers
GL_NV_blend_minmax_factor
GL_NV_blend_square
GL_NV_clip_space_w_scaling
GL_NV_command_list
GL_NV_compute_program5
GL_NV_compute_shader_derivatives
GL_NV_conditional_render
GL_NV_conservative_raster
GL_NV_conservative_raster_dilate
GL_NV_conservative_raster_pre_snap
GL_NV_conservative_raster_pre_snap_triangles
GL_NV_conservative_raster_underestimation
GL_NV_copy_depth_to_color
GL_NV_copy_image
GL_NV_depth_buffer_float
GL_NV_depth_clamp
GL_NV_draw_texture
GL_NV_draw_vulkan_image
GL_NV_ES1_1_compatibility
GL_NV_ES3_1_compatibility
GL_NV_explicit_multisample
GL_NV_feature_query
GL_NV_fence
GL_NV_fill_rectangle
GL_NV_float_buffer
GL_NV_fog_distance
GL_NV_fragment_coverage_to_color
GL_NV_fragment_program
GL_NV_fragment_program_option
GL_NV_fragment_program2
GL_NV_fragment_shader_barycentric
GL_NV_fragment_shader_interlock
GL_NV_framebuffer_mixed_samples
GL_NV_framebuffer_multisample_coverage
GL_NV_geometry_shader4
GL_NV_geometry_shader_passthrough
GL_NV_gpu_program4
GL_NV_internalformat_sample_query
GL_NV_gpu_program4_1
GL_NV_gpu_program5
GL_NV_gpu_program5_mem_extended
GL_NV_gpu_program_fp64
GL_NV_gpu_shader5
GL_NV_half_float
GL_NV_light_max_exponent
GL_NV_memory_attachment
GL_NV_mesh_shader
GL_NV_multisample_coverage
GL_NV_multisample_filter_hint
GL_NV_occlusion_query
GL_NV_packed_depth_stencil
GL_NV_parameter_buffer_object
GL_NV_parameter_buffer_object2
GL_NV_path_rendering
GL_NV_path_rendering_shared_edge
GL_NV_pixel_data_range
GL_NV_point_sprite
GL_NV_primitive_restart
GL_NV_query_resource
GL_NV_query_resource_tag
GL_NV_register_combiners
GL_NV_register_combiners2
GL_NV_representative_fragment_test
GL_NV_sample_locations
GL_NV_sample_mask_override_coverage
GL_NV_scissor_exclusive
GL_NV_shader_atomic_counters
GL_NV_shader_atomic_float
GL_NV_shader_atomic_float64
GL_NV_shader_atomic_fp16_vector
GL_NV_shader_atomic_int64
GL_NV_shader_buffer_load
GL_NV_shader_storage_buffer_object
GL_NV_shader_subgroup_partitioned
GL_NV_shader_texture_footprint
GL_NV_shading_rate_image
GL_NV_stereo_view_rendering
GL_NV_texgen_reflection
GL_NV_texture_barrier
GL_NV_texture_compression_vtc
GL_NV_texture_env_combine4
GL_NV_texture_multisample
GL_NV_texture_rectangle
GL_NV_texture_rectangle_compressed
GL_NV_texture_shader
GL_NV_texture_shader2
GL_NV_texture_shader3
GL_NV_transform_feedback
GL_NV_transform_feedback2
GL_NV_uniform_buffer_unified_memory
GL_NV_uniform_buffer_std430_layout
GL_NV_vertex_array_range
GL_NV_vertex_array_range2
GL_NV_vertex_attrib_integer_64bit
GL_NV_vertex_buffer_unified_memory
GL_NV_vertex_program
GL_NV_vertex_program1_1
GL_NV_vertex_program2
GL_NV_vertex_program2_option
GL_NV_vertex_program3
GL_NV_viewport_array2
GL_NV_viewport_swizzle
GL_NVX_conditional_render
GL_NVX_linked_gpu_multicast
GL_NV_gpu_multicast
GL_NVX_gpu_multicast2
GL_NVX_progress_fence
GL_NVX_gpu_memory_info
GL_NVX_multigpu_info
GL_NVX_nvenc_interop
GL_NV_shader_thread_group
GL_NV_shader_thread_shuffle
GL_KHR_blend_equation_advanced
GL_KHR_blend_equation_advanced_coherent
GL_OVR_multiview
GL_OVR_multiview2
GL_SGIS_generate_mipmap
GL_SGIS_texture_lod
GL_SGIX_depth_texture
GL_SGIX_shadow
GL_SUN_slice_accum
GL_WIN_swap_hint
WGL_EXT_swap_control

- Ready -
Kind regards
Krischan

Windows 10 Pro | i7 9700K@ 3.6GHz | RTX 2080 8GB]
Metaverse | Blitzbasic Archive | My Github projects

Krischan

I've run it on my second rig which has an AMD processor with built-in graphics and I'm getting the same result like you, here is the log. The question is: why does it run on Nvidia, but not on Intel/AMD?

Hardwareinfo:

Width:  2560
Height: 1440
Depth:  32
Hertz:  59

Vendor:         ATI Technologies Inc.
Renderer:       AMD Radeon(TM) Graphics
OpenGL-Version: 4.6.0 Compatibility Profile Context 22.20.42.221019

Max Texture Units: 8
Max Texture Size:  16384
Max Lights:        8

OpenGL Extensions:
GL_EXT_abgr
GL_EXT_blend_color
GL_EXT_blend_minmax
GL_EXT_blend_subtract
GL_EXT_texture_object
GL_EXT_vertex_array
GL_EXT_compiled_vertex_array
GL_EXT_texture3D
GL_EXT_bgra
GL_EXT_draw_range_elements
GL_EXT_point_parameters
GL_EXT_texture_edge_clamp
GL_ARB_multitexture
GL_ARB_multisample
GL_ARB_texture_cube_map
GL_ARB_texture_env_add
GL_ARB_transpose_matrix
GL_EXT_blend_func_separate
GL_EXT_fog_coord
GL_EXT_multi_draw_arrays
GL_EXT_secondary_color
GL_EXT_texture_env_add
GL_EXT_texture_filter_anisotropic
GL_EXT_texture_lod
GL_EXT_texture_lod_bias
GL_NV_blend_square
WGL_EXT_swap_control
GL_ARB_point_parameters
GL_ARB_texture_border_clamp
GL_ARB_texture_compression
GL_EXT_texture_compression_s3tc
GL_EXT_texture_env_combine
GL_EXT_texture_env_dot3
GL_ARB_shadow
GL_ARB_shadow_ambient
GL_ARB_texture_env_combine
GL_ARB_texture_env_dot3
GL_ARB_depth_texture
GL_ARB_fragment_program
GL_ARB_vertex_program
GL_ARB_window_pos
GL_ATI_draw_buffers
GL_ATI_texture_env_combine3
GL_EXT_shadow_funcs
GL_EXT_stencil_wrap
GL_EXT_texture_rectangle
GL_NV_primitive_restart
GL_S3_s3tc
GL_ARB_fragment_program_shadow
GL_ARB_fragment_shader
GL_ARB_occlusion_query
GL_ARB_point_sprite
GL_ARB_shader_objects
GL_ARB_shading_language_100
GL_ARB_texture_non_power_of_two
GL_ARB_vertex_buffer_object
GL_ARB_vertex_shader
GL_EXT_blend_equation_separate
GL_EXT_depth_bounds_test
GL_ARB_color_buffer_float
GL_ARB_draw_buffers
GL_ARB_half_float_pixel
GL_ARB_pixel_buffer_object
GL_ARB_texture_float
GL_ARB_texture_rectangle
GL_EXT_framebuffer_object
GL_EXT_pixel_buffer_object
GL_OES_draw_texture
GL_EXT_framebuffer_blit
GL_EXT_framebuffer_multisample
GL_EXT_packed_depth_stencil
GL_EXT_texture_format_BGRA8888
GL_ATI_separate_stencil
GL_ATI_shader_texture_lod
GL_EXT_draw_buffers2
GL_EXT_framebuffer_sRGB
GL_EXT_geometry_shader4
GL_EXT_gpu_program_parameters
GL_EXT_gpu_shader4
GL_EXT_texture_array
GL_EXT_texture_buffer_object
GL_EXT_texture_compression_latc
GL_EXT_texture_compression_rgtc
GL_EXT_texture_integer
GL_EXT_transform_feedback
GL_NV_depth_buffer_float
GL_OES_EGL_image
GL_EXT_provoking_vertex
GL_EXT_texture_sRGB
GL_EXT_texture_shared_exponent
GL_ARB_depth_buffer_float
GL_ARB_draw_instanced
GL_ARB_framebuffer_object
GL_ARB_framebuffer_sRGB
GL_ARB_geometry_shader4
GL_ARB_half_float_vertex
GL_ARB_instanced_arrays
GL_ARB_map_buffer_range
GL_ARB_texture_buffer_object
GL_ARB_texture_compression_rgtc
GL_ARB_texture_rg
GL_ARB_transform_feedback
GL_ARB_vertex_array_object
GL_EXT_direct_state_access
GL_EXT_texture_snorm
GL_ARB_compatibility
GL_ARB_copy_buffer
GL_ARB_depth_clamp
GL_ARB_draw_buffers_blend
GL_ARB_draw_elements_base_vertex
GL_ARB_fragment_coord_conventions
GL_ARB_sample_shading
GL_ARB_seamless_cube_map
GL_ARB_shader_texture_lod
GL_ARB_sync
GL_ARB_texture_cube_map_array
GL_ARB_texture_gather
GL_ARB_texture_multisample
GL_ARB_texture_multisample_no_array
GL_ARB_uniform_buffer_object
GL_ATI_meminfo
GL_EXT_texture_storage
GL_NV_copy_image
GL_NV_texture_barrier
GL_AMD_blend_minmax_factor
GL_AMD_depth_clamp_separate
GL_AMD_sample_positions
GL_ARB_ES2_compatibility
GL_ARB_base_instance
GL_ARB_blend_func_extended
GL_ARB_debug_output
GL_ARB_draw_indirect
GL_ARB_explicit_attrib_location
GL_ARB_get_program_binary
GL_ARB_gpu_shader5
GL_ARB_gpu_shader_fp64
GL_ARB_occlusion_query2
GL_ARB_robustness
GL_ARB_sampler_objects
GL_ARB_separate_shader_objects
GL_ARB_shader_bit_encoding
GL_ARB_shader_precision
GL_ARB_shader_stencil_export
GL_ARB_shader_subroutine
GL_ARB_tessellation_shader
GL_ARB_texture_compression_bptc
GL_ARB_texture_rgb10_a2ui
GL_ARB_texture_swizzle
GL_ARB_timer_query
GL_ARB_transform_feedback2
GL_ARB_transform_feedback3
GL_ARB_vertex_attrib_64bit
GL_ARB_viewport_array
GL_EXT_shader_image_load_store
GL_EXT_texture_sRGB_decode
GL_AMD_bus_addressable_memory
GL_AMD_pinned_memory
GL_ARB_conservative_depth
GL_ARB_internalformat_query
GL_ARB_shader_atomic_counters
GL_ARB_shader_image_load_store
GL_ARB_shading_language_420pack
GL_ARB_texture_storage
GL_ARB_transform_feedback_instanced
GL_EXT_color_buffer_half_float
GL_EXT_debug_label
GL_AMD_shader_trinary_minmax
GL_ARB_ES3_compatibility
GL_ARB_arrays_of_arrays
GL_ARB_clear_buffer_object
GL_ARB_compute_shader
GL_ARB_copy_image
GL_ARB_explicit_uniform_location
GL_ARB_fragment_layer_viewport
GL_ARB_framebuffer_no_attachments
GL_ARB_internalformat_query2
GL_ARB_invalidate_subdata
GL_ARB_multi_draw_indirect
GL_ARB_program_interface_query
GL_ARB_shader_image_size
GL_ARB_shader_storage_buffer_object
GL_ARB_stencil_texturing
GL_ARB_texture_buffer_range
GL_ARB_texture_storage_multisample
GL_ARB_texture_view
GL_ARB_vertex_attrib_binding
GL_EXT_copy_buffer
GL_KHR_debug
GL_AMD_gpu_shader_half_float
GL_AMD_gpu_shader_int64
GL_ARB_bindless_texture
GL_ARB_buffer_storage
GL_ARB_clear_texture
GL_ARB_enhanced_layouts
GL_ARB_indirect_parameters
GL_ARB_multi_bind
GL_ARB_query_buffer_object
GL_ARB_shader_draw_parameters
GL_ARB_shader_group_vote
GL_ARB_sparse_texture
GL_ARB_texture_stencil8
GL_EXT_copy_image
GL_EXT_draw_buffers_indexed
GL_EXT_geometry_point_size
GL_EXT_gpu_shader5
GL_EXT_sRGB_write_control
GL_EXT_shader_integer_mix
GL_EXT_shader_io_blocks
GL_EXT_tessellation_point_size
GL_EXT_tessellation_shader
GL_EXT_texture_border_clamp
GL_EXT_texture_buffer
GL_EXT_timer_query
GL_KHR_blend_equation_advanced
GL_KHR_blend_equation_advanced_coherent
GL_NV_shader_atomic_int64
GL_ARB_clip_control
GL_ARB_conditional_render_inverted
GL_ARB_cull_distance
GL_ARB_derivative_control
GL_ARB_direct_state_access
GL_ARB_get_texture_sub_image
GL_ARB_pipeline_statistics_query
GL_ARB_shader_texture_image_samples
GL_ARB_sparse_buffer
GL_ARB_texture_barrier
GL_ARB_transform_feedback_overflow_query
GL_EXT_polygon_offset_clamp
GL_EXT_render_snorm
GL_KHR_robust_buffer_access_behavior
GL_KHR_robustness
GL_OVR_multiview
GL_ARB_gpu_shader_int64
GL_ARB_parallel_shader_compile
GL_ARB_shader_ballot
GL_ARB_shader_clock
GL_ARB_shader_viewport_layer_array
GL_ARB_texture_filter_minmax
GL_EXT_texture_sRGB_R8
GL_EXT_texture_sRGB_RG8
GL_KHR_no_error
GL_OVR_multiview2
GL_OVR_multiview_multisampled_render_to_texture
GL_ARB_gl_spirv
GL_EXT_clip_cull_distance
GL_EXT_memory_object
GL_EXT_memory_object_win32
GL_EXT_semaphore
GL_EXT_semaphore_win32
GL_AMD_gpu_shader_int16
GL_ARB_polygon_offset_clamp
GL_ARB_texture_filter_anisotropic
GL_EXT_texture_compression_bptc
GL_KHR_parallel_shader_compile

- Ready -
Kind regards
Krischan

Windows 10 Pro | i7 9700K@ 3.6GHz | RTX 2080 8GB]
Metaverse | Blitzbasic Archive | My Github projects

Krischan

The problem lies somewhere in the shader. When you comment the whole main() section of the fragment shader between the brackets and just use

FragColor=vec4(1.0,0.0,0.0,1.0);

as a single command in there, you'll get nice red models. Unless you start uncommenting the next lines in the main() section and reach this line:

vec2 uv = Vertex_UV;

It looks like the shader crashes (=turns black everything) when it retrieves the data from the Vertex Shader. I don't know why but this is the problem. I must check this further.
Kind regards
Krischan

Windows 10 Pro | i7 9700K@ 3.6GHz | RTX 2080 8GB]
Metaverse | Blitzbasic Archive | My Github projects

Krischan

It looks like AMD and Nvidia interpret the GL standard differently, AMD very strictly and Nvidia very casually. I was able to narrow down the problem in the vertex shader to the float array I use for the lights, but the fragment shader is giving me a headache.

I always cross-checked the shaders with the "glslangValidator" validator tool from the Khronos Group, which gave me no errors. But the ATI tools, well, hahaha, a whole bunch. Some errors I don't understand yet. So the best practice is to make  sure that these tools throw out no errors at all and the code must be tested on ATI, Intel and Nvidia.

KhronosGroup glslang tools (release and debug)
https://github.com/KhronosGroup/glslang/releases/tag/master-tot

Radeon GPU Analyzer (Radeon Developer Tool Suite, runs even if you dont have an ATI card)
https://gpuopen.com/rga/#download

GPU ShaderAnalyzer (older variant of the GPU Analyzer above, but still works)
https://gpuopen.com/archived/gpu-shaderanalyzer/
Kind regards
Krischan

Windows 10 Pro | i7 9700K@ 3.6GHz | RTX 2080 8GB]
Metaverse | Blitzbasic Archive | My Github projects

angros47

#37
Quick question: is it possible that it's just related to the number of lights? The previous version for me didn't work because too many parameters were passed to the shader, by reducing the number of light I removed the error message

Also, try replacing "#version 130" with "#version 130 compatibility". On my OpenB3DPlus I had to add that in a shader to get it to work

Krischan

Quote from: angros47 on March 05, 2023, 16:05:42Quick question: is it possible that it's just related to the number of lights? The previous version for me didn't work because too many parameters were passed to the shader, by reducing the number of light I removed the error message

Also, try replacing "#version 130" with "#version 130 compatibility". On my OpenB3DPlus I had to add that in a shader to get it to work
WOW that is the solution! For an unknown reason, no more than 6 lights work on my AMD while 8 work on Nvidia. Even if the AMD hardware info responds with "8 lights", like the Nvidia does, too. But why is that?

So as a quick workaround, change in both shaders

#define NUM_LIGHTS 8 to "#define NUM_LIGHTS 6
Kind regards
Krischan

Windows 10 Pro | i7 9700K@ 3.6GHz | RTX 2080 8GB]
Metaverse | Blitzbasic Archive | My Github projects

angros47

It has to do with the limit of how many uniforms can be passed to a shader. Some video cards can accept more than others, but the Intel driver is a generic one, and it accepts the minimum, it seems. This is actually good for developing, because if a shader works on the Intel driver, it works everywhere

Krischan

What if I want to use more than 8 lights? Yes, I know there is a OpenGL Hardware lights limit of 8 but I could also pass - instead of the OpenGL light position/color data using the gl_LightSource function - the pivot and array data of virtual fake lights and process them in the shader. But when I can only pass 6 uniforms this is getting complex, maybe using two separate arrays for light 1-6 and light 7-12?

So 8 lights could still work with two arrays of 4
Kind regards
Krischan

Windows 10 Pro | i7 9700K@ 3.6GHz | RTX 2080 8GB]
Metaverse | Blitzbasic Archive | My Github projects

angros47

The earliest version of your shader worked with 8 lights, because each light used less parameters, and so it didn't reach the limit. Anyway, it is possible to use more than 8 lights, but you can't pass them with gl_LightSource. You must pass the light matrix as a generic matrix (it is what is done in OpenB3D ES version, have a look at the file "shaders.cpp" to see how it works): on GLES, or on WebGL, you have to do that to use the light, because the glLight command is not implemented.

OpenB3D actually does that to implement lights in the web version, but everything happens under the hood, as long as no custom shaders are used. Anyway, the limit is still 8 light: it could easily be increased, but it's not recommended, especially if you are going to use per fragment lightning: in fact, each single fragment would have light computed for each light source, and having too many light sources would slow down the rendering process.

Fixed function pipeline (or the default shader used in the Web version, that is made to work even on low end cards) uses per vertex lightning, that is less precise, but computes lights only for each vertex, so it's much faster.

To render many lights (10, 20 or more) usually deferred rendering is used: an example (experimental, and not very useful) is in OpenB3DPlus. It requires a custom shader that has to be used for every surface (it cannot be combined with other shaders), and then a postprocessing shader. It also requires more rendering targets: one for colors, one for depth map, one for normals. In the first pass, a special shader is used that renders all these parameters in the different targets, ignoring the light. In the second stages, these informations are used to render the final image, and lights are applied only on the fragments affected by them, not on every surface. This solution has some drawbacks, by the way, mainly the impossibility to render alpha blending correctly (since an alpha blended surface doesn't update the depth buffer or the normal buffer)

Krischan

I've digged a little more and adding these lines after calling the Graphics3D command gives interesting results:

Local VU:Int ; glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, VarPtr VU)
Local FU:Int ; glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB, VarPtr FU)
Local VA:Int ; glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, VarPtr VA)
Local VS:String = String.FromCString(Byte Ptr(glGetString(GL_VERSION)))
Local SV:String = String.FromCString(Byte Ptr(glGetString(GL_SHADING_LANGUAGE_VERSION)))

Print "Max Vertex Uniforms..: " + VU
Print "Max Fragment Uniforms: " + FU
Print "Max Vertex Attributes: " + VA
Print "GL Version:..........: " + VS
Print "GLSL Version.........: " + SV
End

Nvidia (working)
Max Vertex Uniforms..: 4096
Max Fragment Uniforms: 4096
Max Vertex Attributes: 16
GL Version:..........: 4.6.0 NVIDIA 528.49
GLSL Version.........: 4.60 NVIDIA


ATI (not working, or with 6 lights only)
Max Vertex Uniforms..: 4000
Max Fragment Uniforms: 4000
Max Vertex Attributes: 32
GL Version:..........: 4.6.0 Compatibility Profile Context 22.20.42.221019
GLSL Version.........: 4.60


ATI has twice the Max. Vertex Attributes than Nvidia, but Nvidia works? huh?
Kind regards
Krischan

Windows 10 Pro | i7 9700K@ 3.6GHz | RTX 2080 8GB]
Metaverse | Blitzbasic Archive | My Github projects

Krischan

Oh, and a simple fix that all 8 lights work with little changes to the shader is to move the calculation of the Vertex_LightDir_Length from the Vertex Shader into the Fragment Shader to save some uniforms. I did the calculation in the Vertex Shader as it is not necessary to calculate the length for each texel, but well if it works let's move it back ::)

So the fixed Shaders are:

Vertex:
#version 130

#define NUM_LIGHTS 8

// ----------------------------------------------------------------------------

struct FloatArray {
float Float;
};

// ----------------------------------------------------------------------------

// input variables
uniform float ambFactor;
uniform FloatArray lightradius[NUM_LIGHTS];

// ----------------------------------------------------------------------------

// output variables to fragment shader
out vec2 Vertex_UV;
out vec4 Vertex_Color;
out vec4 Vertex_Position;
out vec3 Vertex_View_Vector;
out vec3 Vertex_Surface_to_Viewer_Direction;
out vec3 Vertex_Normal;
out vec3 Vertex_Ambient_Color;
out vec3 Vertex_LightDir[NUM_LIGHTS];
out vec3 Vertex_LightColor[NUM_LIGHTS];
out float Vertex_LightRange[NUM_LIGHTS];
//out float Vertex_LightDir_Length[NUM_LIGHTS];

// ----------------------------------------------------------------------------

void main()
{
Vertex_Color = gl_Color;
Vertex_Normal = normalize(gl_NormalMatrix * gl_Normal);
Vertex_Position = gl_ModelViewMatrix * gl_Vertex;

for (int i = 0; i < NUM_LIGHTS; ++i)
{
Vertex_LightDir[i] = gl_LightSource[i].position.xyz - Vertex_Position.xyz;
//Vertex_LightDir_Length[i] = length(normalize(Vertex_LightDir[i]));
Vertex_LightColor[i] = gl_LightSource[i].diffuse.rgb;
Vertex_LightRange[i] = lightradius[i].Float;
}

Vertex_UV = gl_MultiTexCoord0.xy;
Vertex_Ambient_Color = gl_LightModel.ambient.rgb * ambFactor;
Vertex_View_Vector = -Vertex_Position.xyz;

vec3 vViewModelPosition = vec3(gl_ModelViewMatrixInverse * vec4(0, 0, 0, 1.0));
vec3 vLocalSurfaceToViewerDirection = normalize(vViewModelPosition-gl_Vertex.xyz);
vec3 vvLocalSurfaceNormal = normalize(gl_Normal);

Vertex_Surface_to_Viewer_Direction = normalize(reflect(vLocalSurfaceToViewerDirection, vvLocalSurfaceNormal)) ;

gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}


Fragment:
#version 130

#define NUM_LIGHTS 8

// ----------------------------------------------------------------------------

struct FloatArray {
    float Float;
};

// ----------------------------------------------------------------------------

const float PI = 3.14159265359;
const float POscale = 0.05;
const float POmin = 8;
const float POmax = 32;
const float POmulti = 1.0;

// ----------------------------------------------------------------------------

uniform sampler2D albedoMap;
uniform sampler2D normalMap;
uniform sampler2D propMap;
uniform sampler2D metallicMap;
uniform sampler2D emissionMap;
uniform samplerCube envMap;

// ----------------------------------------------------------------------------

in vec2 Vertex_UV;
in vec2 Vertex_UVB;
in vec4 Vertex_Color;
in vec3 Vertex_Normal;
in vec3 Vertex_NormalCube;
in vec3 Vertex_Ambient_Color;
in vec3 Vertex_View_Vector;
in vec3 Vertex_Surface_to_Viewer_Direction;
in vec4 Vertex_Position;
in vec3 Vertex_LightDir[NUM_LIGHTS];
in vec3 Vertex_LightColor[NUM_LIGHTS];
in float Vertex_LightRange[NUM_LIGHTS];
//in float Vertex_LightDir_Length[NUM_LIGHTS];

out vec4 FragColor;

// ----------------------------------------------------------------------------

// fixed values
uniform float levelscale;
uniform float gamma;
uniform vec2 texscale;
uniform vec2 texoffset;
uniform vec3 envPos;

// variable values
uniform FloatArray lightradius[NUM_LIGHTS];

// ----------------------------------------------------------------------------

// variable Flags
uniform int flagPB;
uniform int flagPM;
uniform int flagEN;
uniform int flagEM;
uniform int setENV;
uniform int isMetal;

// ----------------------------------------------------------------------------

// texture existance flags
uniform int texAL;
uniform int texNM;
uniform int texPR;
uniform int texME;
uniform int texEM;

// ----------------------------------------------------------------------------

// light attenuation variables
uniform float A;
uniform float B;

// ----------------------------------------------------------------------------

mat3 cotangent_frame(vec3 N, vec3 p, vec2 uv)
{
vec3 dp1 = dFdx(p);
vec3 dp2 = dFdy(p);
vec2 duv1 = dFdx(uv);
vec2 duv = dFdy(uv);
 
vec3 dp2perp = cross(dp2, N);
vec3 dp1perp = cross(N, dp1);
vec3 T = dp2perp * duv1.x + dp1perp * duv.x;
vec3 B = dp2perp * duv1.y + dp1perp * duv.y;
 
float invmax = inversesqrt(max(dot(T, T), dot(B, B)));
return mat3(T * invmax, B * invmax, N);
}

// ----------------------------------------------------------------------------

vec3 perturb_normal(vec3 N, vec3 V, vec3 map, vec2 texcoord)
{
map = map * 255.0 / 127.0 - 128.0 / 127.0;

mat3 TBN = cotangent_frame(N, -V, texcoord);
return normalize(TBN * map);
}

// ----------------------------------------------------------------------------

vec3 ToneMapPBR(vec3 color)
{
// HDR tonemapping and gamma correction
color = color / (color + vec3(1.0));
color = pow(color, vec3(1.0 / gamma));

return color;
}

// ----------------------------------------------------------------------------

float DistributionGGX(vec3 N, vec3 H, float roughness)
{
float a = roughness * roughness;
float a2 = a * a;
float NdotH = max(dot(N, H), 0.0);
float NdotH2 = NdotH * NdotH;

float nom = a2;
float denom = (NdotH2 * (a2 - 1.0) + 1.0);
denom = PI * denom * denom;

return nom / denom;
}

// ----------------------------------------------------------------------------

float GeometrySchlickGGX(float NdotV, float roughness)
{
float r = (roughness + 1.0);
float k = (r * r) / 8.0;

float nom = NdotV;
float denom = NdotV * (1.0 - k) + k;

return nom / denom;
}

// ----------------------------------------------------------------------------

float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness)
{
float NdotV = max(dot(N, V), 0.0);
float NdotL = max(dot(N, L), 0.0);
float ggx2 = GeometrySchlickGGX(NdotV, roughness);
float ggx1 = GeometrySchlickGGX(NdotL, roughness);

return ggx1 * ggx2;
}

// ----------------------------------------------------------------------------

vec3 fresnelSchlick(float cosTheta, vec3 F0)
{
if(cosTheta > 1.0)
cosTheta = 1.0;
float p = pow(1.0 - cosTheta,5.0);
return F0 + (1.0 - F0) * p;
}

// ----------------------------------------------------------------------------

float CalcAtt(float distance, float range, float a, float b)
{
return 1.0 / (1.0 + a * distance + b * distance * distance);
}

// ----------------------------------------------------------------------------

// Contrast Matrix
mat4 contrastMatrix(float contrast)
{
float t = ( 1.0 - contrast ) / 2.0;
   
return mat4(contrast, 0, 0, 0,
0, contrast, 0, 0,
0, 0, contrast, 0,
t, t, t, 1);

}

// ----------------------------------------------------------------------------

vec2 ParallaxOcclusionMapping(vec2 texCoords, vec3 viewDir)
{
    // number of depth layers
    float numLayers = mix(POmax, POmin, abs(dot(vec3(0.0, 0.0, 1.0), viewDir)));

    // calculate the size of each layer
    float layerDepth = 1.0 / numLayers;

    // depth of current layer
    float currentLayerDepth = 0.0;

    // the amount to shift the texture coordinates per layer (from vector P)
    vec2 P = viewDir.xy / viewDir.z * POscale * POmulti;
    vec2 deltaTexCoords = P / numLayers;

    // get initial values
    vec2  currentTexCoords     = texCoords;
    float currentDepthMapValue = texture(propMap, currentTexCoords).b;

    while(currentLayerDepth < currentDepthMapValue)
    {
        // shift texture coordinates along direction of P
        currentTexCoords -= deltaTexCoords;

        // get depthmap value at current texture coordinates
        currentDepthMapValue = texture(propMap, currentTexCoords).b;

        // get depth of next layer
        currentLayerDepth += layerDepth;
    }

    // get texture coordinates before collision (reverse operations)
    vec2 prevTexCoords = currentTexCoords + deltaTexCoords;

    // get depth after and before collision for linear interpolation
    float afterDepth  = currentDepthMapValue - currentLayerDepth;
    float beforeDepth = texture(propMap, prevTexCoords).b - currentLayerDepth + layerDepth;

    // interpolation of texture coordinates
    float weight = afterDepth / (afterDepth - beforeDepth);
    vec2 finalTexCoords = prevTexCoords * weight + currentTexCoords * (1.0 - weight);

    return finalTexCoords;
}

mat3 computeTBN(vec2 tempUv, vec3 worldPos, vec3 worldNormal){
    vec3 Q1  = dFdx(worldPos);
    vec3 Q2  = dFdy(worldPos);
    vec2 st1 = dFdx(tempUv);
    vec2 st2 = dFdy(tempUv);

    vec3 n   = normalize(worldNormal);
    vec3 t  = normalize(Q1*st2.t - Q2*st1.t);

    // or directly compute from the equation
    vec3 b = normalize(-Q1*st2.s + Q2*st1.s);

    mat3 tbn = mat3(t, b, n);

    return tbn;
}

// ----------------------------------------------------------------------------

void main()
{
// Texture coordinates
vec2 ts=texscale;
vec2 uv = Vertex_UV;
//ts.y=-ts.y;
uv = (uv * ts) + texoffset;

// TBN Matrix
vec3 VN = normalize(Vertex_Normal);
vec3 VV = Vertex_View_Vector;
//mat3 TBN = computeTBN(uv.st,-VV,Vertex_Normal);
mat3 TBN = cotangent_frame(VN, VV, uv.st);

// Parallax Mapping
if(flagPM > 0)
{
uv = ParallaxOcclusionMapping(uv, normalize(-VV * TBN));

}

// Albedo Texture
vec4 albedo = vec4(0.5, 0.5, 0.5, 1.0);
if(texAL > 0)
{
albedo = texture(albedoMap, uv);
albedo.rgb = pow(albedo.rgb, vec3(2.2));
}

// Normalmap Texture
vec3 nrm = Vertex_Normal;
if(texNM > 0)
{
nrm = texture(normalMap, uv).rgb;
//nrm.y=1.0-nrm.y;
}

// 3. Perturbated Normals
vec3 N = Vertex_Normal.xyz;
vec3 V = normalize(Vertex_View_Vector);
vec3 PN;
vec3 PNC;
if(texNM == 0)
{
PN = N;
nrm = vec3(0.0, 0.0, 1.0);
}
else
{
vec3 VN = normalize(N);
vec3 VV = normalize(Vertex_View_Vector);
//mat3 TBN = cotangent_frame(VN, -VV, uv.st);

PN = perturb_normal(VN, VV, nrm, uv);
PNC = perturb_normal(Vertex_NormalCube, VV, nrm, uv);
}

// PBR Texture
float ao = 1.0;
float roughness = 0.5;
float metallic = 0.5;

// Roughness
if(texPR > 0)
{
vec3 pbr = texture(propMap, uv).rgb;

ao = pbr.r;
roughness = pbr.g;
}

// Metallic
if(texME > 0)
{
metallic = texture(metallicMap, uv).r;
}

// Emissive
vec3 emission = vec3(0.0);
if(texEM > 0){emission = texture(emissionMap, uv).rgb * 2.0;}

// Ambient
vec3 ambient = Vertex_Ambient_Color * albedo.rgb;

// PBR Lighting
vec3 Lo = vec3(0.0);
vec3 irradiance;
vec3 diffuse=albedo.rgb;
vec3 reflectDir;

// Reflection
vec3 NormalizedRSTVD = normalize(Vertex_Surface_to_Viewer_Direction);

if(flagPB > 0)
{
// calculate reflectance at normal incidence; if dia-electric (like plastic) use F0
// of 0.04 and if it's a metal, use the albedo color as F0 (metallic workflow)   
vec3 F0 = vec3(0.04);
F0 = mix(F0, albedo.rgb, metallic);

for(int i = 0; i < NUM_LIGHTS; ++i)
{
// calculate per-light radiance
vec3 L = normalize(Vertex_LightDir[i]);
vec3 H = normalize(V + L);
float distance = length(normalize(Vertex_LightDir[i]));
float attenuation = CalcAtt(distance, Vertex_LightRange[i], A, B);
vec3 radiance = Vertex_LightColor[i] * attenuation;

// Cook-Torrance BRDF
float NDF = DistributionGGX(PN, H, roughness);
float G = GeometrySmith(PN, V, L, roughness);
vec3 F = fresnelSchlick(max(dot(H, V), 0.0), F0);
          
// specularity
vec3 nominator = NDF * G * F;
float denominator = 4.0 * max(dot(PN, V), 0.0) * max(dot(PN, L), 0.0) + 0.001;
vec3 specular = nominator / denominator;

// kS is equal to Fresnel
vec3 kS = F;

// for energy conservation, the diffuse and specular light can't
// be above 1.0 (unless the surface emits light); to preserve this
// relationship the diffuse component (kD) should equal 1.0 - kS.
vec3 kD = vec3(1.0) - kS;

// multiply kD by the inverse metalness such that only non-metals
// have diffuse lighting, or a linear blend if partly metal (pure metals
// have no diffuse light).
kD *= 1.0-metallic;

// Metallic Reflection --------------------------------------------

diffuse=albedo.rgb;

if(isMetal==1 && flagEN==1 && setENV==1)
{
vec3 v=NormalizedRSTVD;
irradiance = textureCube(envMap, vec3(-v.x,v.y,-v.z)).rgb;
diffuse = (albedo.rgb * (0.0 + (irradiance * 1.0)));
}

// check backface lighting
float NdotL = max(dot(PN, L), 0.0);

Lo += (kD * diffuse.rgb / PI + (specular)) * Vertex_LightRange[i] * radiance * NdotL;
}
}
// PBR off
else
{
for(int i = 0; i < NUM_LIGHTS; ++i)
{
float distance = length(normalize(Vertex_LightDir[i]));
float attenuation = CalcAtt(distance, Vertex_LightRange[i], A, B);
vec3 radiance = Vertex_LightColor[i] * attenuation;

vec3 L = normalize(Vertex_LightDir[i]);
vec3 N = Vertex_Normal.xyz;

float NdotL = max(dot(N, L), 0.0);
Lo += (diffuse.rgb / PI) * Vertex_LightRange[i] * radiance * NdotL;
}
}

// mix final lighting with ambient
vec3 color=(Lo+ambient);

// Ambient Occlusion
color *= ao;

// more contrast using normals and contrast matrix
float NL = max(dot(PN, normalize(Vertex_View_Vector)), 0.0);
color*=NL;
color.rgb*=(vec4(1.0) * contrastMatrix(2.0)).rgb;

// Tonemapping
color = ToneMapPBR(color);

// Gamma correction
color = pow(color, vec3(1.0/2.2));

if(flagEM==0){emission=vec3(0.0);}

// Final olor plus Emissive with Alpha
FragColor = vec4(color+emission, albedo.a);

}
Kind regards
Krischan

Windows 10 Pro | i7 9700K@ 3.6GHz | RTX 2080 8GB]
Metaverse | Blitzbasic Archive | My Github projects

markcwm

I have a fix for the Intel bug now, it takes a max of 7 lights and there is one line in the frag that makes it all go black.

PNC = perturb_normal(Vertex_NormalCube, VV, nrm, uv);
// there is no definition for Vertex_NormalCube so changed it to:
PNC = perturb_normal(Vertex_Normal, VV, nrm, uv);

There is still a strange flickering edges issue in the POM and when I turn off PBR in the main example. Some screenies.