🌶️ Infinite Grid

 Non-maintained solution

The proposed solution is not natively supported and may not work in all scenarios and versions.

It is possible to draw an infinite grid by using a custom shader. This effect can be achieved by enabling this shader and drawing a square covering the entire wanted plane in the DrawViewportBackground method.

Vertex shader:

varying vec3 nearPoint;
varying vec3 farPoint;
varying vec3 eyePos;

uniform mat4 proj;
uniform mat4 mv;
uniform vec3 eyeWorldPosition;

varying mat4 fragView;
varying mat4 fragProj;

vec3 unprojectPoint(float x, float y, float z, mat4 mv, mat4 projection)
{
    mat4 viewInv = inverse(mv);
    mat4 projInv = inverse(projection);
    
    vec4 unprojectedPoint = viewInv * projInv * vec4(x, y, z, 1.0);
    return unprojectedPoint / unprojectedPoint.w;
}

void main()
{
    fragView = mv;
    fragProj = proj;
    eyePos   = eyeWorldPosition;

    gl_Position = ftransform();

    nearPoint = unprojectPoint(gl_Position.x, gl_Position.y, -1, mv, proj);
    farPoint  = unprojectPoint(gl_Position.x, gl_Position.y, 1, mv, proj);
}

Fragment shader:

varying vec3 nearPoint;
varying vec3 farPoint;
varying vec3 eyePos;

varying mat4 fragView;
varying mat4 fragProj;

uniform float near;
uniform float far;

uniform float scale1;
uniform float scale2;

vec4 grid(vec3 fragPos3D, float scale)
{
    vec2 coord = fragPos3D.xy * scale;
    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(0.2,0.2,0.2,1.0 - min(line, 1.0));
    
    if(fragPos3D.x > -10 * minimumx && fragPos3D.x < 10 * minimumx)
    {
        color.z = 1.0;
    }
    
    if(fragPos3D.y > -10 * minimumz && fragPos3D.y < 10 * minimumz)
    {
        color.x = 1.0;
    }
        
    return color;
}

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

void main()
{
    // our grid should be on the XY plane so check fo z
    float t = -eyePos.z / (farPoint.z - eyePos.z);

    vec3 fragPos = eyePos + t * (farPoint - eyePos);
    
    float linearDepth = computeLinearDepth(fragPos);
    
    // fade at the horizon  
    vec3 eyeVec = normalize(eyePos - fragPos);
    float fading = min(1.0, abs(eyeVec.z) * 15.0);
    
    gl_FragColor = 
            (grid(fragPos, scale1) + grid(fragPos, scale2)) *          // adding multiple resolution for the grid
            vec4(1.0, 1.0, 1.0, max(0.0, fading - float(t<0.0)));     // hide the grid where it should not be visible
    
}

A full custom Design sample:

internal class MyDesign : devDept.Eyeshot.Control.Design
{
    private const string VERTEX_CODE = @"
        varying vec3 nearPoint;
        varying vec3 farPoint;
        varying vec3 eyePos;

        uniform mat4 proj;
        uniform mat4 mv;
        uniform vec3 eyeWorldPosition;

        varying mat4 fragView;
        varying mat4 fragProj;

        vec3 unprojectPoint(float x, float y, float z, mat4 mv, mat4 projection)
        {
            mat4 viewInv = inverse(mv);
            mat4 projInv = inverse(projection);
            
            vec4 unprojectedPoint = viewInv * projInv * vec4(x, y, z, 1.0);
            return unprojectedPoint / unprojectedPoint.w;
        }

        void main()
        {
            fragView = mv;
            fragProj = proj;
            eyePos   = eyeWorldPosition;

            gl_Position = ftransform();

            nearPoint = unprojectPoint(gl_Position.x, gl_Position.y, -1, mv, proj);
            farPoint  = unprojectPoint(gl_Position.x, gl_Position.y, 1, mv, proj);
        }
    ";

    private const string FRAGMENT_CODE = @"
        varying vec3 nearPoint;
        varying vec3 farPoint;
        varying vec3 eyePos;

        varying mat4 fragView;
        varying mat4 fragProj;

        uniform float near;
        uniform float far;

        uniform float scale1;
        uniform float scale2;

        vec4 grid(vec3 fragPos3D, float scale)
        {
            vec2 coord = fragPos3D.xy * scale;
            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(0.2,0.2,0.2,1.0 - min(line, 1.0));
            
            if(fragPos3D.x > -10 * minimumx && fragPos3D.x < 10 * minimumx)
            {
                color.z = 1.0;
            }
            
            if(fragPos3D.y > -10 * minimumz && fragPos3D.y < 10 * minimumz)
            {
                color.x = 1.0;
            }
                
            return color;
        }

