Hardware shader update

Discuss anything ZDoom-related that doesn't fall into one of the other categories.

Hardware shader update

Postby dpJudas » Sun Jul 15, 2018 5:16 pm

I couldn't find the old topic where UsernameAK's PR was being discussed, so I'm creating a new one. :)

After his PR got merged in (yesterday I think it was), I've made a few changes to the syntax. This was mainly to ensure that mods wouldn't be copying the light math directly from GZDoom's internal shaders. In the new syntax the shaders are declared as part of the material itself. I.e. for a specular material it looks like this:

Code: Select allExpand view
material texture BRIX
{
   normal "normalmaps/bricks2.png"
   specular "materials/black.png"
   Shader "shaders/texture/warp.fp"
   Speed 1.337
   Texture tex_heightmap "heightmaps/bricks2.png"
   Define "Foobar"
}

The shader itself uses a new function, Material ProcessMaterial() instead of the old Process function. Here's an example:

Code: Select allExpand view
vec2 parallaxMapping(in vec3 V, in vec2 T);

Material ProcessMaterial()
{
   // Warp effect:
   vec2 texCoord = vTexCoord.st;
   const float pi = 3.14159265358979323846;
   vec2 offset = vec2(0.0,0.0);
   offset.y = 0.5 + sin(pi * 2.0 * (texCoord.y + timer * 0.61 + 900.0/8192.0)) + sin(pi * 2.0 * (texCoord.x * 2.0 + timer * 0.36 + 300.0/8192.0));
   offset.x = 0.5 + sin(pi * 2.0 * (texCoord.y + timer * 0.49 + 700.0/8192.0)) + sin(pi * 2.0 * (texCoord.x * 2.0 + timer * 0.49 + 1200.0/8192.0));
   texCoord += offset * 0.025;

   // Parallax effect:
   vec3 V = normalize(vEyeNormal).xyz;
   V.x = -V.x;
   texCoord = parallaxMapping(V, fract(texCoord));

   // Sample the textures and return the result:
   Material material;
   material.Base = getTexel(texCoord);
   material.Normal = ApplyNormalMap(texCoord);
   material.Specular = texture(speculartexture, texCoord).rgb;
   material.Glossiness = uSpecularMaterial.x;
   material.SpecularLevel = uSpecularMaterial.y;
#if defined(BRIGHTMAP)
   material.Bright = texture(brighttexture, texCoord);
#endif
   return material;
}

vec2 parallaxMapping(in vec3 V, in vec2 T)
{
   const float   parallaxScale = 0.25;
   const float minLayers = 8.0;
   const float maxLayers = 32.0;

   float numLayers = mix(maxLayers, minLayers, abs(V.z)); 

   // 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; 
}

Note: this shader is a modified UsernameAK example shader. Please credit him if you use this in a mod, not me. :)

SPECULAR will be defined if the shader is being compiled for a specular material.
PBR will be defined for pbr mats.
BRIGHTMAP will also be defined if it is using a brightmap texture.

The following textures will be defined depending on the type of material: tex, brighttexture, speculartexture, metallictexture, roughnesstexture and aotexture. The helper functions getTexel and ApplyNormalMap can also be used.

The material struct looks like this:
Code: Select allExpand view
struct Material
{
   vec4 Base;
   vec4 Bright;
   vec3 Normal;
   vec3 Specular;
   float Glossiness;
   float SpecularLevel;
   float Metallic;
   float Roughness;
   float AO;
};

It is only required to fill out the fields relevant for the material type being shaded.
dpJudas
 
 
 
Joined: 28 May 2016

Re: Hardware shader update

Postby HAL9000 » Sun Jul 15, 2018 7:29 pm

Ok,thanks for the info, can't wait to play with this. :D
User avatar
HAL9000
I'm sorry Dave, I'm afraid I can't do that
 
Joined: 16 Mar 2018
Discord: HAL9000#9378

Re: Hardware shader update

Postby PixelWAD » Wed Aug 29, 2018 4:32 pm

This seems very interesting, is there any sample PK3 available to understand how it's applied?
PixelWAD
 
Joined: 10 Jun 2018

Re: Hardware shader update

Postby Rebecca Smallham » Thu Aug 30, 2018 4:35 pm

Hi new guy here. So dpJudas I got your code working with the parallax. Looks pretty good as you will see from the video below. I had a few issues with it working correctly:

1: I had to invert the heightmap for the wall textures for it to parallax the right way.

2 : Parallax on the ground flat works but only one way, whichever dynlight it sees first. So it looks a little strange.

3: I had to 0 everything on the warp effect otherwise it just warps the walls which felt like I was tripping. does the warp effect do something with the parallax effect or is it just another shader effect. When I delete the bit of code I get errors spitting out.

Anyway thanks.

Video link below:

https://youtu.be/i3IALacyNfE
Rebecca Smallham
 

Re: Hardware shader update

Postby Pixel Eater » Thu Aug 30, 2018 6:38 pm

That texture is nice! :trippy:
User avatar
Pixel Eater
I sense evil I fear it here today, Like a bad dream that never goes away -MBerry
 
 
 
