diff options
Diffstat (limited to 'source/blender/draw')
-rw-r--r-- | source/blender/draw/CMakeLists.txt | 3 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_armature.c | 10 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache.c | 65 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_common.c | 46 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_common.h | 2 | ||||
-rw-r--r-- | source/blender/draw/modes/shaders/armature_sphere_frag.glsl | 74 | ||||
-rw-r--r-- | source/blender/draw/modes/shaders/armature_sphere_outline_vert.glsl | 102 | ||||
-rw-r--r-- | source/blender/draw/modes/shaders/armature_sphere_vert.glsl | 79 |
8 files changed, 380 insertions, 1 deletions
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 27daab90234..3ab0ea40990 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -221,6 +221,9 @@ data_to_c_simple(modes/shaders/common_globals_lib.glsl SRC) data_to_c_simple(modes/shaders/common_view_lib.glsl SRC) data_to_c_simple(modes/shaders/common_fxaa_lib.glsl SRC) data_to_c_simple(modes/shaders/common_fullscreen_vert.glsl SRC) +data_to_c_simple(modes/shaders/armature_sphere_vert.glsl SRC) +data_to_c_simple(modes/shaders/armature_sphere_frag.glsl SRC) +data_to_c_simple(modes/shaders/armature_sphere_outline_vert.glsl SRC) data_to_c_simple(modes/shaders/armature_shape_outline_vert.glsl SRC) data_to_c_simple(modes/shaders/armature_shape_outline_geom.glsl SRC) data_to_c_simple(modes/shaders/edit_mesh_overlay_frag.glsl SRC) diff --git a/source/blender/draw/intern/draw_armature.c b/source/blender/draw/intern/draw_armature.c index 195acfb7c1f..756cc3e6992 100644 --- a/source/blender/draw/intern/draw_armature.c +++ b/source/blender/draw/intern/draw_armature.c @@ -250,8 +250,12 @@ static void drw_shgroup_bone_custom_wire(const float (*bone_mat)[4], const float static void drw_shgroup_bone_point_solid(const float (*bone_mat)[4], const float color[4]) { if (g_data.bone_point_solid == NULL) { - struct Gwn_Batch *geom = DRW_cache_bone_point_get(); +#if 0 /* old style geometry sphere */ + struct Gwn_Batch *geom = DRW_cache_bone_point_get() g_data.bone_point_solid = shgroup_instance_solid(g_data.pass_bone_solid, geom); +#else /* new style raytraced sphere */ + g_data.bone_point_solid = shgroup_instance_armature_sphere(g_data.pass_bone_solid); +#endif } float final_bonemat[4][4]; mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat); @@ -261,8 +265,12 @@ static void drw_shgroup_bone_point_solid(const float (*bone_mat)[4], const float static void drw_shgroup_bone_point_wire(const float (*bone_mat)[4], const float color[4]) { if (g_data.bone_point_wire == NULL) { +#if 0 /* old style 3 axis circles */ struct Gwn_Batch *geom = DRW_cache_bone_point_wire_outline_get(); g_data.bone_point_wire = shgroup_instance_wire(g_data.pass_bone_wire, geom); +#else /* new style contour outline */ + g_data.bone_point_wire = shgroup_instance_armature_sphere_outline(g_data.pass_bone_wire); +#endif } float final_bonemat[4][4]; mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat); diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c index 439809139c9..587bcac1029 100644 --- a/source/blender/draw/intern/draw_cache.c +++ b/source/blender/draw/intern/draw_cache.c @@ -2082,6 +2082,7 @@ Gwn_Batch *DRW_cache_bone_envelope_head_wire_outline_get(void) Gwn_Batch *DRW_cache_bone_point_get(void) { if (!SHC.drw_bone_point) { +#if 0 /* old style geometry sphere */ const int lon_res = 16; const int lat_res = 8; const float rad = 0.05f; @@ -2119,6 +2120,30 @@ Gwn_Batch *DRW_cache_bone_point_get(void) } SHC.drw_bone_point = GWN_batch_create_ex(GWN_PRIM_TRIS, vbo, NULL, GWN_BATCH_OWNS_VBO); +#else +# define CIRCLE_RESOL 64 + float v[2]; + const float radius = 0.05f; + + /* Position Only 2D format */ + static Gwn_VertFormat format = { 0 }; + static struct { uint pos; } attr_id; + if (format.attrib_ct == 0) { + attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + } + + Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format); + GWN_vertbuf_data_alloc(vbo, CIRCLE_RESOL); + + for (int a = 0; a < CIRCLE_RESOL; a++) { + v[0] = radius * sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL)); + v[1] = radius * cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL)); + GWN_vertbuf_attr_set(vbo, attr_id.pos, a, v); + } + + SHC.drw_bone_point = GWN_batch_create_ex(GWN_PRIM_TRI_FAN, vbo, NULL, GWN_BATCH_OWNS_VBO); +# undef CIRCLE_RESOL +#endif } return SHC.drw_bone_point; } @@ -2126,8 +2151,48 @@ Gwn_Batch *DRW_cache_bone_point_get(void) Gwn_Batch *DRW_cache_bone_point_wire_outline_get(void) { if (!SHC.drw_bone_point_wire) { +#if 0 /* old style geometry sphere */ Gwn_VertBuf *vbo = sphere_wire_vbo(0.05f); SHC.drw_bone_point_wire = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO); +#else +# define CIRCLE_RESOL 64 + float v0[2], v1[2]; + const float radius = 0.05f; + + /* Position Only 2D format */ + static Gwn_VertFormat format = { 0 }; + static struct { uint pos0, pos1; } attr_id; + if (format.attrib_ct == 0) { + attr_id.pos0 = GWN_vertformat_attr_add(&format, "pos0", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + attr_id.pos1 = GWN_vertformat_attr_add(&format, "pos1", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); + } + + Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format); + GWN_vertbuf_data_alloc(vbo, (CIRCLE_RESOL + 1) * 2); + + v0[0] = radius * sinf((2.0f * M_PI * -1) / ((float)CIRCLE_RESOL)); + v0[1] = radius * cosf((2.0f * M_PI * -1) / ((float)CIRCLE_RESOL)); + + unsigned int v = 0; + for (int a = 0; a < CIRCLE_RESOL; a++) { + v1[0] = radius * sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL)); + v1[1] = radius * cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL)); + GWN_vertbuf_attr_set(vbo, attr_id.pos0, v , v0); + GWN_vertbuf_attr_set(vbo, attr_id.pos1, v++, v1); + GWN_vertbuf_attr_set(vbo, attr_id.pos0, v , v0); + GWN_vertbuf_attr_set(vbo, attr_id.pos1, v++, v1); + copy_v2_v2(v0, v1); + } + v1[0] = 0.0f; + v1[1] = radius; + GWN_vertbuf_attr_set(vbo, attr_id.pos0, v , v0); + GWN_vertbuf_attr_set(vbo, attr_id.pos1, v++, v1); + GWN_vertbuf_attr_set(vbo, attr_id.pos0, v , v0); + GWN_vertbuf_attr_set(vbo, attr_id.pos1, v++, v1); + + SHC.drw_bone_point_wire = GWN_batch_create_ex(GWN_PRIM_TRI_STRIP, vbo, NULL, GWN_BATCH_OWNS_VBO); +# undef CIRCLE_RESOL +#endif } return SHC.drw_bone_point_wire; } diff --git a/source/blender/draw/intern/draw_common.c b/source/blender/draw/intern/draw_common.c index 3a2aa970a9b..6d684b1c9fb 100644 --- a/source/blender/draw/intern/draw_common.c +++ b/source/blender/draw/intern/draw_common.c @@ -156,12 +156,17 @@ void DRW_globals_update(void) /* ********************************* SHGROUP ************************************* */ +extern char datatoc_armature_sphere_vert_glsl[]; +extern char datatoc_armature_sphere_frag_glsl[]; +extern char datatoc_armature_sphere_outline_vert_glsl[]; extern char datatoc_armature_shape_outline_vert_glsl[]; extern char datatoc_armature_shape_outline_geom_glsl[]; extern char datatoc_gpu_shader_flat_color_frag_glsl[]; static struct { struct GPUShader *shape_outline; + struct GPUShader *bone_sphere; + struct GPUShader *bone_sphere_outline; } g_armature_shaders = {NULL}; static struct { @@ -491,6 +496,47 @@ DRWShadingGroup *shgroup_instance_armature_shape_outline(DRWPass *pass, struct G return grp; } +DRWShadingGroup *shgroup_instance_armature_sphere(DRWPass *pass) +{ + if (g_armature_shaders.bone_sphere == NULL) { + g_armature_shaders.bone_sphere = DRW_shader_create( + datatoc_armature_sphere_vert_glsl, NULL, + datatoc_armature_sphere_frag_glsl, NULL); + } + + /* TODO own format? */ + DRW_shgroup_instance_format(g_formats.instance_color, { + {"InstanceModelMatrix", DRW_ATTRIB_FLOAT, 16}, + {"color" , DRW_ATTRIB_FLOAT, 4} + }); + + DRWShadingGroup *grp = DRW_shgroup_instance_create(g_armature_shaders.bone_sphere, + pass, DRW_cache_bone_point_get(), g_formats.instance_color); + + return grp; +} + +DRWShadingGroup *shgroup_instance_armature_sphere_outline(DRWPass *pass) +{ + if (g_armature_shaders.bone_sphere_outline == NULL) { + g_armature_shaders.bone_sphere_outline = DRW_shader_create( + datatoc_armature_sphere_outline_vert_glsl, NULL, + datatoc_gpu_shader_flat_color_frag_glsl, NULL); + } + + /* TODO own format? */ + DRW_shgroup_instance_format(g_formats.instance_color, { + {"InstanceModelMatrix", DRW_ATTRIB_FLOAT, 16}, + {"color" , DRW_ATTRIB_FLOAT, 4} + }); + + DRWShadingGroup *grp = DRW_shgroup_instance_create(g_armature_shaders.bone_sphere_outline, + pass, DRW_cache_bone_point_wire_outline_get(), + g_formats.instance_color); + DRW_shgroup_uniform_vec2(grp, "viewportSize", DRW_viewport_size_get(), 1); + + return grp; +} diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h index 8b418135342..ad6ab2d89fd 100644 --- a/source/blender/draw/intern/draw_common.h +++ b/source/blender/draw/intern/draw_common.h @@ -122,6 +122,8 @@ struct DRWShadingGroup *shgroup_instance_bone_envelope_wire(struct DRWPass *pass struct DRWShadingGroup *shgroup_instance_bone_envelope_solid(struct DRWPass *pass, struct Gwn_Batch *geom); struct DRWShadingGroup *shgroup_instance_mball_handles(struct DRWPass *pass, struct Gwn_Batch *geom); struct DRWShadingGroup *shgroup_instance_armature_shape_outline(struct DRWPass *pass, struct Gwn_Batch *geom); +struct DRWShadingGroup *shgroup_instance_armature_sphere(struct DRWPass *pass); +struct DRWShadingGroup *shgroup_instance_armature_sphere_outline(struct DRWPass *pass); int DRW_object_wire_theme_get( struct Object *ob, struct ViewLayer *view_layer, float **r_color); diff --git a/source/blender/draw/modes/shaders/armature_sphere_frag.glsl b/source/blender/draw/modes/shaders/armature_sphere_frag.glsl new file mode 100644 index 00000000000..66d40e92bce --- /dev/null +++ b/source/blender/draw/modes/shaders/armature_sphere_frag.glsl @@ -0,0 +1,74 @@ + +#extension GL_ARB_conservative_depth : enable + +uniform mat4 ViewMatrixInverse; +uniform mat4 ProjectionMatrix; + +flat in vec3 solidColor; +flat in mat4 sphereMatrix; +in vec3 viewPosition; + +#ifdef GL_ARB_conservative_depth +/* Saves a lot of overdraw! */ +layout(depth_greater) out float gl_FragDepth; +#endif + +out vec4 fragColor; + +#define cameraPos ViewMatrixInverse[3].xyz + +float get_depth_from_view_z(float z) +{ + if (ProjectionMatrix[3][3] == 0.0) { + z = (-ProjectionMatrix[3][2] / z) - ProjectionMatrix[2][2]; + } + else { + z = z * ProjectionMatrix[2][2] / (1.0 - ProjectionMatrix[3][2]); + } + return z * 0.5 + 0.5; +} + +void main() +{ + const float sphere_radius = 0.05; + + bool is_perp = (ProjectionMatrix[3][3] == 0.0); + vec3 ray_ori_view = (is_perp) ? vec3(0.0) : viewPosition.xyz; + vec3 ray_dir_view = (is_perp) ? viewPosition : vec3(0.0, 0.0, -1.0); + + /* Single matrix mul without branch. */ + vec4 mul_vec = (is_perp) ? vec4(ray_dir_view, 0.0) : vec4(ray_ori_view, 1.0); + vec3 mul_res = (sphereMatrix * mul_vec).xyz; + + /* Reminder : + * sphereMatrix[3] is the view space origin in sphere space (sph_ori -> view_ori). + * sphereMatrix[2] is the view space Z axis in sphere space. */ + + /* convert to sphere local space */ + vec3 ray_ori = (is_perp) ? sphereMatrix[3].xyz : mul_res; + vec3 ray_dir = (is_perp) ? mul_res : -sphereMatrix[2].xyz; + float ray_len = length(ray_dir); + ray_dir /= ray_len; + + /* Line to sphere intersect */ + const float sphere_radius_sqr = sphere_radius * sphere_radius; + float b = dot(ray_ori, ray_dir); + float c = dot(ray_ori, ray_ori) - sphere_radius_sqr; + float h = b * b - c; + float t = -sqrt(max(0.0, h)) - b; + + /* Compute dot product for lighting */ + vec3 p = ray_dir * t + ray_ori; /* Point on sphere */ + vec3 n = normalize(p); /* Normal is just the point in sphere space, normalized. */ + vec3 l = normalize(sphereMatrix[2].xyz); /* Just the view Z axis in the sphere space. */ + float col = clamp(dot(n, l), 0.0, 1.0); + + /* 2x2 dither pattern to smooth the lighting. */ + float dither = (0.5 + dot(vec2(ivec2(gl_FragCoord.xy) & ivec2(1)), vec2(1.0, 2.0))) * 0.25; + dither *= (1.0 / 255.0); /* Assume 8bit per color buffer. */ + + fragColor = vec4(col * solidColor + dither, 1.0); + + t /= ray_len; + gl_FragDepth = get_depth_from_view_z(ray_dir_view.z * t + ray_ori_view.z); +} diff --git a/source/blender/draw/modes/shaders/armature_sphere_outline_vert.glsl b/source/blender/draw/modes/shaders/armature_sphere_outline_vert.glsl new file mode 100644 index 00000000000..8fe20decdca --- /dev/null +++ b/source/blender/draw/modes/shaders/armature_sphere_outline_vert.glsl @@ -0,0 +1,102 @@ + +uniform mat4 ViewMatrix; +uniform mat4 ProjectionMatrix; +uniform vec2 viewportSize; +uniform float lineThickness = 3.0; + +/* ---- Instanciated Attribs ---- */ +in vec2 pos0; +in vec2 pos1; + +/* ---- Per instance Attribs ---- */ +in mat4 InstanceModelMatrix; +in vec4 color; + +flat out vec4 finalColor; + +/* project to screen space */ +vec2 proj(vec4 pos) +{ + return (0.5 * (pos.xy / pos.w) + 0.5) * viewportSize; +} + +vec2 compute_dir(vec2 v0, vec2 v1, vec2 c) +{ + vec2 dir = normalize(v1 - v0); + dir = vec2(dir.y, -dir.x); + /* The model matrix can be scaled negativly. + * Use projected sphere center to determine + * the outline direction. */ + vec2 cv = c - v0; + dir = (dot(dir, cv) > 0.0) ? -dir : dir; + return dir; +} + +void main() +{ + mat4 model_view_matrix = ViewMatrix * InstanceModelMatrix; + mat4 sphereMatrix = inverse(model_view_matrix); + + bool is_persp = (ProjectionMatrix[3][3] == 0.0); + + /* This is the local space camera ray (not normalize). + * In perspective mode it's also the viewspace position + * of the sphere center. */ + vec3 cam_ray = (is_persp) ? model_view_matrix[3].xyz : vec3(0.0, 0.0, -1.0); + cam_ray = mat3(sphereMatrix) * cam_ray; + + /* Sphere center distance from the camera (persp) in local space. */ + float cam_dist = length(cam_ray); + + /* Compute view aligned orthonormal space. */ + vec3 z_axis = cam_ray / cam_dist; + vec3 x_axis = normalize(cross(sphereMatrix[1].xyz, z_axis)); + vec3 y_axis = cross(z_axis, x_axis); + float z_ofs = 0.0; + + if (is_persp) { + /* For perspective, the projected sphere radius + * can be bigger than the center disc. Compute the + * max angular size and compensate by sliding the disc + * towards the camera and scale it accordingly. */ + const float half_pi = 3.1415926 * 0.5; + const float rad = 0.05; + /* Let be (in local space): + * V the view vector origin. + * O the sphere origin. + * T the point on the target circle. + * We compute the angle between (OV) and (OT). */ + float a = half_pi - asin(rad / cam_dist); + float cos_b = cos(a); + float sin_b = sqrt(clamp(1.0 - cos_b * cos_b, 0.0, 1.0)); + + x_axis *= sin_b; + y_axis *= sin_b; + z_ofs = -rad * cos_b; + } + + /* Camera oriented position (but still in local space) */ + vec3 cam_pos0 = x_axis * pos0.x + y_axis * pos0.y + z_axis * z_ofs; + vec3 cam_pos1 = x_axis * pos1.x + y_axis * pos1.y + z_axis * z_ofs; + + vec4 V = model_view_matrix * vec4(cam_pos0, 1.0); + vec4 p0 = ProjectionMatrix * V; + vec4 p1 = ProjectionMatrix * (model_view_matrix * vec4(cam_pos1, 1.0)); + vec4 c = ProjectionMatrix * vec4(model_view_matrix[3].xyz, 1.0); + + vec2 ssc = proj(c); + vec2 ss0 = proj(p0); + vec2 ss1 = proj(p1); + vec2 edge_dir = compute_dir(ss0, ss1, ssc); + + bool outer = ((gl_VertexID & 1) == 1); + + vec2 t = lineThickness / viewportSize; + t *= (is_persp) ? abs(V.z) : 1.0; + t = (outer) ? t : vec2(0.0); + + gl_Position = p0; + gl_Position.xy += t * edge_dir; + + finalColor = color; +} diff --git a/source/blender/draw/modes/shaders/armature_sphere_vert.glsl b/source/blender/draw/modes/shaders/armature_sphere_vert.glsl new file mode 100644 index 00000000000..fdd27de0eb1 --- /dev/null +++ b/source/blender/draw/modes/shaders/armature_sphere_vert.glsl @@ -0,0 +1,79 @@ + +uniform mat4 ViewMatrix; +uniform mat4 ProjectionMatrix; + +/* ---- Instanciated Attribs ---- */ +in vec2 pos; + +/* ---- Per instance Attribs ---- */ +in mat4 InstanceModelMatrix; +in vec3 color; + +flat out vec3 solidColor; +flat out mat4 sphereMatrix; +out vec3 viewPosition; + +/* Sphere radius */ +const float rad = 0.05; + +void main() +{ + mat4 model_view_matrix = ViewMatrix * InstanceModelMatrix; + sphereMatrix = inverse(model_view_matrix); + + bool is_persp = (ProjectionMatrix[3][3] == 0.0); + + /* This is the local space camera ray (not normalize). + * In perspective mode it's also the viewspace position + * of the sphere center. */ + vec3 cam_ray = (is_persp) ? model_view_matrix[3].xyz : vec3(0.0, 0.0, -1.0); + cam_ray = mat3(sphereMatrix) * cam_ray; + + /* Sphere center distance from the camera (persp) in local space. */ + float cam_dist = length(cam_ray); + + /* Compute view aligned orthonormal space. */ + vec3 z_axis = cam_ray / cam_dist; + vec3 x_axis = normalize(cross(sphereMatrix[1].xyz, z_axis)); + vec3 y_axis = cross(z_axis, x_axis); + + float z_ofs = -rad - 1e-8; /* offset to the front of the sphere */ + if (is_persp) { + /* For perspective, the projected sphere radius + * can be bigger than the center disc. Compute the + * max angular size and compensate by sliding the disc + * towards the camera and scale it accordingly. */ + const float half_pi = 3.1415926 * 0.5; + /* Let be (in local space): + * V the view vector origin. + * O the sphere origin. + * T the point on the target circle. + * We compute the angle between (OV) and (OT). */ + float a = half_pi - asin(rad / cam_dist); + float cos_b = cos(a); + float sin_b = sqrt(clamp(1.0 - cos_b * cos_b, 0.0, 1.0)); +#if 1 + /* Instead of choosing the biggest circle in screenspace, + * we choose the nearest with the same angular size. This + * permit us to leverage GL_ARB_conservative_depth in the + * fragment shader. */ + float minor = cam_dist - rad; + float major = cam_dist - cos_b * rad; + float fac = minor / major; + sin_b *= fac; +#else + z_ofs = -rad * cos_b; +#endif + x_axis *= sin_b; + y_axis *= sin_b; + } + + /* Camera oriented position (but still in local space) */ + vec3 cam_pos = x_axis * pos.x + y_axis * pos.y + z_axis * z_ofs; + + vec4 V = model_view_matrix * vec4(cam_pos, 1.0); + gl_Position = ProjectionMatrix * V; + viewPosition = V.xyz; + + solidColor = color; +} |