Page 6 of 8

Re: Materials (PBR, Specular, Normal maps)

PostPosted: Sat Sep 01, 2018 4:49 am
by Reinchard2
@Indecom I tried your new shader for parallax mapping, but I noticed this isn't compatible with pbr I guess? I mean when I use heightmaps with rest of my pbr maps like roughness/ao/normal my materials don't work with lights ingame at all. But when I use "glossines/specular level values in my gldefs my materials start working with lights, but thay don't read rougness map correctly. I mean I have something like this now:

material Texture "stargr1"
{
normal "materials/normalmaps/stargr1.tga"
specular "materials/specular/spec1.png"
metallic "materials/metallic/startan3.tga"
roughness "materials/roughness/stargr1.tga"
specularlevel 3
glossiness 10
Shader "shaders/texture/parallax.fp"

Texture tex_heightmap "materials/heightmaps/startan3.tga"
Define "Foobar"
}
In pbr I don't need specular map, but I noticed that this new shader works only if I specify some specular map for every material. Any tips?

Re: Materials (PBR, Specular, Normal maps)

PostPosted: Sat Sep 01, 2018 5:40 am
by dpJudas
Here's an updated version of the shader that supports all the various material types (normal, specular, pbr):

Code: Select allExpand view
mat3 GetTBN();
vec3 GetBumpedNormal(mat3 tbn, vec2 texcoord);
vec2 ParallaxMap(mat3 tbn);

Material ProcessMaterial()
{
    mat3 tbn = GetTBN();
    vec2 texCoord = ParallaxMap(tbn);

    Material material;
    material.Base = getTexel(texCoord);
    material.Normal = GetBumpedNormal(tbn, texCoord);
#if defined(SPECULAR)
    material.Specular = texture(speculartexture, texCoord).rgb;
    material.Glossiness = uSpecularMaterial.x;
    material.SpecularLevel = uSpecularMaterial.y;
#endif
#if defined(PBR)
    material.Metallic = texture(metallictexture, texCoord).r;
    material.Roughness = texture(roughnesstexture, texCoord).r;
    material.AO = texture(aotexture, texCoord).r;
#endif
#if defined(BRIGHTMAP)
    material.Bright = texture(brighttexture, texCoord);
#endif
    return material;
}

// Tangent/bitangent/normal space to world space transform matrix
mat3 GetTBN()
{
    vec3 n = normalize(vWorldNormal.xyz);
    vec3 p = pixelpos.xyz;
    vec2 uv = vTexCoord.st;

    // get edge vectors of the pixel triangle
    vec3 dp1 = dFdx(p);
    vec3 dp2 = dFdy(p);
    vec2 duv1 = dFdx(uv);
    vec2 duv2 = dFdy(uv);

    // solve the linear system
    vec3 dp2perp = cross(n, dp2); // cross(dp2, n);
    vec3 dp1perp = cross(dp1, n); // cross(n, dp1);
    vec3 t = dp2perp * duv1.x + dp1perp * duv2.x;
    vec3 b = dp2perp * duv1.y + dp1perp * duv2.y;

    // construct a scale-invariant frame
    float invmax = inversesqrt(max(dot(t,t), dot(b,b)));
    return mat3(t * invmax, b * invmax, n);
}

vec3 GetBumpedNormal(mat3 tbn, vec2 texcoord)
{
#if defined(NORMALMAP)
    vec3 map = texture(normaltexture, texcoord).xyz;
    map = map * 255./127. - 128./127.; // Math so "odd" because 0.5 cannot be precisely described in an unsigned format
    map.y = -map.y;
    return normalize(tbn * map);
#else
    return normalize(vWorldNormal.xyz);
#endif
}

vec2 ParallaxMap(mat3 tbn)
{
    const float parallaxScale = 0.045;
    const float minLayers = 8.0;
    const float maxLayers = 16.0;

    // Calculate fragment view direction in tangent space
    mat3 invTBN = transpose(tbn);
    vec3 V = normalize(invTBN * (uCameraPos.xyz - pixelpos.xyz));
    vec2 T = vTexCoord.st;

    float numLayers = mix(maxLayers, minLayers, clamp(abs(V.z), 0.0, 1.0)); // clamp is required due to precision loss

    // 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 = V.xy * parallaxScale;
    vec2 deltaTexCoords = P / numLayers;
    vec2 currentTexCoords = T;
    float currentDepthMapValue = texture(tex_heightmap, currentTexCoords).r;

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

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

        // 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(tex_heightmap, prevTexCoords).r - currentLayerDepth + layerDepth;
     
    // interpolation of texture coordinates
    float weight = afterDepth / (afterDepth - beforeDepth);
    vec2 finalTexCoords = prevTexCoords * weight + currentTexCoords * (1.0 - weight);

    return finalTexCoords;
}

Re: Materials (PBR, Specular, Normal maps)

PostPosted: Sat Sep 01, 2018 6:29 am
by Reinchard2
Wow, great thanks!

Re: Materials (PBR, Specular, Normal maps)

PostPosted: Sat Sep 01, 2018 7:22 am
by Reinchard2
Everything works well excpet brightmaps. I tried using some brightmap with your new shader and GZDoom shows some information about "missing texture7" in error log.

