GLSL shader ported to HLSL not working

Hi, everyone! I been working on Grid shader for my engine.

It already was implemented to Vulkan’s GLSL, so it great work with OpenGL’s (4.6) GLSL.

But problem occurs when i port this shader to DirectX 11 (HLSL). Overall grid renders the same with all effects on OpenGL and DirectX file. But in DirectX something wrong happens with Pixel/Fragment shader. E.g when i move mouse outside viewport or resize viewport it start to discard pixels and i not see and any grid. I’m 100% sure that problem exactly in this shader because with other meshs and shaders that glitch not happen EVER.

I know about GLSL and HLSL matrices multiplication order. So in GLSL matrices is Right-Column and in HLSL is Left-Column so i take that in count and multiply matrices in HLSL in reverse order.

So one thing that im not sure its about math functions like min/max, fract, smoothstep, log, clamp, etc that this shader uses.

So i show example of my GLSL Fragment Shader and HLSL Pixel Shader.

GLSL:

#version 450 core

layout(location = 1) in vec3 nearPoint; // nearPoint calculated in vertex shader
layout(location = 2) in vec3 farPoint;  // farPoint calculated in vertex shader
layout(location = 3) in mat4 fragView;
layout(location = 7) in mat4 fragProj;

layout(std140, binding = 1) uniform UB_GridFS {
	vec4  gridColor1;
	vec4  gridColor2;
	vec4  cameraPos;
	vec4  cameraForward;
	float near;
	float far;
	float maxDistance;
	float offset;
} gridUBO;

layout (location = 0) out vec4 pixelBuffer; // outColour
layout (location = 1) out int  objectIDBuffer;

// Constants.
const float step = 100.0f;
const float subdivisions = 10.0f;

vec4 Grid(vec3 fragPos3D, float scale, bool drawAxis, vec3 gridColor) {
	vec2 coord = fragPos3D.xz * scale; // use the scale variable to set the distance between the lines
	vec2 derivative = fwidth(coord);
	vec2 grid = abs(fract(coord - 0.5) - 0.5) / derivative;
	float line = min(grid.x, grid.y);
	float minimumz = min(derivative.y, 1);
	float minimumx = min(derivative.x, 1);
	vec4 color = vec4(gridColor, 1.0 - min(line, 1.0));
	// z axis
	if(fragPos3D.x > -0.1 * minimumx && fragPos3D.x < 0.1 * minimumx)
		color = vec4(0.0, 0.0, 1.0, color.w);//1.0;
	// x axis
	if(fragPos3D.z > -0.1 * minimumz && fragPos3D.z < 0.1 * minimumz)
		color = vec4(1.0, 0.0, 0.0, color.w);//1.0;
	return color;
}

float ComputeDepth(vec3 pos) {
	vec4 clip_space_pos = fragProj * fragView * vec4(pos.xyz, 1.0);
	return (clip_space_pos.z / clip_space_pos.w);
}

float ComputeLinearDepth(vec3 pos, float near, float far) {
	vec4 clip_space_pos = fragProj * fragView * vec4(pos.xyz, 1.0);
	float clip_space_depth = (clip_space_pos.z / clip_space_pos.w) * 2.0 - 1.0; // put back between -1 and 1
	float linearDepth = (2.0 * near * far) / (far + near - clip_space_depth * (far - near)); // get linear value between 0.01 and 100
    return linearDepth / far; // normalize
}

int RoundToPowerOfTen(float n) {
	return int(pow(10.0, floor( (1 / log(10)) * log(n))));
}

void main(void) {

	float t = -nearPoint.y / (farPoint.y - nearPoint.y);
	if (t < 0.)
		discard;
	
	// Temp
	float _far = 200.0f;
		
	vec3 fragPos3D = nearPoint + t * (farPoint - nearPoint);
	gl_FragDepth = ComputeDepth(fragPos3D);

	float linearDepth = ComputeLinearDepth(fragPos3D, gridUBO.near, _far);
	float fading = max(0, (0.5 - linearDepth));
	float decreaseDistance = _far * 1.5;
	vec3 pseudoViewPos = vec3(gridUBO.cameraPos.x, fragPos3D.y, gridUBO.cameraPos.z);

	float dist, angleFade;
	vec3 viewvec = gridUBO.cameraPos.xyz - fragPos3D;
	dist = length(viewvec);
	viewvec /= dist;
		
	float angle;
	angle = viewvec.y;
	angle = 1.0 - abs(angle);
	angle *= angle;
	angleFade = 1.0 - angle * angle;
	angleFade *= 1.0 - smoothstep(0.0, gridUBO.maxDistance, dist - gridUBO.maxDistance);
	

	float distanceToCamera = abs(gridUBO.cameraPos.y - fragPos3D.y);
	int powerOfTen = RoundToPowerOfTen(distanceToCamera);
	powerOfTen = max(1, powerOfTen);
	float divs = 1.0 / float(powerOfTen);
	float secondFade = smoothstep(subdivisions / divs, 1 / divs, distanceToCamera);

	vec4 grid1 = Grid(fragPos3D, divs / subdivisions, true, gridUBO.gridColor1.xyz);
	vec4 grid2 = Grid(fragPos3D, divs, true, gridUBO.gridColor2.xyz);

	grid2.a *= secondFade;
	grid1.a *= (1 - secondFade);

	// Adding multiple resolution for the grid.
	pixelBuffer   = grid1 + grid2;
	pixelBuffer.a = max(grid1.a, grid2.a);
	
	pixelBuffer *= float(t > 0);
	pixelBuffer.a *= fading;
	pixelBuffer.a *= angleFade;
}