Joined: 02 Aug 2017
Location: In between the Moon and you, between the buried and me.

Re: Hardware shader update

Postby furyweb » Thu Aug 30, 2018 6:47 pm

test map with a few textures: just bring the console down and type "map para"

https://mega.nz/#!xGAEEYjD!eiP6snnwr5Y0 ... OaITKS4TvU
User avatar
furyweb
 
Joined: 30 Aug 2018
Location: UK

Re: Hardware shader update

Postby PixelWAD » Thu Aug 30, 2018 6:52 pm

This looks awesome!
Rebecca, would you mind sharing PK3 file with this sample?
PixelWAD
 
Joined: 10 Jun 2018

Re: Hardware shader update

Postby furyweb » Thu Aug 30, 2018 6:58 pm

PixelWAD wrote:This looks awesome!
Rebecca, would you mind sharing PK3 file with this sample?


Im not rebecca for some reason its coming up with the wrong name for me lol. Anyway the link should come soon after its been modded. My user name is furyweb btw :D
User avatar
furyweb
 
Joined: 30 Aug 2018
Location: UK

Re: Hardware shader update

Postby wildweasel » Thu Aug 30, 2018 8:12 pm

furyweb wrote:
PixelWAD wrote:This looks awesome!
Rebecca, would you mind sharing PK3 file with this sample?


Im not rebecca for some reason its coming up with the wrong name for me lol. Anyway the link should come soon after its been modded. My user name is furyweb btw :D

Because you were posting while not logged in, and the forum generates random names for guests.
User avatar
wildweasel
「お前はもうトースト」[you are already toast.]
Moderator Team Lead
 
Joined: 15 Jul 2003

Re: Hardware shader update

Postby dpJudas » Thu Aug 30, 2018 9:23 pm

furyweb wrote:1: I had to invert the heightmap for the wall textures for it to parallax the right way.

There seems to be multiple conventions about which way height maps points. Same deal with normal maps. You may have to adjust both to get it correct.

Note: I did not write the original parallax map code used in this example. UsernameAK provided it.

2 : Parallax on the ground flat works but only one way, whichever dynlight it sees first. So it looks a little strange.

The code doesn't use the dynamic lights for parallax calculations at all. It uses the view space direction of the face normal to figure out which pixel would have been hit with the given height map. From there it grabs the normal map normal of that location and feeds it into the normal light calculations.

If the ground/ceiling looks odd, perhaps the normal map also needs its Red or Green channels inverted.

3: I had to 0 everything on the warp effect otherwise it just warps the walls which felt like I was tripping. does the warp effect do something with the parallax effect or is it just another shader effect. When I delete the bit of code I get errors spitting out.

It is just another shader effect stacked on top. You can remove it without it affecting the parallax effect, just make sure you keep the "vec2 texCoord = vTexCoord.st;" line - otherwise you'll get a compile error.

Btw. I tried to download your rar file, but 7zip couldn't unextract it.
dpJudas
 
 
 
Joined: 28 May 2016

Re: Hardware shader update

Postby furyweb » Fri Aug 31, 2018 11:12 am

updated link with just a straight .pk3 download

https://mega.nz/#!hCQwCSQa!b_Muvo-8nqtL ... 4fat91Lsb0
User avatar
furyweb
 
Joined: 30 Aug 2018
Location: UK

Re: Hardware shader update

Postby drfrag » Fri Aug 31, 2018 1:51 pm

Just tested this and works fine in LZDoom (the new old renderer). In GZDoom dynamic lights won't light walls on my crappy GL 3.3 ati card. Besides that it still crashes of course, i really need an nvidia card.
Now there's that draw thick lines thing (new assasin sent to kill the old legacy build)...
User avatar
drfrag
I.R developer, I.R smart
Vintage GZDoom Developer
 
Joined: 23 Apr 2004
Location: Spain

Re: Hardware shader update

Postby PixelWAD » Fri Aug 31, 2018 2:00 pm

It works here on GTX680 GZDoom 3.5.1. How did you generate heightmap from existing pbr textures?
PixelWAD
 
Joined: 10 Jun 2018

Re: Hardware shader update

Postby dpJudas » Fri Aug 31, 2018 2:06 pm

Thanks for the updated pk3. I looked into error you were experiencing with the floor/ceiling - turns out the math in the parallax shader is wrong. Here's an updated fixed version:

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);
    material.Specular = texture(speculartexture, texCoord).rgb;
    material.Glossiness = uSpecularMaterial.x;
    material.SpecularLevel = uSpecularMaterial.y;
#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
    const 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; 
}
dpJudas
 
 
 
Joined: 28 May 2016

Re: Hardware shader update

Postby furyweb » Fri Aug 31, 2018 7:48 pm

Thanks so much for this works perfect and looks even better. Here is an updated pk3 with some tweaked textures

https://mega.nz/#!IGxECSqZ!bomfSG_ODtdx ... fJqD7w_r2w

also the higher res the texture the better the parallax works.
User avatar
furyweb
 
Joined: 30 Aug 2018
Location: UK

Next

Return to General

Who is online

Users browsing this forum: No registered users and 7 guests