Re: Materials (PBR, Specular, Normal maps)

PostPosted: Sat Sep 01, 2018 7:30 am
by dpJudas
This is probably a bug/limitation in how gzdoom handles its shaders. Create two copies of the shader (i.e. para.glsl and para_bm.glsl) and then use different name depending on whether the texture has a brightmap or not.

Re: Materials (PBR, Specular, Normal maps)

PostPosted: Sun Sep 02, 2018 10:38 am
by Reinchard2
OK, thanks. Is there any way to increase heightmap strenght/parallax offset via gldefs code?

Re: Materials (PBR, Specular, Normal maps)

PostPosted: Sun Sep 02, 2018 3:38 pm
by dpJudas
I believe the parallaxScale variable in the shader itself controls this. There's currently no way to set custom uniform values.

You could use a define in the gldefs file, i.e. 'Define "parallaxScale 0.045"' and then remove the 'const float parallaxSacle = 0.045;' line from the shader itself. The catch is that this method will compile a new shader for each different scale you use, which is not good.

Re: Materials (PBR, Specular, Normal maps)

PostPosted: Mon Sep 03, 2018 1:57 am
by Reinchard2
Ok, thanks!

Re: Materials (PBR, Specular, Normal maps)

PostPosted: Thu Sep 06, 2018 12:47 am
by Reinchard2
One more question - what about alpha masks?

Re: Materials (PBR, Specular, Normal maps)

PostPosted: Fri Sep 07, 2018 8:21 am
by Samuel Chibberwell
hey man, thanks for your work

I have found a bug in your code that seems to make it incompatible with some implementations of shader language:

i have a Macbook Air 2012 with intel graphics 4000... os 10.13.6

the error:

ERROR: 0:79: Initializer not allowed

solved by changing:

const float layerDepth = 1.0 / numLayers;

removing "const"


I think that some implementations likely then allow assigning a constant as the result of an expression, i've seen that in some languages. On my card clearly not.
I had this issue with an older version of your shader to.
removing const is unlikely to affect shader performance.

It would be nice if you posted your work to github :)

Re: Materials (PBR, Specular, Normal maps)

PostPosted: Sat Sep 08, 2018 8:17 am
by DarkShroom
my post came up as "Samuel Chibberwell" i think i was logged out er sorry

anyway i was now really interested in figuring the reason for this bug so i meant to leave my username

I hate the idea that you can make and test your mod and it'll work fine on your own system... a user will download it, it won't work, he'll just put it in the recycle bin and move on

Re: Materials (PBR, Specular, Normal maps)

PostPosted: Sat Sep 08, 2018 2:06 pm
by dpJudas
DarkShroom wrote:anyway i was now really interested in figuring the reason for this bug

One of the biggest problems with OpenGL is that each driver brings its own GLSL compiler. The Intel GLSL compiler thinks that line can't be const, while the Nvidia compiler thinks it can be. One of them is wrong, but to figure out which would require reading the GLSL specification carefully. It doesn't really matter much in the end as you'll need to use a syntax that works for all of them regardless of which is to blame.

If you want to maximize the chance your mod works on everyone's computer, make sure you try run it on at least one Intel, one Nvidia and one AMD card.

Re: Materials (PBR, Specular, Normal maps)

PostPosted: Sat Sep 08, 2018 4:28 pm
by furyweb
Me again. dpJudas is it possible to add the option of a glossiness material like specular and normal materials. I know we can control the glossiness through numeric value, but would be nice to use a texture for more control. I would use PBR but until cube map environment has come about so we can have some sort of reflection, i prefer to use specular/normal. Also pbr bugs out with sector lines, as in it cuts off the lighting.

Cheers.

Re: Materials (PBR, Specular, Normal maps)

PostPosted: Sat Sep 08, 2018 6:00 pm
by dpJudas
Yes, that is possible. Change the following lines in the shader from:

Code: Select allExpand view
material.Glossiness = uSpecularMaterial.x;
material.SpecularLevel = uSpecularMaterial.y;

to this:

Code: Select allExpand view
vec4 glossSpec = texture(tex_gloss, texCoord);
material.Glossiness = glossSpec.r * 100.0;
material.SpecularLevel = glossSpec.g * 100.0;

Then add a 'Texture tex_gloss "materials/gloss/foo.png" to the GLSL material entries. This will make the red channel of that texture the glossiness and the green channel the specular level.

The 100 value I typed into the shader is the scale that maps full red and green to that value. I'm not sure what the reasonable max should be here - feel free to adjust it to what makes sense for the two values.

Re: Materials (PBR, Specular, Normal maps)

PostPosted: Sat Sep 08, 2018 6:09 pm
by dpJudas
Thinking about it a bit further the code could use the Glossiness and SpecularLevel parameters in the GLDEFS as the scale factor:

Code: Select allExpand view
vec4 glossSpec = texture(tex_gloss, texCoord);
material.Glossiness = glossSpec.r * uSpecularMaterial.x;
material.SpecularLevel = glossSpec.g * uSpecularMaterial.y;