DwM: Armature: add solid envelope bone drawing.

Envelope bones are now pretty much identical to old drawing code.

Note that currently new DwM drawing code does not seem to care about
wire/solid drawing modes at all, guess this is still TODO... For now we
hence just get both wire and solid for envelope bones, this can be
refined later.
This commit is contained in:
2017-05-18 11:41:59 +02:00
parent 5919919955
commit 23f256b24b
9 changed files with 304 additions and 6 deletions

View File

@@ -78,6 +78,7 @@ static struct {
DRWShadingGroup *bone_box_solid;
DRWShadingGroup *bone_box_wire;
DRWShadingGroup *bone_wire_wire;
DRWShadingGroup *bone_envelope_solid;
DRWShadingGroup *bone_envelope_distance;
DRWShadingGroup *bone_envelope_wire;
DRWShadingGroup *bone_envelope_head_wire;
@@ -165,6 +166,18 @@ static void DRW_shgroup_bone_envelope_distance(
}
}
static void DRW_shgroup_bone_envelope_solid(
const float (*bone_mat)[4], const float color[4],
const float *radius_head, const float *radius_tail)
{
if (g_data.bone_envelope_solid == NULL) {
struct Batch *geom = DRW_cache_bone_envelope_get();
g_data.bone_envelope_solid = shgroup_instance_bone_envelope_solid(g_data.pass_bone_solid, geom, g_data.ob->obmat);
}
DRW_shgroup_call_dynamic_add(g_data.bone_envelope_solid, bone_mat, color, radius_head, radius_tail);
}
static void DRW_shgroup_bone_envelope_wire(
const float (*bone_mat)[4], const float color[4],
const float *radius_head, const float *radius_tail, const float *distance)
@@ -591,7 +604,31 @@ static const float *get_bone_solid_color(
}
}
#else
UNUSED_VARS(eBone, pchan, arm);
if (arm->drawtype == ARM_ENVELOPE) {
/* Edit Mode */
if (eBone) {
bool is_active = (arm->act_edbone == eBone);
if (eBone->flag & BONE_SELECTED) {
if (is_active) {
return g_theme.edge_select_color;
}
else {
return g_theme.bone_select_color;
}
}
}
else if (arm->flag & ARM_POSEMODE) {
bool is_active = (arm->act_bone == pchan->bone);
if (pchan->bone->flag & BONE_SELECTED) {
if (is_active) {
return g_theme.bone_pose_active_color;
}
else {
return g_theme.bone_pose_color;
}
}
}
}
#endif
if (arm->flag & ARM_POSEMODE) {
@@ -895,18 +932,27 @@ static void draw_points(
const float *col_wire_tail = (g_theme.const_color) ? g_theme.const_color : g_theme.vertex_color;
const bool is_envelope_draw = (arm->drawtype == ARM_ENVELOPE);
static const float envelope_ignore = -1.0f;
/* Edit bone points can be selected */
if (eBone) {
if (eBone->flag & BONE_ROOTSEL) {
#ifdef USE_SOLID_COLOR
col_solid_root = g_theme.vertex_select_color;
#else
if (is_envelope_draw) {
col_solid_root = g_theme.vertex_select_color;
}
#endif
col_wire_root = g_theme.vertex_select_color;
}
if (eBone->flag & BONE_TIPSEL) {
#ifdef USE_SOLID_COLOR
col_solid_tail = g_theme.vertex_select_color;
#else
if (is_envelope_draw) {
col_solid_tail = g_theme.vertex_select_color;
}
#endif
col_wire_tail = g_theme.vertex_select_color;
}
@@ -925,6 +971,8 @@ static void draw_points(
if (eBone) {
if (!((eBone->parent) && !EBONE_VISIBLE(arm, eBone->parent))) {
if (is_envelope_draw) {
DRW_shgroup_bone_envelope_solid(eBone->disp_mat, col_solid_root,
&eBone->rad_head, &envelope_ignore);
DRW_shgroup_bone_envelope_head_wire(eBone->disp_mat, col_wire_root,
&eBone->rad_head, &eBone->rad_tail, &eBone->dist);
}
@@ -938,6 +986,8 @@ static void draw_points(
Bone *bone = pchan->bone;
if (!((bone->parent) && (bone->parent->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG)))) {
if (is_envelope_draw) {
DRW_shgroup_bone_envelope_solid(pchan->disp_mat, col_solid_root,
&bone->rad_head, &envelope_ignore);
DRW_shgroup_bone_envelope_head_wire(pchan->disp_mat, col_wire_root,
&bone->rad_head, &bone->rad_tail, &bone->dist);
}
@@ -964,6 +1014,8 @@ static void draw_points(
rad_tail = &pchan->bone->rad_tail;
dist = &pchan->bone->dist;
}
DRW_shgroup_bone_envelope_solid(
BONE_VAR(eBone, pchan, disp_mat), col_solid_tail, &envelope_ignore, rad_tail);
DRW_shgroup_bone_envelope_head_wire(
BONE_VAR(eBone, pchan, disp_tail_mat), col_wire_tail, rad_tail, rad_tail, dist);
}
@@ -1011,7 +1063,7 @@ static void draw_bone_envelope(
const int boneflag, const short constflag,
const int select_id)
{
// const float *col_solid = get_bone_solid_color(eBone, pchan, arm, boneflag, constflag);
const float *col_solid = get_bone_solid_color(eBone, pchan, arm, boneflag, constflag);
const float *col_wire = get_bone_wire_color(eBone, pchan, arm, boneflag, constflag);
static const float col_white[4] = {1.0f, 1.0f, 1.0f, 0.2f};
@@ -1038,6 +1090,7 @@ static void draw_bone_envelope(
DRW_select_load_id(select_id | BONESEL_BONE);
}
DRW_shgroup_bone_envelope_solid(BONE_VAR(eBone, pchan, disp_mat), col_solid, rad_head, rad_tail);
DRW_shgroup_bone_envelope_wire(BONE_VAR(eBone, pchan, disp_mat), col_wire, rad_head, rad_tail, distance);
if (select_id != -1) {

View File

@@ -70,6 +70,7 @@ static struct DRWShapeCache {
Batch *drw_bone_box;
Batch *drw_bone_box_wire;
Batch *drw_bone_wire_wire;
Batch *drw_bone_envelope;
Batch *drw_bone_envelope_distance;
Batch *drw_bone_envelope_wire;
Batch *drw_bone_envelope_head_wire;
@@ -113,6 +114,7 @@ void DRW_shape_cache_free(void)
BATCH_DISCARD_ALL_SAFE(SHC.drw_bone_box);
BATCH_DISCARD_ALL_SAFE(SHC.drw_bone_box_wire);
BATCH_DISCARD_ALL_SAFE(SHC.drw_bone_wire_wire);
BATCH_DISCARD_ALL_SAFE(SHC.drw_bone_envelope);
BATCH_DISCARD_ALL_SAFE(SHC.drw_bone_envelope_distance);
BATCH_DISCARD_ALL_SAFE(SHC.drw_bone_envelope_wire);
BATCH_DISCARD_ALL_SAFE(SHC.drw_bone_envelope_head_wire);
@@ -1530,9 +1532,101 @@ Batch *DRW_cache_bone_wire_wire_outline_get(void)
}
/* Helpers for envelope bone's solid sphere-with-hidden-equatorial-cylinder.
* Note that here we only encode head/tail in forth component of the vector. */
static void benv_lat_lon_to_co(const float lat, const float lon, float r_nor[3])
{
/* Poles are along Y axis. */
r_nor[0] = sinf(lat) * cosf(lon);
r_nor[1] = cosf(lat);
r_nor[2] = sinf(lat) * sinf(lon);
}
static void benv_add_tri(VertexBuffer *vbo, uint pos_id, uint *v_idx, float *co1, float *co2, float *co3)
{
/* Given tri and its seven other mirrors along X/Y/Z axes. */
for (int x = -1; x <= 1; x += 2) {
for (int y = -1; y <= 1; y += 2) {
const float head_tail = (y == -1) ? 0.0f : 1.0f;
for (int z = -1; z <= 1; z += 2) {
VertexBuffer_set_attrib(vbo, pos_id, (*v_idx)++,
(const float[4]){co1[0] * x, co1[1] * y, co1[2] * z, head_tail});
VertexBuffer_set_attrib(vbo, pos_id, (*v_idx)++,
(const float[4]){co2[0] * x, co2[1] * y, co2[2] * z, head_tail});
VertexBuffer_set_attrib(vbo, pos_id, (*v_idx)++,
(const float[4]){co3[0] * x, co3[1] * y, co3[2] * z, head_tail});
}
}
}
}
Batch *DRW_cache_bone_envelope_get(void)
{
#define CIRCLE_RESOL 32 /* Must be multiple of 4 */
if (!SHC.drw_bone_envelope) {
const int lon_res = CIRCLE_RESOL / 4;
const int lat_res = CIRCLE_RESOL / 4;
const float lon_inc = M_PI_2 / lon_res;
const float lat_inc = M_PI_2 / lat_res;
unsigned int v_idx = 0;
static VertexFormat format = { 0 };
static struct { uint pos; } attr_id;
if (format.attrib_ct == 0) {
attr_id.pos = VertexFormat_add_attrib(&format, "pos", COMP_F32, 4, KEEP_FLOAT);
}
/* Vertices */
VertexBuffer *vbo = VertexBuffer_create_with_format(&format);
VertexBuffer_allocate_data(vbo, lat_res * lon_res * 8 * 6);
float lon = 0.0f;
for (int i = 0; i < lon_res; i++, lon += lon_inc) {
float lat = 0.0f;
float co1[3], co2[3], co3[3], co4[3];
for (int j = 0; j < lat_res; j++, lat += lat_inc) {
benv_lat_lon_to_co(lat , lon , co1);
benv_lat_lon_to_co(lat , lon + lon_inc, co2);
benv_lat_lon_to_co(lat + lat_inc, lon + lon_inc, co3);
benv_lat_lon_to_co(lat + lat_inc, lon , co4);
if (j != 0) { /* At pole, n1 and n2 are identical. */
benv_add_tri(vbo, attr_id.pos, &v_idx, co1, co2, co3);
}
benv_add_tri(vbo, attr_id.pos, &v_idx, co1, co3, co4);
}
/* lat is at equator (i.e. lat == pi / 2). */
/* We need to add 'cylinder' part between the equators (along XZ plane). */
for (int x = -1; x <= 1; x += 2) {
for (int z = -1; z <= 1; z += 2) {
VertexBuffer_set_attrib(vbo, attr_id.pos, v_idx++,
(const float[4]){co3[0] * x, co3[1], co3[2] * z, 0.0f});
VertexBuffer_set_attrib(vbo, attr_id.pos, v_idx++,
(const float[4]){co4[0] * x, co4[1], co4[2] * z, 0.0f});
VertexBuffer_set_attrib(vbo, attr_id.pos, v_idx++,
(const float[4]){co4[0] * x, co4[1], co4[2] * z, 1.0f});
VertexBuffer_set_attrib(vbo, attr_id.pos, v_idx++,
(const float[4]){co3[0] * x, co3[1], co3[2] * z, 0.0f});
VertexBuffer_set_attrib(vbo, attr_id.pos, v_idx++,
(const float[4]){co4[0] * x, co4[1], co4[2] * z, 1.0f});
VertexBuffer_set_attrib(vbo, attr_id.pos, v_idx++,
(const float[4]){co3[0] * x, co3[1], co3[2] * z, 1.0f});
}
}
}
SHC.drw_bone_envelope = Batch_create(PRIM_TRIANGLES, vbo, NULL);
}
return SHC.drw_bone_envelope;
}
Batch *DRW_cache_bone_envelope_distance_outline_get(void)
{
#define CIRCLE_RESOL 32
#define CIRCLE_RESOL 32 /* Must be multiple of 2 */
if (!SHC.drw_bone_envelope_distance) {
unsigned int v_idx = 0;
@@ -1570,7 +1664,7 @@ Batch *DRW_cache_bone_envelope_distance_outline_get(void)
}
/* Bone body and tail. */
/* Bone body. */
Batch *DRW_cache_bone_envelope_wire_outline_get(void)
{
if (!SHC.drw_bone_envelope_wire) {
@@ -1600,10 +1694,10 @@ Batch *DRW_cache_bone_envelope_wire_outline_get(void)
}
/* Bone head. */
/* Bone head and tail. */
Batch *DRW_cache_bone_envelope_head_wire_outline_get(void)
{
#define CIRCLE_RESOL 32
#define CIRCLE_RESOL 32 /* Must be multiple of 2 */
if (!SHC.drw_bone_envelope_head_wire) {
unsigned int v_idx = 0;

View File

@@ -82,6 +82,7 @@ struct Batch *DRW_cache_bone_octahedral_wire_outline_get(void);
struct Batch *DRW_cache_bone_box_get(void);
struct Batch *DRW_cache_bone_box_wire_outline_get(void);
struct Batch *DRW_cache_bone_wire_wire_outline_get(void);
struct Batch *DRW_cache_bone_envelope_get(void);
struct Batch *DRW_cache_bone_envelope_distance_outline_get(void);
struct Batch *DRW_cache_bone_envelope_wire_outline_get(void);
struct Batch *DRW_cache_bone_envelope_head_wire_outline_get(void);

View File

@@ -308,6 +308,22 @@ DRWShadingGroup *shgroup_instance_bone_envelope(DRWPass *pass, struct Batch *geo
return grp;
}
DRWShadingGroup *shgroup_instance_bone_envelope_solid(DRWPass *pass, struct Batch *geom, float (*obmat)[4])
{
static float light[3] = {0.0f, 0.0f, 1.0f};
GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_INSTANCE_BONE_ENVELOPE_SOLID);
DRWShadingGroup *grp = DRW_shgroup_instance_create(sh, pass, geom);
DRW_shgroup_attrib_float(grp, "InstanceModelMatrix", 16);
DRW_shgroup_attrib_float(grp, "color", 4);
DRW_shgroup_attrib_float(grp, "radius_head", 1);
DRW_shgroup_attrib_float(grp, "radius_tail", 1);
DRW_shgroup_uniform_mat4(grp, "ObjectModelMatrix", (float *)obmat);
DRW_shgroup_uniform_vec3(grp, "light", light, 1);
return grp;
}
/* ******************************************** COLOR UTILS *********************************************** */

View File

@@ -102,6 +102,7 @@ struct DRWShadingGroup *shgroup_camera_instance(struct DRWPass *pass, struct Bat
struct DRWShadingGroup *shgroup_distance_lines_instance(struct DRWPass *pass, struct Batch *geom);
struct DRWShadingGroup *shgroup_spot_instance(struct DRWPass *pass, struct Batch *geom);
struct DRWShadingGroup *shgroup_instance_bone_envelope(struct DRWPass *pass, struct Batch *geom, float (*obmat)[4]);
struct DRWShadingGroup *shgroup_instance_bone_envelope_solid(struct DRWPass *pass, struct Batch *geom, float (*obmat)[4]);
int DRW_object_wire_theme_get(struct Object *ob, struct SceneLayer *sl, float **r_color);
float *DRW_color_background_blend_get(int theme_id);

View File

@@ -172,6 +172,7 @@ data_to_c_simple(shaders/gpu_shader_instance_distance_line_vert.glsl SRC)
data_to_c_simple(shaders/gpu_shader_instance_edges_variying_color_geom.glsl SRC)
data_to_c_simple(shaders/gpu_shader_instance_edges_variying_color_vert.glsl SRC)
data_to_c_simple(shaders/gpu_shader_instance_bone_envelope_vert.glsl SRC)
data_to_c_simple(shaders/gpu_shader_instance_bone_envelope_solid_vert.glsl SRC)
data_to_c_simple(shaders/gpu_shader_3D_groundline_geom.glsl SRC)
data_to_c_simple(shaders/gpu_shader_3D_groundpoint_vert.glsl SRC)

View File

@@ -169,6 +169,7 @@ typedef enum GPUBuiltinShader {
GPU_SHADER_INSTANCE_EDGES_VARIYING_COLOR,
GPU_SHADER_3D_INSTANCE_BONE_ENVELOPE,
GPU_SHADER_3D_INSTANCE_BONE_ENVELOPE_SOLID,
GPU_NUM_BUILTIN_SHADERS /* (not an actual shader) */
} GPUBuiltinShader;

View File

@@ -93,6 +93,7 @@ extern char datatoc_gpu_shader_instance_distance_line_vert_glsl[];
extern char datatoc_gpu_shader_instance_edges_variying_color_geom_glsl[];
extern char datatoc_gpu_shader_instance_edges_variying_color_vert_glsl[];
extern char datatoc_gpu_shader_instance_bone_envelope_vert_glsl[];
extern char datatoc_gpu_shader_instance_bone_envelope_solid_vert_glsl[];
extern char datatoc_gpu_shader_3D_groundpoint_vert_glsl[];
extern char datatoc_gpu_shader_3D_groundline_geom_glsl[];
@@ -790,6 +791,8 @@ GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader)
[GPU_SHADER_3D_INSTANCE_BONE_ENVELOPE] = { datatoc_gpu_shader_instance_bone_envelope_vert_glsl,
datatoc_gpu_shader_flat_color_frag_glsl },
[GPU_SHADER_3D_INSTANCE_BONE_ENVELOPE_SOLID] = { datatoc_gpu_shader_instance_bone_envelope_solid_vert_glsl,
datatoc_gpu_shader_simple_lighting_frag_glsl },
};
if (builtin_shaders[shader] == NULL) {
@@ -806,6 +809,7 @@ GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader)
defines = "#define AXIS_NAME;\n";
break;
case GPU_SHADER_3D_OBJECTSPACE_SIMPLE_LIGHTING_VARIYING_COLOR:
case GPU_SHADER_3D_INSTANCE_BONE_ENVELOPE_SOLID:
defines = "#define USE_INSTANCE_COLOR;\n";
break;
case GPU_SHADER_3D_FLAT_COLOR_U32:

View File

@@ -0,0 +1,127 @@
/* This shader takes a 2D shape, puts it in 3D Object space such that is stays aligned with view and bone,
* and scales head/tail/distance according to per-instance attributes
* (and 'role' of current vertex, encoded in zw input, head or tail, and inner or outer for distance outline).
* It is used for both the distance outline drawing, and the wire version of envelope bone. */
uniform mat4 ViewMatrix;
uniform mat4 ObjectModelMatrix;
uniform mat4 ViewProjectionMatrix;
/* ---- Instanciated Attribs ---- */
in vec4 pos; /* w encodes head (== 0.0f), tail (== 1.0f) or in-between. */
/* ---- Per instance Attribs ---- */
in mat4 InstanceModelMatrix;
in vec4 color;
in float radius_head;
in float radius_tail;
out vec3 normal;
flat out vec4 finalColor;
void main()
{
// gl_Position = ViewProjectionMatrix * ObjectModelMatrix * InstanceModelMatrix * vec4(pos.xyz, 1.0f);
// normal = pos.xyz;
// finalColor = color;
// return;
/* We get head/tail in object space. */
vec4 head = InstanceModelMatrix * vec4(0.0f, 0.0f, 0.0f, 1.0f);
vec4 tail = InstanceModelMatrix * vec4(0.0f, 1.0f, 0.0f, 1.0f);
/* We need rotation from bone mat, but not scaling. */
mat3 bone_mat = mat3(InstanceModelMatrix);
bone_mat[0] = normalize(bone_mat[0]);
bone_mat[1] = normalize(bone_mat[1]);
bone_mat[2] = normalize(bone_mat[2]);
mat3 nor_mat = transpose(inverse(mat3(ViewMatrix * ObjectModelMatrix) * bone_mat));
/* Where does this comes from???? Don't know why, but is mandatory anyway... :/ */
const float size = 2.0f;
head.xyz *= size;
tail.xyz *= size;
bool head_only = (radius_tail < 0.0f);
bool tail_only = (radius_head < 0.0f);
/* == 0: head; == 1: tail; in-between: along bone. */
float head_fac = head_only ? 0.0f : (tail_only ? 1.0f : pos.w);
vec4 ob_pos;
vec4 ob_bone_origin;
float radius;
/* head */
if (head_fac <= 0.0f) {
if (!head_only) {
/* We are drawing the body itself, need to adjust start/end positions and radius! */
vec3 bone_vec = tail.xyz - head.xyz;
float len = length(bone_vec);
if (len > (radius_head + radius_tail)) {
float fac = (len - radius_head) / len;
radius = fac * radius_head + (1.0f - fac) * radius_tail;
bone_vec /= len;
ob_bone_origin = vec4(head.xyz + bone_vec * radius_head * size, 1.0f);
}
else {
radius = (radius_head + radius_tail) / 2.0f;
ob_bone_origin = (head + tail) / 2.0f;
}
}
else {
radius = radius_head;
ob_bone_origin = head;
}
}
/* tail */
else if (head_fac >= 1.0f) {
if (!tail_only) {
/* We are drawing the body itself, need to adjust start/end positions and radius! */
vec3 bone_vec = tail.xyz - head.xyz;
float len = length(bone_vec);
if (len > (radius_head + radius_tail)) {
float fac = (len - radius_tail) / len;
radius = fac * radius_tail + (1.0f - fac) * radius_head;
bone_vec /= len;
ob_bone_origin = vec4(tail.xyz - bone_vec * radius_tail * size, 1.0f);
}
else {
radius = (radius_head + radius_tail) / 2.0f;
ob_bone_origin = (head + tail) / 2.0f;
}
}
else {
radius = radius_tail;
ob_bone_origin = tail;
}
}
/* Body of the bone */
#if 0 /* Note: not used currently! */
else {
float tail_fac = 1.0f - head_fac;
radius = radius_head * head_fac + radius_tail * tail_fac;
ob_bone_origin = head * head_fac + tail * tail_fac;
}
#endif
/* Yep, since input pos is unit sphere coordinates, it's also our normal. */
vec3 nor = pos.xyz;
ob_pos = pos * radius * size;
ob_pos.xyz = bone_mat * ob_pos.xyz;
ob_pos.w = 1.0f;
gl_Position = ViewProjectionMatrix * ObjectModelMatrix * (ob_pos + ob_bone_origin);
normal = normalize(nor_mat * nor);
finalColor = color;
}