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.
Comments
Please sign in to leave a comment.