diff --git a/source/blender/draw/engines/overlay/overlay_next_armature.hh b/source/blender/draw/engines/overlay/overlay_next_armature.hh index c891ead3e73..c8bee4d156d 100644 --- a/source/blender/draw/engines/overlay/overlay_next_armature.hh +++ b/source/blender/draw/engines/overlay/overlay_next_armature.hh @@ -288,6 +288,7 @@ class Armatures : Overlay { sub.shader_set(res.shaders.armature_shape_wire.get()); sub.push_constant("alpha", 1.0f); sub.push_constant("do_smooth_wire", do_smooth_wire); + sub.push_constant("use_arrow_drawing", false); opaque_.shape_wire = ⊂ } if (use_wire_alpha) { @@ -297,6 +298,7 @@ class Armatures : Overlay { sub.bind_texture("depthTex", depth_tex); sub.push_constant("alpha", wire_alpha * 0.6f); sub.push_constant("do_smooth_wire", do_smooth_wire); + sub.push_constant("use_arrow_drawing", false); transparent_.shape_wire = ⊂ } else { @@ -309,6 +311,7 @@ class Armatures : Overlay { sub.shader_set(res.shaders.armature_shape_wire_strip.get()); sub.push_constant("alpha", 1.0f); sub.push_constant("do_smooth_wire", do_smooth_wire); + sub.push_constant("use_arrow_drawing", false); opaque_.shape_wire_strip = ⊂ } if (use_wire_alpha) { @@ -318,6 +321,7 @@ class Armatures : Overlay { sub.bind_texture("depthTex", depth_tex); sub.push_constant("alpha", wire_alpha * 0.6f); sub.push_constant("do_smooth_wire", do_smooth_wire); + sub.push_constant("use_arrow_drawing", false); transparent_.shape_wire_strip = ⊂ } else { @@ -593,6 +597,7 @@ class Armatures : Overlay { using CustomShapeBuf = MutableMapItem>; + gpu::Batch *arrow_batch = res.shapes.arrows.get(); for (CustomShapeBuf item : bb.custom_shape_fill.items()) { item.value->end_sync(*bb.shape_fill, item.key); } @@ -600,7 +605,19 @@ class Armatures : Overlay { item.value->end_sync(*bb.shape_outline, item.key, GPU_PRIM_LINES, 1); } for (CustomShapeBuf item : bb.custom_shape_wire.items()) { + /* WORKAROUND: This shape needs a special vertex shader path that should be triggered by + * its vclass attribute. However, to avoid many changes in the primitive expansion API, + * we create a specific path inside the shader only for this shape batch and infer the + * value of the `vclass` attribute based on the vertex index. */ + if (item.key == arrow_batch) { + bb.shape_wire->push_constant("use_arrow_drawing", true); + } + item.value->end_sync(*bb.shape_wire, item.key, GPU_PRIM_TRIS, 2); + + if (item.key == arrow_batch) { + bb.shape_wire->push_constant("use_arrow_drawing", false); + } } for (CustomShapeBuf item : bb.custom_shape_wire_strip.items()) { item.value->end_sync(*bb.shape_wire_strip, item.key, GPU_PRIM_TRIS, 2); diff --git a/source/blender/draw/engines/overlay/overlay_next_shape.cc b/source/blender/draw/engines/overlay/overlay_next_shape.cc index 39b8f5576c6..1a71cdf332c 100644 --- a/source/blender/draw/engines/overlay/overlay_next_shape.cc +++ b/source/blender/draw/engines/overlay/overlay_next_shape.cc @@ -867,20 +867,23 @@ ShapeCache::ShapeCache() * Fractional part of Z is a positive offset at axis unit position. */ int flag = VCLASS_EMPTY_AXES | VCLASS_SCREENALIGNED; /* Center to axis line. */ + /* NOTE: overlay_armature_shape_wire_vert.glsl expects the axis verts at the origin to be the + * only ones with this coordinates (it derives the VCLASS from it). */ + float pos_on_axis = float(axis) + 1e-8f; verts.append({{0.0f, 0.0f, 0.0f}, 0}); - verts.append({{0.0f, 0.0f, float(axis)}, flag}); + verts.append({{0.0f, 0.0f, pos_on_axis}, flag}); /* Axis end marker. */ constexpr int marker_fill_layer = 6; for (int j = 1; j < marker_fill_layer + 1; j++) { for (float2 axis_marker_vert : axis_marker) { - verts.append({{axis_marker_vert * ((4.0f * j) / marker_fill_layer), float(axis)}, flag}); + verts.append({{axis_marker_vert * ((4.0f * j) / marker_fill_layer), pos_on_axis}, flag}); } } /* Axis name. */ const Vector *axis_names[3] = {&x_axis_name, &y_axis_name, &z_axis_name}; for (float2 axis_name_vert : *(axis_names[axis])) { int flag = VCLASS_EMPTY_AXES | VCLASS_EMPTY_AXES_NAME | VCLASS_SCREENALIGNED; - verts.append({{axis_name_vert * 4.0f, axis + 0.25f}, flag}); + verts.append({{axis_name_vert * 4.0f, pos_on_axis + 0.25f}, flag}); } } arrows = BatchPtr( diff --git a/source/blender/draw/engines/overlay/shaders/infos/overlay_armature_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_armature_info.hh index f747f8f14e5..22053e3f24c 100644 --- a/source/blender/draw/engines/overlay/shaders/infos/overlay_armature_info.hh +++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_armature_info.hh @@ -134,6 +134,7 @@ PUSH_CONSTANT(BOOL, do_smooth_wire) STORAGE_BUF_FREQ(0, READ, float, pos[], GEOMETRY) STORAGE_BUF(1, READ, mat4, data_buf[]) PUSH_CONSTANT(IVEC2, gpu_attr_0) +PUSH_CONSTANT(BOOL, use_arrow_drawing) VERTEX_OUT(overlay_armature_shape_wire_iface) VERTEX_SOURCE("overlay_armature_shape_wire_vert.glsl") FRAGMENT_SOURCE("overlay_armature_shape_wire_frag.glsl") diff --git a/source/blender/draw/engines/overlay/shaders/overlay_armature_shape_wire_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_shape_wire_vert.glsl index b247cbf4e87..ef18001ad13 100644 --- a/source/blender/draw/engines/overlay/shaders/overlay_armature_shape_wire_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_shape_wire_vert.glsl @@ -38,7 +38,30 @@ VertOut vertex_main(VertIn v_in) mat4 model_mat = extract_matrix_packed_data(v_in.inst_matrix, state_color, bone_color); VertOut v_out; - v_out.world_pos = (model_mat * vec4(v_in.lP, 1.0)).xyz; + + /* WORKAROUND: This shape needs a special vertex shader path that should be triggered by + * its vclass attribute. However, to avoid many changes in the primitive expansion API, + * we create a specific path inside the shader only for this shape batch and infer the + * value of the `vclass` attribute based on the vertex index. */ + if (use_arrow_drawing) { + /* Keep in sync with the arrows shape batch creation. */ + /* Adapted from overlay_extra_vert.glsl. */ + vec3 vpos = v_in.lP; + vec3 vofs = vec3(0.0); + uint axis = uint(vpos.z); + /* Assumes origin vertices are the only one at Z=0. */ + if (vpos.z > 0.0) { + vofs[axis] = (1.0 + fract(vpos.z)); + } + /* Scale uniformly by axis length */ + vpos *= length(model_mat[axis].xyz); + /* World sized, camera facing geometry. */ + vec3 screen_pos = ViewMatrixInverse[0].xyz * vpos.x + ViewMatrixInverse[1].xyz * vpos.y; + v_out.world_pos = (model_mat * vec4(vofs, 1.0)).xyz + screen_pos; + } + else { + v_out.world_pos = (model_mat * vec4(v_in.lP, 1.0)).xyz; + } v_out.gpu_position = drw_point_world_to_homogenous(v_out.world_pos); v_out.finalColor.rgb = mix(state_color.rgb, bone_color.rgb, 0.5);