Hardware shader update

Discuss anything ZDoom-related that doesn't fall into one of the other categories.
dpJudas
 
 
Posts: 3037
Joined: Sat May 28, 2016 1:01 pm

Hardware shader update

Post by dpJudas »

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 all

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 all

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 all

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.
User avatar
HAL9000
Posts: 266
Joined: Fri Mar 16, 2018 7:44 am
Contact:

Re: Hardware shader update

Post by HAL9000 »

Ok,thanks for the info, can't wait to play with this. :D
PixelWAD
Posts: 188
Joined: Sun Jun 10, 2018 7:01 pm

Re: Hardware shader update

Post by PixelWAD »

This seems very interesting, is there any sample PK3 available to understand how it's applied?
Guest

Re: Hardware shader update

Post by Guest »

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
User avatar
Pixel Eater
 
 
Posts: 667
Joined: Wed Aug 02, 2017 12:31 am
Location: In between the Moon and you, between the buried and me.

Re: Hardware shader update

Post by Pixel Eater »

That texture is nice! :trippy:
User avatar
furyweb
Posts: 33
Joined: Thu Aug 30, 2018 3:23 pm
Location: UK

Re: Hardware shader update

Post by furyweb »

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

https://mega.nz/#!xGAEEYjD!eiP6snnwr5Y0 ... OaITKS4TvU
PixelWAD
Posts: 188
Joined: Sun Jun 10, 2018 7:01 pm

Re: Hardware shader update

Post by PixelWAD »

This looks awesome!
Rebecca, would you mind sharing PK3 file with this sample?
User avatar
furyweb
Posts: 33
Joined: Thu Aug 30, 2018 3:23 pm
Location: UK

Re: Hardware shader update

Post by furyweb »

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
wildweasel
Posts: 21706
Joined: Tue Jul 15, 2003 7:33 pm
Preferred Pronouns: He/Him
Operating System Version (Optional): A lot of them
Graphics Processor: Not Listed
Contact:

Re: Hardware shader update

Post by wildweasel »

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.
dpJudas
 
 
Posts: 3037
Joined: Sat May 28, 2016 1:01 pm

Re: Hardware shader update

Post by dpJudas »

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.
User avatar
furyweb
Posts: 33
Joined: Thu Aug 30, 2018 3:23 pm
Location: UK

Re: Hardware shader update

Post by furyweb »

updated link with just a straight .pk3 download

https://mega.nz/#!hCQwCSQa!b_Muvo-8nqtL ... 4fat91Lsb0
User avatar
drfrag
Vintage GZDoom Developer
Posts: 3141
Joined: Fri Apr 23, 2004 3:51 am
Location: Spain
Contact:

Re: Hardware shader update

Post by drfrag »

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)...
PixelWAD
Posts: 188
Joined: Sun Jun 10, 2018 7:01 pm

Re: Hardware shader update

Post by PixelWAD »

It works here on GTX680 GZDoom 3.5.1. How did you generate heightmap from existing pbr textures?
dpJudas
 
 
Posts: 3037
Joined: Sat May 28, 2016 1:01 pm

Re: Hardware shader update

Post by dpJudas »

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 all

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;  
}
User avatar
furyweb
Posts: 33
Joined: Thu Aug 30, 2018 3:23 pm
Location: UK

Re: Hardware shader update

Post by furyweb »

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.
Post Reply

Return to “General”