Uses screen-aligned quads for origin lines to avoid issues on NVidia

While we are add it, use alpha-antialised lines to make them look nice
This commit is contained in:
clayjohn 2023-10-24 18:02:36 +02:00
parent e8d57afaec
commit 5591f289d7
2 changed files with 101 additions and 50 deletions

View file

@ -6486,25 +6486,91 @@ void Node3DEditor::_init_indicators() {
origin_enabled = true;
grid_enabled = true;
indicator_mat.instantiate();
indicator_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
indicator_mat->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
indicator_mat->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
indicator_mat->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);
indicator_mat->set_transparency(StandardMaterial3D::Transparency::TRANSPARENCY_ALPHA_DEPTH_PRE_PASS);
Ref<Shader> origin_shader = memnew(Shader);
origin_shader->set_code(R"(
// 3D editor origin line shader.
shader_type spatial;
render_mode blend_mix,cull_disabled,unshaded, fog_disabled;
void vertex() {
vec3 point_a = MODEL_MATRIX[3].xyz;
// Encoded in scale.
vec3 point_b = vec3(MODEL_MATRIX[0].x, MODEL_MATRIX[1].y, MODEL_MATRIX[2].z);
// Points are already in world space, so no need for MODEL_MATRIX anymore.
vec4 clip_a = PROJECTION_MATRIX * (VIEW_MATRIX * vec4(point_a, 1.0));
vec4 clip_b = PROJECTION_MATRIX * (VIEW_MATRIX * vec4(point_b, 1.0));
vec2 screen_a = VIEWPORT_SIZE * (0.5 * clip_a.xy / clip_a.w + 0.5);
vec2 screen_b = VIEWPORT_SIZE * (0.5 * clip_b.xy / clip_b.w + 0.5);
vec2 x_basis = normalize(screen_b - screen_a);
vec2 y_basis = vec2(-x_basis.y, x_basis.x);
float width = 3.0;
vec2 screen_point_a = screen_a + width * (VERTEX.x * x_basis + VERTEX.y * y_basis);
vec2 screen_point_b = screen_b + width * (VERTEX.x * x_basis + VERTEX.y * y_basis);
vec2 screen_point_final = mix(screen_point_a, screen_point_b, VERTEX.z);
vec4 clip_final = mix(clip_a, clip_b, VERTEX.z);
POSITION = vec4(clip_final.w * ((2.0 * screen_point_final) / VIEWPORT_SIZE - 1.0), clip_final.z, clip_final.w);
UV = VERTEX.yz * clip_final.w;
if (!OUTPUT_IS_SRGB) {
COLOR.rgb = mix(pow((COLOR.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)), COLOR.rgb * (1.0 / 12.92), lessThan(COLOR.rgb, vec3(0.04045)));
}
}
void fragment() {
// Multiply by 0.5 since UV is actually UV is [-1, 1].
float line_width = fwidth(UV.x * 0.5);
float line_uv = abs(UV.x * 0.5);
float line = smoothstep(line_width * 1.0, line_width * 0.25, line_uv);
ALBEDO = COLOR.rgb;
ALPHA *= COLOR.a * line;
}
)");
origin_mat.instantiate();
origin_mat->set_shader(origin_shader);
Vector<Color> origin_colors;
Vector<Vector3> origin_points;
origin_points.resize(6);
const int count_of_elements = 3 * 6;
origin_colors.resize(count_of_elements);
origin_points.resize(count_of_elements);
origin_points.set(0, Vector3(0.0, -0.5, 0.0));
origin_points.set(1, Vector3(0.0, -0.5, 1.0));
origin_points.set(2, Vector3(0.0, 0.5, 1.0));
int x = 0;
origin_points.set(3, Vector3(0.0, -0.5, 0.0));
origin_points.set(4, Vector3(0.0, 0.5, 1.0));
origin_points.set(5, Vector3(0.0, 0.5, 0.0));
Array d;
d.resize(RS::ARRAY_MAX);
d[RenderingServer::ARRAY_VERTEX] = origin_points;
origin_mesh = RenderingServer::get_singleton()->mesh_create();
RenderingServer::get_singleton()->mesh_add_surface_from_arrays(origin_mesh, RenderingServer::PRIMITIVE_TRIANGLES, d);
RenderingServer::get_singleton()->mesh_surface_set_material(origin_mesh, 0, origin_mat->get_rid());
origin_multimesh = RenderingServer::get_singleton()->multimesh_create();
RenderingServer::get_singleton()->multimesh_set_mesh(origin_multimesh, origin_mesh);
RenderingServer::get_singleton()->multimesh_allocate_data(origin_multimesh, 12, RS::MultimeshTransformFormat::MULTIMESH_TRANSFORM_3D, true, false);
RenderingServer::get_singleton()->multimesh_set_visible_instances(origin_multimesh, -1);
LocalVector<float> distances;
distances.resize(5);
distances[0] = -1000000.0;
distances[1] = -1000.0;
distances[2] = 0.0;
distances[3] = 1000.0;
distances[4] = 1000000.0;
for (int i = 0; i < 3; i++) {
Vector3 axis;
axis[i] = 1;
Color origin_color;
switch (i) {
case 0:
@ -6521,27 +6587,26 @@ void Node3DEditor::_init_indicators() {
break;
}
grid_enable[i] = false;
grid_visible[i] = false;
Vector3 axis;
axis[i] = 1;
origin_colors.set(x, origin_color);
origin_colors.set(x + 1, origin_color);
origin_colors.set(x + 2, origin_color);
origin_colors.set(x + 3, origin_color);
origin_colors.set(x + 4, origin_color);
origin_colors.set(x + 5, origin_color);
// To both allow having a large origin size and avoid jitter
// at small scales, we should segment the line into pieces.
// 3 pieces seems to do the trick, and let's use powers of 2.
origin_points.set(x, axis * 1048576);
origin_points.set(x + 1, axis * 1024);
origin_points.set(x + 2, axis * 1024);
origin_points.set(x + 3, axis * -1024);
origin_points.set(x + 4, axis * -1024);
origin_points.set(x + 5, axis * -1048576);
x += 6;
for (int j = 0; j < 4; j++) {
Transform3D t = Transform3D();
t = t.scaled(axis * distances[j + 1]);
t = t.translated(axis * distances[j]);
RenderingServer::get_singleton()->multimesh_instance_set_transform(origin_multimesh, i * 4 + j, t);
RenderingServer::get_singleton()->multimesh_instance_set_color(origin_multimesh, i * 4 + j, origin_color);
}
}
origin_instance = RenderingServer::get_singleton()->instance_create2(origin_multimesh, get_tree()->get_root()->get_world_3d()->get_scenario());
RS::get_singleton()->instance_set_layer_mask(origin_instance, 1 << Node3DEditorViewport::GIZMO_GRID_LAYER);
RS::get_singleton()->instance_geometry_set_flag(origin_instance, RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING, true);
RS::get_singleton()->instance_geometry_set_flag(origin_instance, RS::INSTANCE_FLAG_USE_BAKED_LIGHT, false);
RS::get_singleton()->instance_set_ignore_culling(origin_instance, true);
RenderingServer::get_singleton()->instance_geometry_set_cast_shadows_setting(origin_instance, RS::SHADOW_CASTING_SETTING_OFF);
Ref<Shader> grid_shader = memnew(Shader);
grid_shader->set_code(R"(
// 3D editor grid shader.
@ -6590,22 +6655,6 @@ void fragment() {
grid_visible[2] = grid_enable[2];
_init_grid();
origin = RenderingServer::get_singleton()->mesh_create();
Array d;
d.resize(RS::ARRAY_MAX);
d[RenderingServer::ARRAY_VERTEX] = origin_points;
d[RenderingServer::ARRAY_COLOR] = origin_colors;
RenderingServer::get_singleton()->mesh_add_surface_from_arrays(origin, RenderingServer::PRIMITIVE_LINES, d);
RenderingServer::get_singleton()->mesh_surface_set_material(origin, 0, indicator_mat->get_rid());
origin_instance = RenderingServer::get_singleton()->instance_create2(origin, get_tree()->get_root()->get_world_3d()->get_scenario());
RS::get_singleton()->instance_set_layer_mask(origin_instance, 1 << Node3DEditorViewport::GIZMO_GRID_LAYER);
RS::get_singleton()->instance_geometry_set_flag(origin_instance, RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING, true);
RS::get_singleton()->instance_geometry_set_flag(origin_instance, RS::INSTANCE_FLAG_USE_BAKED_LIGHT, false);
RenderingServer::get_singleton()->instance_geometry_set_cast_shadows_setting(origin_instance, RS::SHADOW_CASTING_SETTING_OFF);
}
{
@ -7223,7 +7272,8 @@ void Node3DEditor::_init_grid() {
void Node3DEditor::_finish_indicators() {
RenderingServer::get_singleton()->free(origin_instance);
RenderingServer::get_singleton()->free(origin);
RenderingServer::get_singleton()->free(origin_multimesh);
RenderingServer::get_singleton()->free(origin_mesh);
_finish_grid();
}

View file

@ -597,7 +597,8 @@ private:
ToolMode tool_mode;
RID origin;
RID origin_mesh;
RID origin_multimesh;
RID origin_instance;
bool origin_enabled = false;
RID grid[3];
@ -631,7 +632,7 @@ private:
RID indicators_instance;
RID cursor_mesh;
RID cursor_instance;
Ref<StandardMaterial3D> indicator_mat;
Ref<ShaderMaterial> origin_mat;
Ref<ShaderMaterial> grid_mat[3];
Ref<StandardMaterial3D> cursor_material;