        float computeLinearDepth(vec3 pos) 
        {
            vec4 clip_space_pos = fragProj * fragView * vec4(pos.xzy, 1.0);
// put back between -1 and 1 float clip_space_depth = (clip_space_pos.z / clip_space_pos.w) * 2.0 - 1.0;
// get linear value between 0.01 and 100 float lDepth = (2.0 * near * far) / (far + near - clip_space_depth * (far - near)); return lDepth / far; // normalize } void main() { // our grid should be on the XY plane so check fo z float t = -eyePos.z / (farPoint.z - eyePos.z); vec3 fragPos = eyePos + t * (farPoint - eyePos); float linearDepth = computeLinearDepth(fragPos); // fade at the horizon vec3 eyeVec = normalize(eyePos - fragPos); float fading = min(1.0, abs(eyeVec.z) * 15.0); gl_FragColor = (grid(fragPos, scale1) + grid(fragPos, scale2)) * // multi resolution vec4(1.0, 1.0, 1.0, max(0.0, fading - float(t<0.0)));// hide the grid where needed } "; private MyShader _shader; public MyDesign() { _shader = new MyShader(VERTEX_CODE, FRAGMENT_CODE); } protected override void OnHandleCreated(EventArgs e) { base.OnHandleCreated(e); ActiveViewport.Grid.Visible = false; } protected override void DrawViewportBackground(DrawSceneParams data) { base.DrawViewportBackground(data); DrawGrid(data); } private void DrawGrid(DrawSceneParams data) { float[] mv = new Identity().MatrixAsVectorFloatByColumn; float[] proj = ActiveViewport.Camera
.GetModelViewProjectionMatrix()
.Select(v => (float)v)
.ToArray(); gl.PushMatrix(); gl.MatrixMode(gl.PROJECTION); gl.LoadIdentity(); gl.MatrixMode(gl.MODELVIEW); gl.LoadIdentity(); if (!_shader.Compile(data.RenderContext)) { throw new Exception("Wrong compilation"); } _shader.Enable(data.RenderContext); gl.Enable(gl.BLEND); gl.Enable(gl.DEPTH_TEST); gl.Clear(gl.DEPTH_BUFFER_BIT); _shader.SetParameters( new MyShaderParameters( data.RenderContext, mv, proj, (float)ActiveViewport.Camera.Near, (float)ActiveViewport.Camera.Far, new float[] { (float)ActiveViewport.Camera.Location.X, (float)ActiveViewport.Camera.Location.Y, (float)ActiveViewport.Camera.Location.Z }, 0.01f, 0.05f)); data.RenderContext.DrawQuad(new RectangleF(-1, -1, 2, 2)); gl.PopMatrix(); data.RenderContext.SetShader(data.RenderContext.CurrentShader, data.ShaderParams, true); } } class MyShader : GLShader { public uint MyID => programObj; public MyShader(string vertexCode, string fragmentCode) : base(vertexCode, fragmentCode) { } public override void SetParameters(object shaderParams) { MyShaderParameters myParams = (MyShaderParameters)shaderParams; RenderContextBase context = myParams.RenderContext; Enable(context); gl.UseProgram(programObj); gl.UniformMatrix4fvARB(GetUniformLocation("proj"), 1, false, myParams.Projection); gl.UniformMatrix4fvARB(GetUniformLocation("mv"), 1, false, myParams.ModelView); gl.Uniform1f(GetUniformLocation("near"), myParams.Near); gl.Uniform1f(GetUniformLocation("far"), myParams.Far); gl.Uniform3f(GetUniformLocation("eyeWorldPosition"), myParams.EyeWorldPosition[0], myParams.EyeWorldPosition[1], myParams.EyeWorldPosition[2]); gl.Uniform1f(GetUniformLocation("scale1"), myParams.Scale1); gl.Uniform1f(GetUniformLocation("scale2"), myParams.Scale2); Disable(context); } } class MyShaderParameters : ShaderParameters { public readonly float[] ModelView; public readonly float[] Projection; public readonly float[] EyeWorldPosition; public readonly float Near; public readonly float Far; public readonly float Scale1; public readonly float Scale2; public MyShaderParameters( RenderContextBase renderContext, float[] modelView, float[] projection, float near, float far, float[] eyeWorldPosition, float scale1, float scale2) : base(renderContext) { ModelView = modelView; Projection = projection; EyeWorldPosition = eyeWorldPosition; Near = near; Far = far; Scale1 = scale1; Scale2 = scale2; } }

Limitations

  • This solution works only with OpenGL renderer.
Was this article helpful?
1 out of 1 found this helpful

Comments

0 comments

Please sign in to leave a comment.

Articles in this section

See more