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