VR Grid floor with falloff based on XRCamera position.

A simple grid shader that calculates the falloff from the center of the XRCamera. 

Needs the below script to be attached to a MeshInstance3D with a PlaneMesh.

If you got any pointers on how to improve it, let me know!

extends MeshInstance3D

@onready var plane = self
@onready var camera_global_position = %XRCamera3D.global_transform.origin
@onready var camera_local_position = plane.to_local(camera_global_position)
@onready var projected_position = Vector2(camera_local_position.x, camera_local_position.z)
@onready var plane_size = mesh.size  

func _process(delta):
	camera_global_position = %XRCamera3D.global_transform.origin
	camera_local_position = plane.to_local(camera_global_position)
	projected_position = Vector2(camera_local_position.x, camera_local_position.z)
	
	var uv_coordinates = Vector2(
		0.5 + camera_local_position.x / plane_size.x,
		0.5 + camera_local_position.z / plane_size.y
	)

	var shader_material = mesh.surface_get_material(0) # Assuming the mesh is the first surface
	if shader_material and shader_material is ShaderMaterial:
		shader_material.set_shader_parameter("camera_uv", uv_coordinates)

 

Shader code
// Inspired and heavyily copied code from this excellent post:
// https://bgolus.medium.com/the-best-darn-grid-shader-yet-727f9278b9d8

shader_type spatial;

render_mode blend_mix;

uniform vec2 camera_uv;

void vertex() {
	// Called for every vertex the material is visible on.
}

float pristineGrid(vec2 uv, vec2 lineWidth) {
    vec2 ddx = dFdx(uv);
    vec2 ddy = dFdy(uv);
    vec2 uvDeriv = vec2(length(vec2(ddx.x, ddy.x)), length(vec2(ddx.y, ddy.y)));
    bvec2 invertLine = bvec2(lineWidth.x > 0.5, lineWidth.y > 0.5);
    vec2 targetWidth = vec2(
        invertLine.x ? .0 - lineWidth.x : lineWidth.x,
        invertLine.y ? 1.0 - lineWidth.y : lineWidth.y
    );
    vec2 drawWidth = clamp(targetWidth, uvDeriv, vec2(0.5));
    vec2 lineAA = uvDeriv * 1.5;
    vec2 gridUV = abs(fract(uv) * 2.0 - 1.0);
    gridUV.x = invertLine.x ? gridUV.x : 1.0 - gridUV.x;
    gridUV.y = invertLine.y ? gridUV.y : 1.0 - gridUV.y;
    vec2 grid2 = smoothstep(drawWidth + lineAA, drawWidth - lineAA, gridUV);

    grid2 *= clamp(targetWidth / drawWidth, 0.0, 1.0);
    grid2 = mix(grid2, targetWidth, clamp(uvDeriv * 2.0 - 1.0, 0.0, 1.0));
    grid2.x = invertLine.x ? 1.0 - grid2.x : grid2.x;
    grid2.y = invertLine.y ? 1.0 - grid2.y : grid2.y;
    return mix(grid2.x, 1.0, grid2.y);
}

void fragment() {
	// Adjust this to control the number of grid lines
	float scaleFactor = 500.0; 
    vec2 scaledUV = UV * scaleFactor;

    // Adjust line width as needed
    vec2 lineWidth = vec2(0.025, 0.025); 

    // Generate the grid pattern
    float gridValue = pristineGrid(scaledUV, lineWidth);

    // Calculate distance falloff
	float centerDistance = length(UV - camera_uv);
    float falloffStart = 0.0; // Start of the falloff
    float falloffEnd = 0.5; // End of the falloff, after which the grid is completely faded out
    float falloff = 0.25 - smoothstep(falloffStart, falloffEnd, centerDistance);
    falloff = clamp(falloff, 0.0, 1.0); // Ensure falloff doesn't go below 0

    // Apply the distance falloff to the grid value
    float finalGridValue = gridValue * falloff;

    ALBEDO = vec3(finalGridValue);
    ALPHA = gridValue * falloff;
}
Tags
grid, VR, XR
The shader code and all code snippets in this post are under CC0 license and can be used freely without the author's permission. Images and videos, and assets depicted in those, do not fall under this license. For more info, see our License terms.

Related shaders

Circle Mask (with Feathering & Position)

Quick Procedural Floor Tiles

Dashed Grid (The Best Darn Grid Shader (Yet))

Subscribe
Notify of
guest

2 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Kimau
Kimau
3 months ago

You can just use the global CAMERA_POSITION_WORLD.
Also you prob should make uniforms
uniform float grid_scale = 50.0;
uniform float line_width = 0.01;