HLSL:

// Input VAO data from Vertex Shader.
struct FsInput {
	float3   nearPoint : v_NearPoint;
	float3   farPoint  : v_FarPoint;
	float4x4 fragView  : v_FragView;
	float4x4 fragProj  : v_FragProj;
	float4   position  : SV_Position;
};

cbuffer UB_GridFS : register(b1) {
	float4 gridColor1;
	float4 gridColor2;
	float4 cameraPos;
	float4 cameraForward;
	float  near;
	float  far;
	float  maxDistance;
	float  offset;
};

struct OMOut {
	float4 pixelBuffer  : SV_Target0;
	float	 depthBuffer : SV_Depth;
};

// Constants.
const static float step = 100.0f;
const static float subdivisions = 10.0f;

float4 Grid(float3 fragPos3D, float scale, float3 gridColor) { // No cause glitching OK
	float2 coord = float2(fragPos3D.x * scale, fragPos3D.z * scale);
	float2 derivative = fwidth(coord);
	float2 grid = abs(frac(coord - 0.5) - 0.5) / derivative;
	float _line = min(grid.x, grid.y);
	float minimumz = min(derivative.y, 1);
	float minimumx = min(derivative.x, 1);
	float4 color = float4(gridColor, 1.0f - min(_line, 1.0));
	// z axis
	if(fragPos3D.x > -0.1 * minimumx && fragPos3D.x < 0.1 * minimumx)
		color = float4(0.0, 0.0, 1.0, color.w);
	// x axis
	if(fragPos3D.z > -0.1 * minimumz && fragPos3D.z < 0.1 * minimumz)
		color = float4(1.0, 0.0, 0.0, color.w);
	return color;
}

float ComputeDepth(float3 pos, float4x4 fragProj, float4x4 fragView) {
	float4 clip_space_pos = mul(mul(fragProj, fragView), float4(pos, 1.0f));
	return (clip_space_pos.z / clip_space_pos.w);
}

float ComputeLinearDepth(float3 pos, float4x4 fragProj, float4x4 fragView, float near, float far) {
	float4 clip_space_pos = mul(mul(fragProj, fragView), float4(pos, 1.0f));
	float clip_space_depth = (clip_space_pos.z / clip_space_pos.w) * 2.0f - 1.0f; // put back between -1 and 1
	float linearDepth = (2.0f * near * far) / (far + near - clip_space_depth * (far - near)); // get linear value between 0.01 and 100
	return linearDepth / far; // normalize
}

int RoundToPowerOfTen(float n) { // Cause litte glitch
	return int(pow(10.0, floor( (1 / log(10)) * log(n))));
}

OMOut main(FsInput input) {

	OMOut omOut;
	
	// HLSL specific.
	float3 gridColor1xyz = float3(gridColor1.x, gridColor1.y, gridColor1.z);
	float3 gridColor2xyz = float3(gridColor2.x, gridColor2.y, gridColor2.z); // Something wrong with this color.
	//
	
	// Temp
	float _far = 200.0f;
	
	float t = -input.nearPoint.y / (input.farPoint.y - input.nearPoint.y);
	if (t < 0.)
		discard;
	
	float3 fragPos3D = input.nearPoint + t * (input.farPoint - input.nearPoint);
	omOut.depthBuffer = ComputeDepth(fragPos3D, input.fragProj, input.fragView);
	
	float linearDepth = ComputeLinearDepth(fragPos3D, input.fragProj, input.fragView, near, _far);
	float fading = max(0, (0.5 - linearDepth));
	float decreaseDistance = _far * 1.5;
	float3 pseudoViewPos = float3(cameraPos.x, fragPos3D.y, cameraPos.z);
	
	float dist, angleFade;
	float3 cameraPosXYZ = float3(cameraPos.x, cameraPos.y, cameraPos.z);
	float3 viewvec = cameraPosXYZ - fragPos3D;
	dist = length(viewvec);
	viewvec /= dist;
		
	float angle;
	angle = viewvec.y;
	angle = 1.0 - abs(angle);
	angle *= angle;
	angleFade = 1.0 - angle * angle;
	angleFade *= 1.0 - smoothstep(0.0, maxDistance, dist - maxDistance);

	float distanceToCamera = abs(cameraPos.y - fragPos3D.y);
	int powerOfTen = RoundToPowerOfTen(distanceToCamera);
	powerOfTen = max(1, powerOfTen);
	float divs = 1.0 / float(powerOfTen);
	float secondFade = smoothstep(subdivisions / divs, 1 / divs, distanceToCamera);

	float4 grid1 = Grid(fragPos3D, divs / subdivisions, gridColor1xyz);
	float4 grid2 = Grid(fragPos3D, divs, gridColor2xyz);

	grid2.a *= secondFade;
	grid1.a *= (1 - secondFade);

	// Adding multiple resolution for the grid.
	omOut.pixelBuffer   = grid1 + grid2;
	omOut.pixelBuffer.a = max(grid1.a, grid2.a);
	
	omOut.pixelBuffer *= float(t > 0);
	omOut.pixelBuffer.a *= fading;
	omOut.pixelBuffer.a *= angleFade;
	return omOut;
}

So one problem that i think that can cause this is just because of some math functions that works differently in GLSL/HLSL.

Math Functions that use this shader:

  • fwidth
  • abs
  • frac
  • min
  • max
  • pow
  • log
  • floor
  • length
  • smoothstep
  • clamp