diff options
Diffstat (limited to 'source/blender/draw/modes/shaders')
77 files changed, 4806 insertions, 0 deletions
diff --git a/source/blender/draw/modes/shaders/animviz_mpath_lines_geom.glsl b/source/blender/draw/modes/shaders/animviz_mpath_lines_geom.glsl new file mode 100644 index 00000000000..d9d59880e99 --- /dev/null +++ b/source/blender/draw/modes/shaders/animviz_mpath_lines_geom.glsl @@ -0,0 +1,38 @@ + +layout(lines) in; +layout(triangle_strip, max_vertices = 4) out; + +uniform mat4 ProjectionMatrix; +uniform vec2 viewportSize; +uniform int lineThickness = 2; + +in vec4 finalColor_geom[]; +in vec2 ssPos[]; + +out vec4 finalColor; + +vec2 compute_dir(vec2 v0, vec2 v1) +{ + vec2 dir = normalize(v1 - v0 + 1e-8); + dir = vec2(-dir.y, dir.x); + return dir; +} + +void main(void) +{ + vec2 t; + vec2 edge_dir = compute_dir(ssPos[0], ssPos[1]) / viewportSize; + + bool is_persp = (ProjectionMatrix[3][3] == 0.0); + + finalColor = finalColor_geom[0]; + t = edge_dir * (float(lineThickness) * (is_persp ? gl_in[0].gl_Position.w : 1.0)); + gl_Position = gl_in[0].gl_Position + vec4(t, 0.0, 0.0); EmitVertex(); + gl_Position = gl_in[0].gl_Position - vec4(t, 0.0, 0.0); EmitVertex(); + + finalColor = finalColor_geom[1]; + t = edge_dir * (float(lineThickness) * (is_persp ? gl_in[1].gl_Position.w : 1.0)); + gl_Position = gl_in[1].gl_Position + vec4(t, 0.0, 0.0); EmitVertex(); + gl_Position = gl_in[1].gl_Position - vec4(t, 0.0, 0.0); EmitVertex(); + EndPrimitive(); +} diff --git a/source/blender/draw/modes/shaders/animviz_mpath_lines_vert.glsl b/source/blender/draw/modes/shaders/animviz_mpath_lines_vert.glsl new file mode 100644 index 00000000000..276f4004fb6 --- /dev/null +++ b/source/blender/draw/modes/shaders/animviz_mpath_lines_vert.glsl @@ -0,0 +1,91 @@ + +uniform mat4 ViewMatrix; +uniform mat4 ViewProjectionMatrix; +uniform vec2 viewportSize; + +uniform int frameCurrent; +uniform int frameStart; +uniform int frameEnd; +uniform int cacheStart; +uniform bool selected; +uniform bool useCustomColor; +uniform vec3 customColor; + +in vec3 pos; + +out vec2 ssPos; +out vec4 finalColor_geom; + +/* project to screen space */ +vec2 proj(vec4 pos) +{ + return (0.5 * (pos.xy / pos.w) + 0.5) * viewportSize; +} + +#define SET_INTENSITY(A, B, C, min, max) (((1.0 - (float(C - B) / float(C - A))) * (max - min)) + min) + +void main() +{ + gl_Position = ViewProjectionMatrix * vec4(pos, 1.0); + + ssPos = proj(gl_Position); + + int frame = gl_VertexID + cacheStart; + + float intensity; /* how faint */ + + vec3 blend_base = (abs(frame - frameCurrent) == 1) ? colorCurrentFrame.rgb : colorBackground.rgb; /* "bleed" cframe color to ease color blending */ + + /* TODO: We might want something more consistent with custom color and standard colors. */ + if (frame < frameCurrent) { + if (useCustomColor) { + /* Custom color: previous frames color is darker than current frame */ + finalColor_geom.rgb = customColor * 0.25; + } + else { + /* black - before frameCurrent */ + if (selected) { + intensity = SET_INTENSITY(frameStart, frame, frameCurrent, 0.25, 0.75); + } + else { + intensity = SET_INTENSITY(frameStart, frame, frameCurrent, 0.68, 0.92); + } + finalColor_geom.rgb = mix(colorWire.rgb, blend_base, intensity); + } + } + else if (frame > frameCurrent) { + if (useCustomColor) { + /* Custom color: next frames color is equal to user selected color */ + finalColor_geom.rgb = customColor; + } + else { + /* blue - after frameCurrent */ + if (selected) { + intensity = SET_INTENSITY(frameCurrent, frame, frameEnd, 0.25, 0.75); + } + else { + intensity = SET_INTENSITY(frameCurrent, frame, frameEnd, 0.68, 0.92); + } + + finalColor_geom.rgb = mix(colorBonePose.rgb, blend_base, intensity); + } + } + else { + if (useCustomColor) { + /* Custom color: current frame color is slightly darker than user selected color */ + finalColor_geom.rgb = customColor * 0.5; + } + else { + /* green - on frameCurrent */ + if (selected) { + intensity = 0.5f; + } + else { + intensity = 0.99f; + } + finalColor_geom.rgb = clamp(mix(colorCurrentFrame.rgb, colorBackground.rgb, intensity) - 0.1, 0.0, 0.1); + } + } + + finalColor_geom.a = 1.0; +} diff --git a/source/blender/draw/modes/shaders/animviz_mpath_points_vert.glsl b/source/blender/draw/modes/shaders/animviz_mpath_points_vert.glsl new file mode 100644 index 00000000000..3b2f170ca22 --- /dev/null +++ b/source/blender/draw/modes/shaders/animviz_mpath_points_vert.glsl @@ -0,0 +1,47 @@ + +uniform mat4 ViewProjectionMatrix; + +uniform int pointSize = 2; +uniform int frameCurrent; +uniform int cacheStart; +uniform bool showKeyFrames = true; +uniform bool useCustomColor; +uniform vec3 customColor; + +in vec3 pos; +in int flag; + +#define MOTIONPATH_VERT_SEL (1 << 0) +#define MOTIONPATH_VERT_KEY (1 << 1) + +out vec4 finalColor; + +void main() +{ + gl_Position = ViewProjectionMatrix * vec4(pos, 1.0); + gl_PointSize = float(pointSize + 2); + + int frame = gl_VertexID + cacheStart; + finalColor = (useCustomColor) ? vec4(customColor, 1.0) : vec4(1.0); + + /* Bias to reduce z fighting with the path */ + gl_Position.z -= 1e-4; + + if (showKeyFrames) { + if ((flag & MOTIONPATH_VERT_KEY) != 0) { + gl_PointSize = float(pointSize + 5); + finalColor = colorVertexSelect; + /* Bias more to get these on top of regular points */ + gl_Position.z -= 1e-4; + } + /* Draw big green dot where the current frame is. + * NOTE: this is only done when keyframes are shown, since this adds similar types of clutter + */ + if (frame == frameCurrent) { + gl_PointSize = float(pointSize + 8); + finalColor = colorCurrentFrame; + /* Bias more to get these on top of keyframes */ + gl_Position.z -= 1e-4; + } + } +} diff --git a/source/blender/draw/modes/shaders/armature_axes_vert.glsl b/source/blender/draw/modes/shaders/armature_axes_vert.glsl new file mode 100644 index 00000000000..53b2a3d3b3b --- /dev/null +++ b/source/blender/draw/modes/shaders/armature_axes_vert.glsl @@ -0,0 +1,30 @@ + +uniform mat4 ViewProjectionMatrix; +uniform vec3 screenVecs[3]; + +/* ---- Instantiated Attribs ---- */ +in float axis; /* position on the axis. [0.0-1.0] is X axis, [1.0-2.0] is Y, etc... */ +in vec2 screenPos; +in vec3 colorAxis; + +/* ---- Per instance Attribs ---- */ +in mat4 InstanceModelMatrix; +in vec4 color; + +flat out vec4 finalColor; + +void main() +{ + vec3 chosen_axis = InstanceModelMatrix[int(axis)].xyz; + vec3 y_axis = InstanceModelMatrix[1].xyz; + vec3 bone_loc = InstanceModelMatrix[3].xyz; + vec3 wpos = bone_loc + y_axis + chosen_axis * fract(axis); + vec3 spos = screenVecs[0].xyz * screenPos.x + screenVecs[1].xyz * screenPos.y; + /* Scale uniformly by axis length */ + spos *= length(chosen_axis); + + gl_Position = ViewProjectionMatrix * vec4(wpos + spos, 1.0); + + finalColor.rgb = mix(colorAxis, color.rgb, color.a); + finalColor.a = 1.0; +} diff --git a/source/blender/draw/modes/shaders/armature_dof_vert.glsl b/source/blender/draw/modes/shaders/armature_dof_vert.glsl new file mode 100644 index 00000000000..5c89cf644d6 --- /dev/null +++ b/source/blender/draw/modes/shaders/armature_dof_vert.glsl @@ -0,0 +1,30 @@ + +uniform mat4 ViewProjectionMatrix; + +/* ---- Instantiated Attribs ---- */ +in vec2 pos; + +/* ---- Per instance Attribs ---- */ +/* Assumed to be in world coordinate already. */ +in mat4 InstanceModelMatrix; +in vec4 color; +in vec2 amin; +in vec2 amax; + +flat out vec4 finalColor; + +vec3 sphere_project(float ax, float az) +{ + float sine = 1.0 - ax * ax - az * az; + float q3 = sqrt(max(0.0, sine)); + + return vec3(-az * q3, 0.5 - sine, ax * q3) * 2.0; +} + +void main() +{ + vec3 final_pos = sphere_project(pos.x * abs((pos.x > 0.0) ? amax.x : amin.x), + pos.y * abs((pos.y > 0.0) ? amax.y : amin.y)); + gl_Position = ViewProjectionMatrix * (InstanceModelMatrix * vec4(final_pos, 1.0)); + finalColor = color; +} diff --git a/source/blender/draw/modes/shaders/armature_envelope_distance_frag.glsl b/source/blender/draw/modes/shaders/armature_envelope_distance_frag.glsl new file mode 100644 index 00000000000..cecc5447c7c --- /dev/null +++ b/source/blender/draw/modes/shaders/armature_envelope_distance_frag.glsl @@ -0,0 +1,15 @@ + +flat in vec3 finalStateColor; /* UNUSED */ +flat in vec3 finalBoneColor; /* UNUSED */ +in vec3 normalView; + +out vec4 fragColor; + +uniform vec4 color = vec4(1.0, 1.0, 1.0, 0.2); + +void main() +{ + float n = normalize(normalView).z; + n = 1.0 - clamp(-n, 0.0, 1.0); + fragColor = color * n; +} diff --git a/source/blender/draw/modes/shaders/armature_envelope_outline_vert.glsl b/source/blender/draw/modes/shaders/armature_envelope_outline_vert.glsl new file mode 100644 index 00000000000..307c7276184 --- /dev/null +++ b/source/blender/draw/modes/shaders/armature_envelope_outline_vert.glsl @@ -0,0 +1,156 @@ + +uniform mat4 ViewMatrix; +uniform mat4 ViewMatrixInverse; +uniform mat4 ViewProjectionMatrix; +uniform mat4 ProjectionMatrix; + +uniform vec2 viewportSize; +uniform float lineThickness = 2.0; + +/* ---- Instantiated Attribs ---- */ +in vec2 pos0; +in vec2 pos1; +in vec2 pos2; + +/* ---- Per instance Attribs ---- */ +/* Assumed to be in world coordinate already. */ +in vec4 headSphere; +in vec4 tailSphere; +in vec4 outlineColorSize; +in vec3 xAxis; + +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 v2) +{ + vec2 dir = normalize(v2 - v0); + dir = vec2(dir.y, -dir.x); + return dir; +} + +mat3 compute_mat(vec4 sphere, vec3 bone_vec, out float z_ofs) +{ + bool is_persp = (ProjectionMatrix[3][3] == 0.0); + vec3 cam_ray = (is_persp) ? sphere.xyz - ViewMatrixInverse[3].xyz + : -ViewMatrixInverse[2].xyz; + + /* Sphere center distance from the camera (persp) in world space. */ + float cam_dist = length(cam_ray); + + /* Compute view aligned orthonormal space. */ + vec3 z_axis = cam_ray / cam_dist; + vec3 x_axis = normalize(cross(bone_vec, z_axis)); + vec3 y_axis = cross(z_axis, x_axis); + 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; + float rad = sphere.w; + /* Let be : + * 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; + } + + return mat3(x_axis, y_axis, z_axis); +} + +struct Bone { vec3 vec; float sinb; }; + +bool bone_blend_starts(vec3 p, Bone b) +{ + /* we just want to know when the head sphere starts interpolating. */ + return dot(p, b.vec) > -b.sinb; +} + +vec3 get_outline_point( + vec2 pos, vec4 sph_near, vec4 sph_far, + mat3 mat_near, mat3 mat_far, float z_ofs_near, float z_ofs_far, Bone b) +{ + /* Compute outline position on the nearest sphere and check + * if it penetrates the capsule body. If it does, put this + * vertex on the farthest sphere. */ + vec3 wpos = mat_near * vec3(pos * sph_near.w, z_ofs_near); + if (bone_blend_starts(wpos, b)) { + wpos = sph_far.xyz + mat_far * vec3(pos * sph_far.w, z_ofs_far); + } + else { + wpos += sph_near.xyz; + } + return wpos; +} + +void main() +{ + float dst_head = distance(headSphere.xyz, ViewMatrixInverse[3].xyz); + float dst_tail = distance(tailSphere.xyz, ViewMatrixInverse[3].xyz); + // float dst_head = -dot(headSphere.xyz, ViewMatrix[2].xyz); + // float dst_tail = -dot(tailSphere.xyz, ViewMatrix[2].xyz); + + vec4 sph_near, sph_far; + if ((dst_head > dst_tail) && (ProjectionMatrix[3][3] == 0.0)) { + sph_near = tailSphere; + sph_far = headSphere; + } + else { + sph_near = headSphere; + sph_far = tailSphere; + } + + vec3 bone_vec = (sph_far.xyz - sph_near.xyz) + 1e-8; + + Bone b; + float bone_lenrcp = 1.0 / max(1e-8, sqrt(dot(bone_vec, bone_vec))); + b.sinb = (sph_far.w - sph_near.w) * bone_lenrcp * sph_near.w; + b.vec = bone_vec * bone_lenrcp; + + float z_ofs_near, z_ofs_far; + mat3 mat_near = compute_mat(sph_near, bone_vec, z_ofs_near); + mat3 mat_far = compute_mat(sph_far, bone_vec, z_ofs_far); + + vec3 wpos0 = get_outline_point(pos0, sph_near, sph_far, mat_near, mat_far, z_ofs_near, z_ofs_far, b); + vec3 wpos1 = get_outline_point(pos1, sph_near, sph_far, mat_near, mat_far, z_ofs_near, z_ofs_far, b); + vec3 wpos2 = get_outline_point(pos2, sph_near, sph_far, mat_near, mat_far, z_ofs_near, z_ofs_far, b); + + vec4 V = ViewMatrix * vec4(wpos1, 1.0); + float pres_fac = (ProjectionMatrix[3][3] == 0.0) ? abs(V.z) : 1.0; + + vec4 p0 = ViewProjectionMatrix * vec4(wpos0, 1.0); + vec4 p1 = ProjectionMatrix * V; + vec4 p2 = ViewProjectionMatrix * vec4(wpos2, 1.0); + + /* compute position from 3 vertex because the change in direction + * can happen very quicky and lead to very thin edges. */ + vec2 ss0 = proj(p0); + vec2 ss1 = proj(p1); + vec2 ss2 = proj(p2); + vec2 edge_dir = compute_dir(ss0, ss1, ss2); + + bool outer = ((gl_VertexID & 1) == 1); + vec2 t = outlineColorSize.w * (lineThickness / viewportSize); + t *= pres_fac; + t = (outer) ? t : vec2(0.0); + + gl_Position = p1; + gl_Position.xy += t * edge_dir; + + finalColor = vec4(outlineColorSize.rgb, 1.0); +} diff --git a/source/blender/draw/modes/shaders/armature_envelope_solid_frag.glsl b/source/blender/draw/modes/shaders/armature_envelope_solid_frag.glsl new file mode 100644 index 00000000000..78b29296601 --- /dev/null +++ b/source/blender/draw/modes/shaders/armature_envelope_solid_frag.glsl @@ -0,0 +1,18 @@ + +uniform float alpha = 0.6; + +flat in vec3 finalStateColor; +flat in vec3 finalBoneColor; +in vec3 normalView; + +out vec4 fragColor; + +void main() +{ + /* Smooth lighting factor. */ + const float s = 0.2; /* [0.0-0.5] range */ + float n = normalize(normalView).z; + float fac = clamp((n * (1.0 - s)) + s, 0.0, 1.0); + fragColor.rgb = mix(finalStateColor, finalBoneColor, fac); + fragColor.a = alpha; +} diff --git a/source/blender/draw/modes/shaders/armature_envelope_solid_vert.glsl b/source/blender/draw/modes/shaders/armature_envelope_solid_vert.glsl new file mode 100644 index 00000000000..11935e9001f --- /dev/null +++ b/source/blender/draw/modes/shaders/armature_envelope_solid_vert.glsl @@ -0,0 +1,55 @@ + +uniform mat4 ViewMatrix; +uniform mat4 ViewMatrixInverse; +uniform mat4 ViewProjectionMatrix; + +/* ---- Instantiated Attribs ---- */ +in vec3 pos; + +/* ---- Per instance Attribs ---- */ +/* Assumed to be in world coordinate already. */ +in vec4 headSphere; +in vec4 tailSphere; +in vec3 xAxis; +in vec3 stateColor; +in vec3 boneColor; + +flat out vec3 finalStateColor; +flat out vec3 finalBoneColor; +out vec3 normalView; + +void main() +{ + vec3 bone_vec = tailSphere.xyz - headSphere.xyz; + float bone_len = max(1e-8, sqrt(dot(bone_vec, bone_vec))); + float bone_lenrcp = 1.0 / bone_len; +#ifdef SMOOTH_ENVELOPE + float sinb = (tailSphere.w - headSphere.w) * bone_lenrcp; +#else + const float sinb = 0.0; +#endif + + vec3 y_axis = bone_vec * bone_lenrcp; + vec3 z_axis = normalize(cross(xAxis, -y_axis)); + vec3 x_axis = cross(y_axis, z_axis); /* cannot trust xAxis to be orthogonal. */ + + vec3 sp, nor; + nor = sp = pos.xyz; + + /* In bone space */ + bool is_head = (pos.z < -sinb); + sp *= (is_head) ? headSphere.w : tailSphere.w; + sp.z += (is_head) ? 0.0 : bone_len; + + /* Convert to world space */ + mat3 bone_mat = mat3(x_axis, y_axis, z_axis); + sp = bone_mat * sp.xzy + headSphere.xyz; + nor = bone_mat * nor.xzy; + + normalView = mat3(ViewMatrix) * nor; + + gl_Position = ViewProjectionMatrix * vec4(sp, 1.0); + + finalStateColor = stateColor; + finalBoneColor = boneColor; +} diff --git a/source/blender/draw/modes/shaders/armature_shape_outline_geom.glsl b/source/blender/draw/modes/shaders/armature_shape_outline_geom.glsl new file mode 100644 index 00000000000..bcfa097b277 --- /dev/null +++ b/source/blender/draw/modes/shaders/armature_shape_outline_geom.glsl @@ -0,0 +1,101 @@ + +layout(lines_adjacency) in; +layout(triangle_strip, max_vertices = 6) out; + +in vec4 pPos[]; +in vec3 vPos[]; +in vec2 ssPos[]; +in vec2 ssNor[]; +in vec4 vColSize[]; + +flat out vec4 finalColor; +uniform mat4 ProjectionMatrix; +uniform vec2 viewportSize; +uniform float lineThickness = 2.0; + +vec2 compute_dir(vec2 v0, vec2 v1) +{ + vec2 dir = normalize(v1 - v0); + dir = vec2(-dir.y, dir.x); + return dir; +} + +void emit_edge(vec2 edge_dir, vec2 hidden_dir, vec2 thick, bool is_persp) +{ + float fac = dot(-hidden_dir, edge_dir); + edge_dir *= (fac < 0.0) ? -1.0 : 1.0; + + vec2 t = thick * (is_persp ? abs(vPos[1].z) : 1.0); + gl_Position = pPos[1]; + EmitVertex(); + gl_Position.xy += t * edge_dir; + EmitVertex(); + + t = thick * (is_persp ? abs(vPos[2].z) : 1.0); + gl_Position = pPos[2]; + EmitVertex(); + gl_Position.xy += t * edge_dir; + EmitVertex(); +} + +void emit_corner(const int e, vec2 thick, bool is_persp) +{ + vec2 corner_dir = ssNor[e]; + vec2 t = thick * (is_persp ? abs(vPos[e].z) : 1.0); + + gl_Position = pPos[e] + vec4(t * corner_dir, 0.0, 0.0); + EmitVertex(); +} + +void main(void) +{ + finalColor = vec4(vColSize[0].rgb, 1.0); + + bool is_persp = (ProjectionMatrix[3][3] == 0.0); + + vec3 view_vec = (is_persp) ? normalize(vPos[1]) : vec3(0.0, 0.0, -1.0); + vec3 v10 = vPos[0] - vPos[1]; + vec3 v12 = vPos[2] - vPos[1]; + vec3 v13 = vPos[3] - vPos[1]; + + vec3 n0 = cross(v12, v10); + vec3 n3 = cross(v13, v12); + + float fac0 = dot(view_vec, n0); + float fac3 = dot(view_vec, n3); + + /* If one of the face is perpendicular to the view, + * consider it and outline edge. */ + if (abs(fac0) > 1e-5 && abs(fac3) > 1e-5) { + /* If both adjacent verts are facing the camera the same way, + * then it isn't an outline edge. */ + if (sign(fac0) == sign(fac3)) + return; + } + + /* Don't outline if concave edge. */ + if (dot(n0, v13) > 0.0001) + return; + + vec2 thick = vColSize[0].w * (lineThickness / viewportSize); + vec2 edge_dir = compute_dir(ssPos[1], ssPos[2]); + + vec2 hidden_point; + /* Take the farthest point to compute edge direction + * (avoid problems with point behind near plane). + * If the chosen point is parallel to the edge in screen space, + * choose the other point anyway. + * This fixes some issue with cubes in orthographic views.*/ + if (vPos[0].z < vPos[3].z) { + hidden_point = (abs(fac0) > 1e-5) ? ssPos[0] : ssPos[3]; + } + else { + hidden_point = (abs(fac3) > 1e-5) ? ssPos[3] : ssPos[0]; + } + vec2 hidden_dir = normalize(hidden_point - ssPos[1]); + + emit_corner(1, thick, is_persp); + emit_edge(edge_dir, hidden_dir, thick, is_persp); + emit_corner(2, thick, is_persp); + EndPrimitive(); +} diff --git a/source/blender/draw/modes/shaders/armature_shape_outline_vert.glsl b/source/blender/draw/modes/shaders/armature_shape_outline_vert.glsl new file mode 100644 index 00000000000..7619d8018f9 --- /dev/null +++ b/source/blender/draw/modes/shaders/armature_shape_outline_vert.glsl @@ -0,0 +1,47 @@ + +uniform mat3 NormalMatrix; + +uniform mat4 ViewMatrix; +uniform mat4 ProjectionMatrix; +uniform vec2 viewportSize; + +/* ---- Instantiated Attribs ---- */ +in vec3 pos; +in vec3 snor; + +/* ---- Per instance Attribs ---- */ +in mat4 InstanceModelMatrix; +in vec4 outlineColorSize; + +out vec4 pPos; +out vec3 vPos; +out vec2 ssPos; +out vec2 ssNor; +out vec4 vColSize; + +/* project to screen space */ +vec2 proj(vec4 pos) +{ + return (0.5 * (pos.xy / pos.w) + 0.5) * viewportSize; +} + +void main() +{ + /* This is slow and run per vertex, but it's still faster than + * doing it per instance on CPU and sending it on via instance attrib */ + mat3 NormalMatrix = transpose(inverse(mat3(ViewMatrix * InstanceModelMatrix))); + + vec4 viewpos = ViewMatrix * (InstanceModelMatrix * vec4(pos, 1.0)); + + vPos = viewpos.xyz; + pPos = ProjectionMatrix * viewpos; + + /* TODO FIX: there is still a problem with this vector + * when the bone is scaled or in persp mode. But it's + * barelly visible at the outline corners. */ + ssNor = normalize((NormalMatrix * snor).xy); + + ssPos = proj(pPos); + + vColSize = outlineColorSize; +} diff --git a/source/blender/draw/modes/shaders/armature_shape_solid_frag.glsl b/source/blender/draw/modes/shaders/armature_shape_solid_frag.glsl new file mode 100644 index 00000000000..45748bf5644 --- /dev/null +++ b/source/blender/draw/modes/shaders/armature_shape_solid_frag.glsl @@ -0,0 +1,11 @@ + +uniform float alpha = 0.6; + +in vec4 finalColor; + +out vec4 fragColor; + +void main() +{ + fragColor = vec4(finalColor.rgb, alpha); +} diff --git a/source/blender/draw/modes/shaders/armature_shape_solid_vert.glsl b/source/blender/draw/modes/shaders/armature_shape_solid_vert.glsl new file mode 100644 index 00000000000..7abbf7f3d25 --- /dev/null +++ b/source/blender/draw/modes/shaders/armature_shape_solid_vert.glsl @@ -0,0 +1,36 @@ + +uniform mat3 NormalMatrix; +uniform mat4 ViewMatrixInverse; +uniform mat4 ViewProjectionMatrix; + +uniform mat4 ViewMatrix; +uniform mat4 ProjectionMatrix; + +/* ---- Instantiated Attribs ---- */ +in vec3 pos; +in vec3 nor; + +/* ---- Per instance Attribs ---- */ +in mat4 InstanceModelMatrix; +in vec3 boneColor; +in vec3 stateColor; + +out vec4 finalColor; + +void main() +{ + mat3 NormalMatrix = transpose(inverse(mat3(ViewMatrix * InstanceModelMatrix))); + vec3 normal = normalize(NormalMatrix * nor); + + /* Do lighting at an angle to avoid flat shading on front facing bone. */ + const vec3 light = vec3(0.1, 0.1, 0.8); + float n = dot(normal, light); + + /* Smooth lighting factor. */ + const float s = 0.2; /* [0.0-0.5] range */ + float fac = clamp((n * (1.0 - s)) + s, 0.0, 1.0); + finalColor.rgb = mix(stateColor, boneColor, fac); + finalColor.a = 1.0; + + gl_Position = ViewProjectionMatrix * (InstanceModelMatrix * vec4(pos, 1.0)); +} 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..0c1fefbf814 --- /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 = 2.0; + +/* ---- Instantiated Attribs ---- */ +in vec2 pos0; +in vec2 pos1; + +/* ---- Per instance Attribs ---- */ +in mat4 InstanceModelMatrix; +in vec4 outlineColorSize; + +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 = outlineColorSize.w * (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 = vec4(outlineColorSize.rgb, 1.0); +} diff --git a/source/blender/draw/modes/shaders/armature_sphere_solid_frag.glsl b/source/blender/draw/modes/shaders/armature_sphere_solid_frag.glsl new file mode 100644 index 00000000000..a0fdd55931f --- /dev/null +++ b/source/blender/draw/modes/shaders/armature_sphere_solid_frag.glsl @@ -0,0 +1,81 @@ + +#extension GL_ARB_conservative_depth : enable + +uniform mat4 ViewMatrixInverse; +uniform mat4 ProjectionMatrix; +uniform float alpha = 0.4; + +flat in vec3 finalStateColor; +flat in vec3 finalBoneColor; +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. */ + + + /* Smooth lighting factor. */ + const float s = 0.2; /* [0.0-0.5] range */ + float fac = clamp((dot(n, l) * (1.0 - s)) + s, 0.0, 1.0); + fragColor.rgb = mix(finalStateColor, finalBoneColor, fac); + + /* 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(fragColor.rgb + dither, alpha); + + 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_solid_vert.glsl b/source/blender/draw/modes/shaders/armature_sphere_solid_vert.glsl new file mode 100644 index 00000000000..7cbc0c5bc3a --- /dev/null +++ b/source/blender/draw/modes/shaders/armature_sphere_solid_vert.glsl @@ -0,0 +1,82 @@ + +uniform mat4 ViewMatrix; +uniform mat4 ProjectionMatrix; + +/* ---- Instantiated Attribs ---- */ +in vec2 pos; + +/* ---- Per instance Attribs ---- */ +in mat4 InstanceModelMatrix; +in vec3 stateColor; +in vec3 boneColor; + +flat out vec3 finalStateColor; +flat out vec3 finalBoneColor; +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; + + finalStateColor = stateColor; + finalBoneColor = boneColor; +} diff --git a/source/blender/draw/modes/shaders/armature_stick_frag.glsl b/source/blender/draw/modes/shaders/armature_stick_frag.glsl new file mode 100644 index 00000000000..d03cf4c0366 --- /dev/null +++ b/source/blender/draw/modes/shaders/armature_stick_frag.glsl @@ -0,0 +1,13 @@ + +noperspective in float colorFac; +flat in vec4 finalWireColor; +flat in vec4 finalInnerColor; + +out vec4 fragColor; + +void main() +{ + float fac = smoothstep(1.0, 0.2, colorFac); + fragColor.rgb = mix(finalInnerColor.rgb, finalWireColor.rgb, fac); + fragColor.a = 1.0; +} diff --git a/source/blender/draw/modes/shaders/armature_stick_vert.glsl b/source/blender/draw/modes/shaders/armature_stick_vert.glsl new file mode 100644 index 00000000000..58fc48e608e --- /dev/null +++ b/source/blender/draw/modes/shaders/armature_stick_vert.glsl @@ -0,0 +1,88 @@ + +uniform mat4 ProjectionMatrix; +uniform mat4 ViewProjectionMatrix; +uniform mat4 ViewMatrix; +uniform vec2 viewportSize; + +/* ---- Instantiated Attribs ---- */ +in vec2 pos; /* bone aligned screen space */ +in uint flag; + +#define COL_WIRE 1u /* (1 << 0) */ +#define COL_HEAD 2u /* (1 << 1) */ +#define COL_TAIL 4u /* (1 << 2) */ +#define COL_BONE 8u /* (1 << 3) */ + +#define POS_HEAD 16u /* (1 << 4) */ +#define POS_TAIL 32u /* (1 << 5) */ /* UNUSED */ +#define POS_BONE 64u /* (1 << 6) */ + +/* ---- Per instance Attribs ---- */ +in vec3 boneStart; +in vec3 boneEnd; +in vec4 wireColor; /* alpha encode if we do wire. If 0.0 we dont. */ +in vec4 boneColor; /* alpha encode if we do bone. If 0.0 we dont. */ +in vec4 headColor; /* alpha encode if we do head. If 0.0 we dont. */ +in vec4 tailColor; /* alpha encode if we do tail. If 0.0 we dont. */ + +#define do_wire (wireColor.a > 0.0) +#define is_head bool(flag & POS_HEAD) +#define is_bone bool(flag & POS_BONE) + +noperspective out float colorFac; +flat out vec4 finalWireColor; +flat out vec4 finalInnerColor; + +uniform float stickSize = 5.0; /* might be dependent on DPI setting in the future. */ + +/* project to screen space */ +vec2 proj(vec4 pos) +{ + return (0.5 * (pos.xy / pos.w) + 0.5) * viewportSize; +} + +void main() +{ + finalInnerColor = ((flag & COL_HEAD) != 0u) ? headColor : tailColor; + finalInnerColor = ((flag & COL_BONE) != 0u) ? boneColor : finalInnerColor; + finalWireColor = (do_wire) ? wireColor : finalInnerColor; + /* Make the color */ + colorFac = ((flag & COL_WIRE) == 0u) ? ((flag & COL_BONE) != 0u) ? 1.0 : 2.0 : 0.0; + + vec4 v0 = ViewMatrix * vec4(boneStart, 1.0); + vec4 v1 = ViewMatrix * vec4(boneEnd, 1.0); + + /* Clip the bone to the camera origin plane (not the clip plane) + * to avoid glitches if one end is behind the camera origin (in persp). */ + float clip_dist = (ProjectionMatrix[3][3] == 0.0) ? -1e-7 : 1e20; /* hardcoded, -1e-8 is giving gliches. */ + vec3 bvec = v1.xyz - v0.xyz; + vec3 clip_pt = v0.xyz + bvec * ((v0.z - clip_dist) / -bvec.z); + if (v0.z > clip_dist) { + v0.xyz = clip_pt; + } + else if (v1.z > clip_dist) { + v1.xyz = clip_pt; + } + + vec4 p0 = ProjectionMatrix * v0; + vec4 p1 = ProjectionMatrix * v1; + + float h = (is_head) ? p0.w : p1.w; + + vec2 x_screen_vec = normalize(proj(p1) - proj(p0) + 1e-8); + vec2 y_screen_vec = vec2(x_screen_vec.y, -x_screen_vec.x); + + /* 2D screen aligned pos at the point */ + vec2 vpos = pos.x * x_screen_vec + pos.y * y_screen_vec; + vpos *= (ProjectionMatrix[3][3] == 0.0) ? h : 1.0; + vpos *= (do_wire) ? 1.0 : 0.5; + + if (finalInnerColor.a > 0.0) { + gl_Position = (is_head) ? p0 : p1; + gl_Position.xy += stickSize * (vpos / viewportSize); + gl_Position.z += (is_bone) ? 0.0 : 1e-6; /* Avoid Z fighting of head/tails. */ + } + else { + gl_Position = vec4(0.0); + } +} diff --git a/source/blender/draw/modes/shaders/common_fullscreen_vert.glsl b/source/blender/draw/modes/shaders/common_fullscreen_vert.glsl new file mode 100644 index 00000000000..fc5cc1cdcc3 --- /dev/null +++ b/source/blender/draw/modes/shaders/common_fullscreen_vert.glsl @@ -0,0 +1,10 @@ + +in vec2 pos; +in vec2 uvs; +out vec4 uvcoordsvar; + +void main() +{ + uvcoordsvar = vec4(uvs, 0.0, 0.0); + gl_Position = vec4(pos, 0.0, 1.0); +} diff --git a/source/blender/draw/modes/shaders/common_fxaa_lib.glsl b/source/blender/draw/modes/shaders/common_fxaa_lib.glsl new file mode 100644 index 00000000000..236ac5c67f0 --- /dev/null +++ b/source/blender/draw/modes/shaders/common_fxaa_lib.glsl @@ -0,0 +1,677 @@ +//---------------------------------------------------------------------------------- +// File: es3-kepler\FXAA/FXAA3_11.h +// SDK Version: v3.00 +// Email: gameworks@nvidia.com +// Site: http://developer.nvidia.com/ +// +// Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of NVIDIA CORPORATION nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +//---------------------------------------------------------------------------------- + +/* BLENDER MODIFICATIONS: + * + * - (#B1#) Compute luma on the fly using BT. 709 luma function + * - (#B2#) main function instead of #include, due to lack of + * ARB_shading_language_include in 3.3 + * - (#B3#) version and extension directives + * - removed "FXAA Console" algorithm support and shader parameters + * - removed HLSL support shims + * - (#B4#) change luma sampling to compute, not use A channel + * (this also removes GATHER4_ALPHA support) + * - removed all the console shaders (only remaining algorithm is "FXAA PC + * Quality") + * + * Note that this file doesn't follow the coding style guidelines. + */ + +/*============================================================================ + FXAA QUALITY - TUNING KNOBS +------------------------------------------------------------------------------ +NOTE the other tuning knobs are now in the shader function inputs! +============================================================================*/ +#ifndef FXAA_QUALITY__PRESET + // + // Choose the quality preset. + // This needs to be compiled into the shader as it effects code. + // Best option to include multiple presets is to + // in each shader define the preset, then include this file. + // + // OPTIONS + // ----------------------------------------------------------------------- + // 10 to 15 - default medium dither (10=fastest, 15=highest quality) + // 20 to 29 - less dither, more expensive (20=fastest, 29=highest quality) + // 39 - no dither, very expensive + // + // NOTES + // ----------------------------------------------------------------------- + // 12 = slightly faster then FXAA 3.9 and higher edge quality (default) + // 13 = about same speed as FXAA 3.9 and better than 12 + // 23 = closest to FXAA 3.9 visually and performance wise + // _ = the lowest digit is directly related to performance + // _ = the highest digit is directly related to style + // + #define FXAA_QUALITY__PRESET 12 +#endif + +/*============================================================================ + + FXAA QUALITY - PRESETS + +============================================================================*/ + +/*============================================================================ + FXAA QUALITY - MEDIUM DITHER PRESETS +============================================================================*/ +#if (FXAA_QUALITY__PRESET == 10) + #define FXAA_QUALITY__PS 3 + #define FXAA_QUALITY__P0 1.5 + #define FXAA_QUALITY__P1 3.0 + #define FXAA_QUALITY__P2 12.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 11) + #define FXAA_QUALITY__PS 4 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 3.0 + #define FXAA_QUALITY__P3 12.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 12) + #define FXAA_QUALITY__PS 5 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 4.0 + #define FXAA_QUALITY__P4 12.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 13) + #define FXAA_QUALITY__PS 6 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 4.0 + #define FXAA_QUALITY__P5 12.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 14) + #define FXAA_QUALITY__PS 7 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 4.0 + #define FXAA_QUALITY__P6 12.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 15) + #define FXAA_QUALITY__PS 8 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 2.0 + #define FXAA_QUALITY__P6 4.0 + #define FXAA_QUALITY__P7 12.0 +#endif + +/*============================================================================ + FXAA QUALITY - LOW DITHER PRESETS +============================================================================*/ +#if (FXAA_QUALITY__PRESET == 20) + #define FXAA_QUALITY__PS 3 + #define FXAA_QUALITY__P0 1.5 + #define FXAA_QUALITY__P1 2.0 + #define FXAA_QUALITY__P2 8.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 21) + #define FXAA_QUALITY__PS 4 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 8.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 22) + #define FXAA_QUALITY__PS 5 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 8.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 23) + #define FXAA_QUALITY__PS 6 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 8.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 24) + #define FXAA_QUALITY__PS 7 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 3.0 + #define FXAA_QUALITY__P6 8.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 25) + #define FXAA_QUALITY__PS 8 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 2.0 + #define FXAA_QUALITY__P6 4.0 + #define FXAA_QUALITY__P7 8.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 26) + #define FXAA_QUALITY__PS 9 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 2.0 + #define FXAA_QUALITY__P6 2.0 + #define FXAA_QUALITY__P7 4.0 + #define FXAA_QUALITY__P8 8.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 27) + #define FXAA_QUALITY__PS 10 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 2.0 + #define FXAA_QUALITY__P6 2.0 + #define FXAA_QUALITY__P7 2.0 + #define FXAA_QUALITY__P8 4.0 + #define FXAA_QUALITY__P9 8.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 28) + #define FXAA_QUALITY__PS 11 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 2.0 + #define FXAA_QUALITY__P6 2.0 + #define FXAA_QUALITY__P7 2.0 + #define FXAA_QUALITY__P8 2.0 + #define FXAA_QUALITY__P9 4.0 + #define FXAA_QUALITY__P10 8.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 29) + #define FXAA_QUALITY__PS 12 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 2.0 + #define FXAA_QUALITY__P6 2.0 + #define FXAA_QUALITY__P7 2.0 + #define FXAA_QUALITY__P8 2.0 + #define FXAA_QUALITY__P9 2.0 + #define FXAA_QUALITY__P10 4.0 + #define FXAA_QUALITY__P11 8.0 +#endif + +/*============================================================================ + FXAA QUALITY - EXTREME QUALITY +============================================================================*/ +#if (FXAA_QUALITY__PRESET == 39) + #define FXAA_QUALITY__PS 12 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.0 + #define FXAA_QUALITY__P2 1.0 + #define FXAA_QUALITY__P3 1.0 + #define FXAA_QUALITY__P4 1.0 + #define FXAA_QUALITY__P5 1.5 + #define FXAA_QUALITY__P6 2.0 + #define FXAA_QUALITY__P7 2.0 + #define FXAA_QUALITY__P8 2.0 + #define FXAA_QUALITY__P9 2.0 + #define FXAA_QUALITY__P10 4.0 + #define FXAA_QUALITY__P11 8.0 +#endif + +#define FxaaSat(x) clamp(x, 0.0, 1.0) + +#ifdef FXAA_ALPHA + +#define FxaaTexTop(t, p) textureLod(t, p, 0.0).aaaa +#define FxaaTexOff(t, p, o, r) textureLodOffset(t, p, 0.0, o).aaaa +#define FxaaLuma(rgba) rgba.a + +#else + +#define FxaaTexTop(t, p) textureLod(t, p, 0.0) +#define FxaaTexOff(t, p, o, r) textureLodOffset(t, p, 0.0, o) + +/* (#B1#) */ +float FxaaLuma(vec4 rgba) { + // note: sqrt because the sampled colors are in a linear colorspace! + // this approximates a perceptual conversion, which is good enough for the + // algorithm + return sqrt(dot(rgba.rgb, vec3(0.2126, 0.7152, 0.0722))); +} + +#endif + +/*============================================================================ + + FXAA3 QUALITY - PC + +============================================================================*/ +/*--------------------------------------------------------------------------*/ +vec4 FxaaPixelShader( + // + // Use noperspective interpolation here (turn off perspective interpolation). + // {xy} = center of pixel + vec2 pos, + // + // Input color texture. + // {rgb_} = color in linear or perceptual color space + sampler2D tex, + // + // Only used on FXAA Quality. + // This must be from a constant/uniform. + // {x_} = 1.0/screenWidthInPixels + // {_y} = 1.0/screenHeightInPixels + vec2 fxaaQualityRcpFrame, + // + // Only used on FXAA Quality. + // This used to be the FXAA_QUALITY__SUBPIX define. + // It is here now to allow easier tuning. + // Choose the amount of sub-pixel aliasing removal. + // This can effect sharpness. + // 1.00 - upper limit (softer) + // 0.75 - default amount of filtering + // 0.50 - lower limit (sharper, less sub-pixel aliasing removal) + // 0.25 - almost off + // 0.00 - completely off + float fxaaQualitySubpix, + // + // Only used on FXAA Quality. + // This used to be the FXAA_QUALITY__EDGE_THRESHOLD define. + // It is here now to allow easier tuning. + // The minimum amount of local contrast required to apply algorithm. + // 0.333 - too little (faster) + // 0.250 - low quality + // 0.166 - default + // 0.125 - high quality + // 0.063 - overkill (slower) + float fxaaQualityEdgeThreshold, + // + // Only used on FXAA Quality. + // This used to be the FXAA_QUALITY__EDGE_THRESHOLD_MIN define. + // It is here now to allow easier tuning. + // Trims the algorithm from processing darks. + // 0.0833 - upper limit (default, the start of visible unfiltered edges) + // 0.0625 - high quality (faster) + // 0.0312 - visible limit (slower) + float fxaaQualityEdgeThresholdMin +) { +/*--------------------------------------------------------------------------*/ + vec2 posM; + posM.x = pos.x; + posM.y = pos.y; + vec4 rgbyM = FxaaTexTop(tex, posM); + float lumaM = FxaaLuma(rgbyM); // (#B4#) + float lumaS = FxaaLuma(FxaaTexOff(tex, posM, ivec2( 0, 1), fxaaQualityRcpFrame.xy)); + float lumaE = FxaaLuma(FxaaTexOff(tex, posM, ivec2( 1, 0), fxaaQualityRcpFrame.xy)); + float lumaN = FxaaLuma(FxaaTexOff(tex, posM, ivec2( 0,-1), fxaaQualityRcpFrame.xy)); + float lumaW = FxaaLuma(FxaaTexOff(tex, posM, ivec2(-1, 0), fxaaQualityRcpFrame.xy)); +/*--------------------------------------------------------------------------*/ + float maxSM = max(lumaS, lumaM); + float minSM = min(lumaS, lumaM); + float maxESM = max(lumaE, maxSM); + float minESM = min(lumaE, minSM); + float maxWN = max(lumaN, lumaW); + float minWN = min(lumaN, lumaW); + float rangeMax = max(maxWN, maxESM); + float rangeMin = min(minWN, minESM); + float rangeMaxScaled = rangeMax * fxaaQualityEdgeThreshold; + float range = rangeMax - rangeMin; + float rangeMaxClamped = max(fxaaQualityEdgeThresholdMin, rangeMaxScaled); + bool earlyExit = range < rangeMaxClamped; +/*--------------------------------------------------------------------------*/ + if(earlyExit) { + return rgbyM; + } +/*--------------------------------------------------------------------------*/ + float lumaNW = FxaaLuma(FxaaTexOff(tex, posM, ivec2(-1,-1), fxaaQualityRcpFrame.xy)); + float lumaSE = FxaaLuma(FxaaTexOff(tex, posM, ivec2( 1, 1), fxaaQualityRcpFrame.xy)); + float lumaNE = FxaaLuma(FxaaTexOff(tex, posM, ivec2( 1,-1), fxaaQualityRcpFrame.xy)); + float lumaSW = FxaaLuma(FxaaTexOff(tex, posM, ivec2(-1, 1), fxaaQualityRcpFrame.xy)); +/*--------------------------------------------------------------------------*/ + float lumaNS = lumaN + lumaS; + float lumaWE = lumaW + lumaE; + float subpixRcpRange = 1.0/range; + float subpixNSWE = lumaNS + lumaWE; + float edgeHorz1 = (-2.0 * lumaM) + lumaNS; + float edgeVert1 = (-2.0 * lumaM) + lumaWE; +/*--------------------------------------------------------------------------*/ + float lumaNESE = lumaNE + lumaSE; + float lumaNWNE = lumaNW + lumaNE; + float edgeHorz2 = (-2.0 * lumaE) + lumaNESE; + float edgeVert2 = (-2.0 * lumaN) + lumaNWNE; +/*--------------------------------------------------------------------------*/ + float lumaNWSW = lumaNW + lumaSW; + float lumaSWSE = lumaSW + lumaSE; + float edgeHorz4 = (abs(edgeHorz1) * 2.0) + abs(edgeHorz2); + float edgeVert4 = (abs(edgeVert1) * 2.0) + abs(edgeVert2); + float edgeHorz3 = (-2.0 * lumaW) + lumaNWSW; + float edgeVert3 = (-2.0 * lumaS) + lumaSWSE; + float edgeHorz = abs(edgeHorz3) + edgeHorz4; + float edgeVert = abs(edgeVert3) + edgeVert4; +/*--------------------------------------------------------------------------*/ + float subpixNWSWNESE = lumaNWSW + lumaNESE; + float lengthSign = fxaaQualityRcpFrame.x; + bool horzSpan = edgeHorz >= edgeVert; + float subpixA = subpixNSWE * 2.0 + subpixNWSWNESE; +/*--------------------------------------------------------------------------*/ + if(!horzSpan) lumaN = lumaW; + if(!horzSpan) lumaS = lumaE; + if(horzSpan) lengthSign = fxaaQualityRcpFrame.y; + float subpixB = (subpixA * (1.0/12.0)) - lumaM; +/*--------------------------------------------------------------------------*/ + float gradientN = lumaN - lumaM; + float gradientS = lumaS - lumaM; + float lumaNN = lumaN + lumaM; + float lumaSS = lumaS + lumaM; + bool pairN = abs(gradientN) >= abs(gradientS); + float gradient = max(abs(gradientN), abs(gradientS)); + if(pairN) lengthSign = -lengthSign; + float subpixC = FxaaSat(abs(subpixB) * subpixRcpRange); +/*--------------------------------------------------------------------------*/ + vec2 posB; + posB.x = posM.x; + posB.y = posM.y; + vec2 offNP; + offNP.x = (!horzSpan) ? 0.0 : fxaaQualityRcpFrame.x; + offNP.y = ( horzSpan) ? 0.0 : fxaaQualityRcpFrame.y; + if(!horzSpan) posB.x += lengthSign * 0.5; + if( horzSpan) posB.y += lengthSign * 0.5; +/*--------------------------------------------------------------------------*/ + vec2 posN; + posN.x = posB.x - offNP.x * FXAA_QUALITY__P0; + posN.y = posB.y - offNP.y * FXAA_QUALITY__P0; + vec2 posP; + posP.x = posB.x + offNP.x * FXAA_QUALITY__P0; + posP.y = posB.y + offNP.y * FXAA_QUALITY__P0; + float subpixD = ((-2.0)*subpixC) + 3.0; + float lumaEndN = FxaaLuma(FxaaTexTop(tex, posN)); + float subpixE = subpixC * subpixC; + float lumaEndP = FxaaLuma(FxaaTexTop(tex, posP)); +/*--------------------------------------------------------------------------*/ + if(!pairN) lumaNN = lumaSS; + float gradientScaled = gradient * 1.0/4.0; + float lumaMM = lumaM - lumaNN * 0.5; + float subpixF = subpixD * subpixE; + bool lumaMLTZero = lumaMM < 0.0; +/*--------------------------------------------------------------------------*/ + lumaEndN -= lumaNN * 0.5; + lumaEndP -= lumaNN * 0.5; + bool doneN = abs(lumaEndN) >= gradientScaled; + bool doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P1; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P1; + bool doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P1; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P1; +/*--------------------------------------------------------------------------*/ + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P2; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P2; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P2; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P2; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 3) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P3; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P3; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P3; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P3; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 4) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P4; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P4; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P4; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P4; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 5) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P5; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P5; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P5; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P5; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 6) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P6; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P6; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P6; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P6; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 7) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P7; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P7; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P7; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P7; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 8) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P8; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P8; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P8; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P8; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 9) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P9; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P9; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P9; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P9; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 10) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P10; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P10; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P10; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P10; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 11) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P11; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P11; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P11; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P11; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 12) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P12; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P12; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P12; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P12; +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } +/*--------------------------------------------------------------------------*/ + float dstN = posM.x - posN.x; + float dstP = posP.x - posM.x; + if(!horzSpan) dstN = posM.y - posN.y; + if(!horzSpan) dstP = posP.y - posM.y; +/*--------------------------------------------------------------------------*/ + bool goodSpanN = (lumaEndN < 0.0) != lumaMLTZero; + float spanLength = (dstP + dstN); + bool goodSpanP = (lumaEndP < 0.0) != lumaMLTZero; + float spanLengthRcp = 1.0/spanLength; +/*--------------------------------------------------------------------------*/ + bool directionN = dstN < dstP; + float dst = min(dstN, dstP); + bool goodSpan = directionN ? goodSpanN : goodSpanP; + float subpixG = subpixF * subpixF; + float pixelOffset = (dst * (-spanLengthRcp)) + 0.5; + float subpixH = subpixG * fxaaQualitySubpix; +/*--------------------------------------------------------------------------*/ + float pixelOffsetGood = goodSpan ? pixelOffset : 0.0; + float pixelOffsetSubpix = max(pixelOffsetGood, subpixH); + if(!horzSpan) posM.x += pixelOffsetSubpix * lengthSign; + if( horzSpan) posM.y += pixelOffsetSubpix * lengthSign; + return vec4(FxaaTexTop(tex, posM).xyz, lumaM); +} +/*==========================================================================*/ diff --git a/source/blender/draw/modes/shaders/common_globals_lib.glsl b/source/blender/draw/modes/shaders/common_globals_lib.glsl new file mode 100644 index 00000000000..69ba304ca24 --- /dev/null +++ b/source/blender/draw/modes/shaders/common_globals_lib.glsl @@ -0,0 +1,80 @@ + +/* keep in sync with GlobalsUboStorage */ +layout(std140) uniform globalsBlock { + vec4 colorWire; + vec4 colorWireEdit; + vec4 colorActive; + vec4 colorSelect; + vec4 colorTransform; + vec4 colorLibrarySelect; + vec4 colorLibrary; + vec4 colorLamp; + vec4 colorSpeaker; + vec4 colorCamera; + vec4 colorEmpty; + vec4 colorVertex; + vec4 colorVertexSelect; + vec4 colorVertexUnreferenced; + vec4 colorVertexMissingData; + vec4 colorEditMeshActive; + vec4 colorEdgeSelect; + vec4 colorEdgeSeam; + vec4 colorEdgeSharp; + vec4 colorEdgeCrease; + vec4 colorEdgeBWeight; + vec4 colorEdgeFaceSelect; + vec4 colorEdgeFreestyle; + vec4 colorFace; + vec4 colorFaceSelect; + vec4 colorFaceFreestyle; + vec4 colorNormal; + vec4 colorVNormal; + vec4 colorLNormal; + vec4 colorFaceDot; + vec4 colorDeselect; + vec4 colorOutline; + vec4 colorLampNoAlpha; + + vec4 colorBackground; + + vec4 colorHandleFree; + vec4 colorHandleAuto; + vec4 colorHandleVect; + vec4 colorHandleAlign; + vec4 colorHandleAutoclamp; + vec4 colorHandleSelFree; + vec4 colorHandleSelAuto; + vec4 colorHandleSelVect; + vec4 colorHandleSelAlign; + vec4 colorHandleSelAutoclamp; + vec4 colorNurbUline; + vec4 colorNurbVline; + vec4 colorNurbSelUline; + vec4 colorNurbSelVline; + vec4 colorActiveSpline; + + vec4 colorBonePose; + + vec4 colorCurrentFrame; + + vec4 colorGrid; + vec4 colorGridEmphasise; + vec4 colorGridAxisX; + vec4 colorGridAxisY; + vec4 colorGridAxisZ; + + float sizeLampCenter; + float sizeLampCircle; + float sizeLampCircleShadow; + float sizeVertex; + float sizeEdge; + float sizeEdgeFix; + float sizeFaceDot; + + float gridDistance; + float gridResolution; + float gridSubdivisions; + float gridScale; + + float pad_globalsBlock; +}; diff --git a/source/blender/draw/modes/shaders/common_hair_lib.glsl b/source/blender/draw/modes/shaders/common_hair_lib.glsl new file mode 100644 index 00000000000..594a7b31f0b --- /dev/null +++ b/source/blender/draw/modes/shaders/common_hair_lib.glsl @@ -0,0 +1,199 @@ +/** + * Library to create hairs dynamically from control points. + * This is less bandwidth intensive than fetching the vertex attributes + * but does more ALU work per vertex. This also reduce the number + * of data the CPU has to precompute and transfert for each update. + **/ + +/** + * hairStrandsRes: Number of points per hair strand. + * 2 - no subdivision + * 3+ - 1 or more interpolated points per hair. + **/ +uniform int hairStrandsRes = 8; + +/** + * hairThicknessRes : Subdiv around the hair. + * 1 - Wire Hair: Only one pixel thick, independent of view distance. + * 2 - Polystrip Hair: Correct width, flat if camera is parallel. + * 3+ - Cylinder Hair: Massive calculation but potentially perfect. Still need proper support. + **/ +uniform int hairThicknessRes = 1; + +/* Hair thickness shape. */ +uniform float hairRadRoot = 0.01; +uniform float hairRadTip = 0.0; +uniform float hairRadShape = 0.5; +uniform bool hairCloseTip = true; + +uniform mat4 hairDupliMatrix; + +/* -- Per control points -- */ +uniform samplerBuffer hairPointBuffer; /* RGBA32F */ +#define point_position xyz +#define point_time w /* Position along the hair length */ + +/* -- Per strands data -- */ +uniform usamplerBuffer hairStrandBuffer; /* R32UI */ + +/* Not used, use one buffer per uv layer */ +//uniform samplerBuffer hairUVBuffer; /* RG32F */ +//uniform samplerBuffer hairColBuffer; /* RGBA16 linear color */ + +void unpack_strand_data(uint data, out int strand_offset, out int strand_segments) +{ +#if 0 /* Pack point count */ + // strand_offset = (data & 0x1FFFFFFFu); + // strand_segments = 1u << (data >> 29u); /* We only need 3 bits to store subdivision level. */ +#else + strand_offset = int(data & 0x00FFFFFFu); + strand_segments = int(data >> 24u); +#endif +} + +/* -- Subdivision stage -- */ +/** + * We use a transform feedback to preprocess the strands and add more subdivision to it. + * For the moment theses are simple smooth interpolation but one could hope to see the full + * children particle modifiers being evaluated at this stage. + * + * If no more subdivision is needed, we can skip this step. + **/ + +#ifdef HAIR_PHASE_SUBDIV +int hair_get_base_id(float local_time, int strand_segments, out float interp_time) +{ + float time_per_strand_seg = 1.0 / float(strand_segments); + + float ratio = local_time / time_per_strand_seg; + interp_time = fract(ratio); + + return int(ratio); +} + +void hair_get_interp_attribs(out vec4 data0, out vec4 data1, out vec4 data2, out vec4 data3, out float interp_time) +{ + float local_time = float(gl_VertexID % hairStrandsRes) / float(hairStrandsRes - 1); + + int hair_id = gl_VertexID / hairStrandsRes; + uint strand_data = texelFetch(hairStrandBuffer, hair_id).x; + + int strand_offset, strand_segments; + unpack_strand_data(strand_data, strand_offset, strand_segments); + + int id = hair_get_base_id(local_time, strand_segments, interp_time); + + int ofs_id = id + strand_offset; + + data0 = texelFetch(hairPointBuffer, ofs_id - 1); + data1 = texelFetch(hairPointBuffer, ofs_id); + data2 = texelFetch(hairPointBuffer, ofs_id + 1); + data3 = texelFetch(hairPointBuffer, ofs_id + 2); + + if (id <= 0) { + /* root points. Need to reconstruct previous data. */ + data0 = data1 * 2.0 - data2; + } + if (id + 1 >= strand_segments) { + /* tip points. Need to reconstruct next data. */ + data3 = data2 * 2.0 - data1; + } +} +#endif + +/* -- Drawing stage -- */ +/** + * For final drawing, the vertex index and the number of vertex per segment + **/ + +#ifndef HAIR_PHASE_SUBDIV +int hair_get_strand_id(void) +{ + return gl_VertexID / (hairStrandsRes * hairThicknessRes); +} + +int hair_get_base_id(void) +{ + return gl_VertexID / hairThicknessRes; +} + +/* Copied from cycles. */ +float hair_shaperadius(float shape, float root, float tip, float time) +{ + float radius = 1.0 - time; + + if (shape < 0.0) { + radius = pow(radius, 1.0 + shape); + } + else { + radius = pow(radius, 1.0 / (1.0 - shape)); + } + + if (hairCloseTip && (time > 0.99)) { + return 0.0; + } + + return (radius * (root - tip)) + tip; +} + +void hair_get_pos_tan_binor_time( + bool is_persp, mat4 invmodel_mat, vec3 camera_pos, vec3 camera_z, + out vec3 wpos, out vec3 wtan, out vec3 wbinor, out float time, out float thickness, out float thick_time) +{ + int id = hair_get_base_id(); + vec4 data = texelFetch(hairPointBuffer, id); + wpos = data.point_position; + time = data.point_time; + if (time == 0.0) { + /* Hair root */ + wtan = texelFetch(hairPointBuffer, id + 1).point_position - wpos; + } + else { + wtan = wpos - texelFetch(hairPointBuffer, id - 1).point_position; + } + + wpos = (hairDupliMatrix * vec4(wpos, 1.0)).xyz; + wtan = mat3(hairDupliMatrix) * wtan; + + vec3 camera_vec = (is_persp) ? wpos - camera_pos : -camera_z; + wbinor = normalize(cross(camera_vec, wtan)); + + thickness = hair_shaperadius(hairRadShape, hairRadRoot, hairRadTip, time); + + if (hairThicknessRes > 1) { + thick_time = float(gl_VertexID % hairThicknessRes) / float(hairThicknessRes - 1); + thick_time = thickness * (thick_time * 2.0 - 1.0); + + /* Take object scale into account. + * NOTE: This only works fine with uniform scaling. */ + float scale = 1.0 / length(mat3(invmodel_mat) * wbinor); + + wpos += wbinor * thick_time * scale; + } +} + +vec2 hair_get_customdata_vec2(const samplerBuffer cd_buf) +{ + int id = hair_get_strand_id(); + return texelFetch(cd_buf, id).rg; +} + +vec3 hair_get_customdata_vec3(const samplerBuffer cd_buf) +{ + int id = hair_get_strand_id(); + return texelFetch(cd_buf, id).rgb; +} + +vec4 hair_get_customdata_vec4(const samplerBuffer cd_buf) +{ + int id = hair_get_strand_id(); + return texelFetch(cd_buf, id).rgba; +} + +vec3 hair_get_strand_pos(void) +{ + int id = hair_get_strand_id() * hairStrandsRes; + return texelFetch(hairPointBuffer, id).point_position; +} + +#endif diff --git a/source/blender/draw/modes/shaders/common_hair_refine_vert.glsl b/source/blender/draw/modes/shaders/common_hair_refine_vert.glsl new file mode 100644 index 00000000000..9f412c57db3 --- /dev/null +++ b/source/blender/draw/modes/shaders/common_hair_refine_vert.glsl @@ -0,0 +1,55 @@ + +/* To be compiled with common_hair_lib.glsl */ + +out vec4 outData; + +vec4 get_weights_cardinal(float t) +{ + float t2 = t * t; + float t3 = t2 * t; +#if defined(CARDINAL) + float fc = 0.71; +#else /* defined(CATMULL_ROM) */ + float fc = 0.5; +#endif + + vec4 weights; + /* GLSL Optimized version of key_curve_position_weights() */ + float fct = t * fc; + float fct2 = t2 * fc; + float fct3 = t3 * fc; + weights.x = ( fct2 * 2.0 - fct3) - fct; + weights.y = ( t3 * 2.0 - fct3) + (-t2 * 3.0 + fct2) + 1.0; + weights.z = (-t3 * 2.0 + fct3) + ( t2 * 3.0 - (2.0 * fct2)) + fct; + weights.w = fct3 - fct2; + return weights; +} + +/* TODO(fclem): This one is buggy, find why. (it's not the optimization!!) */ +vec4 get_weights_bspline(float t) +{ + float t2 = t * t; + float t3 = t2 * t; + + vec4 weights; + /* GLSL Optimized version of key_curve_position_weights() */ + weights.xz = vec2(-0.16666666, -0.5) * t3 + (0.5 * t2 + 0.5 * vec2(-t, t) + 0.16666666); + weights.y = ( 0.5 * t3 - t2 + 0.66666666); + weights.w = ( 0.16666666 * t3); + return weights; +} + +vec4 interp_data(vec4 v0, vec4 v1, vec4 v2, vec4 v3, vec4 w) +{ + return v0 * w.x + v1 * w.y + v2 * w.z + v3 * w.w; +} + +void main(void) +{ + float interp_time; + vec4 data0, data1, data2, data3; + hair_get_interp_attribs(data0, data1, data2, data3, interp_time); + + vec4 weights = get_weights_cardinal(interp_time); + outData = interp_data(data0, data1, data2, data3, weights); +} diff --git a/source/blender/draw/modes/shaders/common_view_lib.glsl b/source/blender/draw/modes/shaders/common_view_lib.glsl new file mode 100644 index 00000000000..d261d263a6f --- /dev/null +++ b/source/blender/draw/modes/shaders/common_view_lib.glsl @@ -0,0 +1,14 @@ +/* keep in sync with DRWManager.view_data */ +layout(std140) uniform viewBlock { + /* Same order as DRWViewportMatrixType */ + mat4 ViewProjectionMatrix; + mat4 ViewProjectionMatrixInverse; + mat4 ViewMatrix; + mat4 ViewMatrixInverse; + mat4 ProjectionMatrix; + mat4 ProjectionMatrixInverse; + + vec4 CameraTexCoFactors; + + vec4 clipPlanes[2]; +}; diff --git a/source/blender/draw/modes/shaders/edit_curve_overlay_handle_geom.glsl b/source/blender/draw/modes/shaders/edit_curve_overlay_handle_geom.glsl new file mode 100644 index 00000000000..7bc9b381bad --- /dev/null +++ b/source/blender/draw/modes/shaders/edit_curve_overlay_handle_geom.glsl @@ -0,0 +1,96 @@ + +#define VERTEX_ACTIVE 1 << 0 +#define VERTEX_SELECTED 1 << 1 +#define ACTIVE_NURB 1 << 2 /* Keep the same value of `ACTIVE_NURB` in `draw_cache_imp_curve.c` */ +#define EVEN_U_BIT 1 << 3 + +layout(lines) in; +layout(triangle_strip, max_vertices = 10) out; + +uniform vec2 viewportSize; +uniform bool showCurveHandles; + +flat in int vertFlag[]; + +out vec4 finalColor; + +void output_line(vec2 offset, vec4 color) +{ + finalColor = color; + + gl_Position = gl_in[0].gl_Position; + gl_Position.xy += offset * gl_in[0].gl_Position.w; + EmitVertex(); + + gl_Position = gl_in[1].gl_Position; + gl_Position.xy += offset * gl_in[1].gl_Position.w; + EmitVertex(); +} + +void main() +{ + vec4 v1 = gl_in[0].gl_Position; + vec4 v2 = gl_in[1].gl_Position; + + int is_active_nurb = (vertFlag[1] & ACTIVE_NURB); + int color_id = (vertFlag[1] >> 4); + + /* Don't output any edges if we don't show handles */ + if (!showCurveHandles && (color_id < 5)) + return; + + bool edge_selected = (((vertFlag[1] | vertFlag[0]) & VERTEX_SELECTED) != 0); + + vec4 inner_color; + if (color_id == 0) inner_color = (edge_selected) ? colorHandleSelFree : colorHandleFree; + else if (color_id == 1) inner_color = (edge_selected) ? colorHandleSelAuto : colorHandleAuto; + else if (color_id == 2) inner_color = (edge_selected) ? colorHandleSelVect : colorHandleVect; + else if (color_id == 3) inner_color = (edge_selected) ? colorHandleSelAlign : colorHandleAlign; + else if (color_id == 4) inner_color = (edge_selected) ? colorHandleSelAutoclamp : colorHandleAutoclamp; + else { + bool is_selected = (((vertFlag[1] & vertFlag[0]) & VERTEX_SELECTED) != 0); + bool is_u_segment = (((vertFlag[1] ^ vertFlag[0]) & EVEN_U_BIT) != 0); + if (is_u_segment) { + inner_color = (is_selected) ? colorNurbSelUline : colorNurbUline; + } + else { + inner_color = (is_selected) ? colorNurbSelVline : colorNurbVline; + } + } + + vec4 outer_color = (is_active_nurb != 0) + ? mix(colorActiveSpline, inner_color, 0.25) /* Minimize active color bleeding on inner_color. */ + : vec4(inner_color.rgb, 0.0); + + vec2 v1_2 = (v2.xy/v2.w - v1.xy/v1.w); + vec2 offset = sizeEdge * 4.0 / viewportSize; /* 4.0 is eyeballed */ + + if (abs(v1_2.x * viewportSize.x) < abs(v1_2.y * viewportSize.y)) { + offset.y = 0.0; + } + else { + offset.x = 0.0; + } + + /* draw the transparent border (AA). */ + if (is_active_nurb != 0) { + offset *= 0.75; /* Don't make the active "halo" appear very thick. */ + output_line(offset * 2.0, vec4(colorActiveSpline.rgb, 0.0)); + } + + /* draw the outline. */ + output_line(offset, outer_color); + + /* draw the core of the line. */ + output_line(vec2(0.0), inner_color); + + /* draw the outline. */ + output_line(-offset, outer_color); + + /* draw the transparent border (AA). */ + if (is_active_nurb != 0) { + output_line(offset * -2.0, vec4(colorActiveSpline.rgb, 0.0)); + } + + EndPrimitive(); +} diff --git a/source/blender/draw/modes/shaders/edit_curve_overlay_handle_vert.glsl b/source/blender/draw/modes/shaders/edit_curve_overlay_handle_vert.glsl new file mode 100644 index 00000000000..d3f9deedf0c --- /dev/null +++ b/source/blender/draw/modes/shaders/edit_curve_overlay_handle_vert.glsl @@ -0,0 +1,15 @@ + +/* Draw Curve Handles */ + +uniform mat4 ModelViewProjectionMatrix; + +in vec3 pos; +in int data; + +flat out int vertFlag; + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + vertFlag = data; +} diff --git a/source/blender/draw/modes/shaders/edit_curve_overlay_loosevert_vert.glsl b/source/blender/draw/modes/shaders/edit_curve_overlay_loosevert_vert.glsl new file mode 100644 index 00000000000..85e38ba3b43 --- /dev/null +++ b/source/blender/draw/modes/shaders/edit_curve_overlay_loosevert_vert.glsl @@ -0,0 +1,31 @@ + +/* Draw Curve Vertices */ + +uniform mat4 ModelViewProjectionMatrix; +uniform vec2 viewportSize; + +in vec3 pos; +in int data; + +out vec4 finalColor; + +#define VERTEX_ACTIVE (1 << 0) +#define VERTEX_SELECTED (1 << 1) + +void main() +{ + if ((data & VERTEX_SELECTED) != 0) { + if ((data & VERTEX_ACTIVE) != 0) { + finalColor = colorEditMeshActive; + } + else { + finalColor = colorVertexSelect; + } + } + else { + finalColor = colorVertex; + } + + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + gl_PointSize = sizeVertex * 2.0; +} diff --git a/source/blender/draw/modes/shaders/edit_lattice_overlay_frag.glsl b/source/blender/draw/modes/shaders/edit_lattice_overlay_frag.glsl new file mode 100644 index 00000000000..e78462b6915 --- /dev/null +++ b/source/blender/draw/modes/shaders/edit_lattice_overlay_frag.glsl @@ -0,0 +1,22 @@ + +flat in int vertFlag; + +#define VERTEX_SELECTED (1 << 0) +#define VERTEX_ACTIVE (1 << 1) + +out vec4 FragColor; + +void main() +{ + /* TODO: vertex size */ + + if ((vertFlag & VERTEX_SELECTED) != 0) { + FragColor = colorVertexSelect; + } + else if ((vertFlag & VERTEX_ACTIVE) != 0) { + FragColor = colorEditMeshActive; + } + else { + FragColor = colorVertex; + } +} diff --git a/source/blender/draw/modes/shaders/edit_lattice_overlay_loosevert_vert.glsl b/source/blender/draw/modes/shaders/edit_lattice_overlay_loosevert_vert.glsl new file mode 100644 index 00000000000..0cbc66a2b1f --- /dev/null +++ b/source/blender/draw/modes/shaders/edit_lattice_overlay_loosevert_vert.glsl @@ -0,0 +1,39 @@ + +/* Draw Lattice Vertices */ + +uniform mat4 ModelViewProjectionMatrix; +uniform vec2 viewportSize; + +in vec3 pos; +in int data; + +/* these are the same for all vertices + * and does not need interpolation */ +flat out int vertFlag; +flat out int clipCase; + +/* See fragment shader */ +noperspective out vec4 eData1; +flat out vec4 eData2; + +/* project to screen space */ +vec2 proj(vec4 pos) +{ + return (0.5 * (pos.xy / pos.w) + 0.5) * viewportSize; +} + +void main() +{ + clipCase = 0; + + vec4 pPos = ModelViewProjectionMatrix * vec4(pos, 1.0); + + /* only vertex position 0 is used */ + eData1 = eData2 = vec4(1e10); + eData2.zw = proj(pPos); + + vertFlag = data; + + gl_PointSize = sizeVertex; + gl_Position = pPos; +} diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_common_lib.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_common_lib.glsl new file mode 100644 index 00000000000..b37862f2037 --- /dev/null +++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_common_lib.glsl @@ -0,0 +1,53 @@ +#define EDGE_EXISTS (1 << 0) +#define EDGE_ACTIVE (1 << 1) +#define EDGE_SELECTED (1 << 2) +#define EDGE_SEAM (1 << 3) +#define EDGE_SHARP (1 << 4) +#define EDGE_FREESTYLE (1 << 5) +#define EDGE_VERTEX_ACTIVE (1 << (0 + 8)) +#define EDGE_VERTEX_SELECTED (1 << (1 + 8)) +#define EDGE_VERTEX_EXISTS (1 << (2 + 8)) + +#define VERTEX_ACTIVE (1 << 0) +#define VERTEX_SELECTED (1 << 1) +#define VERTEX_EXISTS (1 << 2) + +#define FACE_ACTIVE (1 << 3) +#define FACE_SELECTED (1 << 4) +#define FACE_FREESTYLE (1 << 5) + +uniform bool doEdges = true; + +vec4 EDIT_MESH_edge_color_outer(int edge_flag, bool face_active, float crease, float bweight) +{ + vec4 color = vec4(0.0); + color = ((edge_flag & EDGE_FREESTYLE) != 0) ? colorEdgeFreestyle : color; + color = ((edge_flag & EDGE_SHARP) != 0) ? colorEdgeSharp : color; + color = (crease > 0.0) ? vec4(colorEdgeCrease.rgb, crease) : color; + color = (bweight > 0.0) ? vec4(colorEdgeBWeight.rgb, bweight) : color; + color = ((edge_flag & EDGE_SEAM) != 0) ? colorEdgeSeam : color; + + if (face_active) { + color = colorEditMeshActive; + } + return color; +} + +vec4 EDIT_MESH_edge_color_inner(int edge_flag, bool face_active) +{ + vec4 color = colorWireEdit; +#ifdef EDGE_SELECTION + color = ((edge_flag & EDGE_SELECTED) != 0) ? colorEdgeSelect : color; + color = ((edge_flag & EDGE_ACTIVE) != 0) ? colorEditMeshActive : color; +#else + color = (doEdges && (edge_flag & EDGE_SELECTED) != 0) ? colorEdgeSelect : color; +#endif + return color; +} + +vec4 EDIT_MESH_vertex_color(int vertex_flag) +{ + vec4 color = colorWireEdit; + color = (doEdges && (vertex_flag & (VERTEX_ACTIVE | VERTEX_SELECTED)) != 0) ? colorEdgeSelect : color; + return color; +} diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_facedot_frag.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_facedot_frag.glsl new file mode 100644 index 00000000000..71cc1ccde8d --- /dev/null +++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_facedot_frag.glsl @@ -0,0 +1,19 @@ + +flat in int isSelected; +#ifdef VERTEX_FACING +flat in float facing; +#endif + +out vec4 FragColor; + +void main() +{ + if (isSelected != 0) + FragColor = colorFaceDot; + else + FragColor = colorVertex; + +#ifdef VERTEX_FACING + FragColor.a *= 1.0 - abs(facing) * 0.4; +#endif +} diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_facedot_vert.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_facedot_vert.glsl new file mode 100644 index 00000000000..50f6f3e2cf8 --- /dev/null +++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_facedot_vert.glsl @@ -0,0 +1,31 @@ + +uniform mat4 ModelViewProjectionMatrix; + +in vec3 pos; +in vec4 norAndFlag; + +flat out int isSelected; + +#ifdef VERTEX_FACING +uniform mat4 ProjectionMatrix; +uniform mat4 ModelViewMatrix; +uniform mat3 NormalMatrix; + +flat out float facing; +#endif + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + /* Bias Facedot Z position in clipspace. */ + gl_Position.z -= 0.00035; + gl_PointSize = sizeFaceDot; + isSelected = int(norAndFlag.w); +#ifdef VERTEX_FACING + vec3 view_normal = normalize(NormalMatrix * norAndFlag.xyz); + vec3 view_vec = (ProjectionMatrix[3][3] == 0.0) + ? normalize((ModelViewMatrix * vec4(pos, 1.0)).xyz) + : vec3(0.0, 0.0, 1.0); + facing = dot(view_vec, view_normal); +#endif +} diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_facefill_frag.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_facefill_frag.glsl new file mode 100644 index 00000000000..2e729009a38 --- /dev/null +++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_facefill_frag.glsl @@ -0,0 +1,7 @@ +flat in vec4 faceColor; +out vec4 FragColor; + +void main() +{ + FragColor = faceColor; +} diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_facefill_vert.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_facefill_vert.glsl new file mode 100644 index 00000000000..eb68eb9b0dc --- /dev/null +++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_facefill_vert.glsl @@ -0,0 +1,28 @@ + +uniform mat4 ModelViewProjectionMatrix; +uniform ivec4 dataMask = ivec4(0xFF); + +in vec3 pos; +in ivec4 data; + +flat out vec4 faceColor; + +#define FACE_ACTIVE (1 << 3) +#define FACE_SELECTED (1 << 4) +#define FACE_FREESTYLE (1 << 5) + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + + ivec4 data_m = data & dataMask; + + if ((data_m.x & FACE_ACTIVE) != 0) + faceColor = colorFaceSelect; + else if ((data_m.x & FACE_SELECTED) != 0) + faceColor = colorFaceSelect; + else if ((data_m.x & FACE_FREESTYLE) != 0) + faceColor = colorFaceFreestyle; + else + faceColor = colorFace; +} diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_frag.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_frag.glsl new file mode 100644 index 00000000000..8d7a653c2fe --- /dev/null +++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_frag.glsl @@ -0,0 +1,152 @@ + +/* Solid Wirefram implementation + * Mike Erwin, Clément Foucault */ + +uniform float faceAlphaMod; +uniform float edgeScale; +uniform bool isXray = false; + +flat in vec3 edgesCrease; +flat in vec3 edgesBweight; +flat in vec4 faceColor; +flat in ivec3 flag; +#ifdef VERTEX_SELECTION +in vec3 vertexColor; +#endif + +#ifdef EDGE_FIX +flat in vec2 ssPos[3]; +#else +in vec3 barycentric; +#endif + +#ifdef VERTEX_FACING +in float facing; +#endif + +out vec4 FragColor; + +/* Vertex flag is shifted and combined with the edge flag */ +#define FACE_ACTIVE_ (FACE_ACTIVE << 8) + +#define LARGE_EDGE_SIZE 2.15 + +/* Enough to visually fill gaps and not enough to mess the AA gradient too much. */ +#define EDGE_FIX_ALPHA 0.67 + +void distToEdgesAndPoints(out vec3 edges, out vec3 points) +{ +#ifdef EDGE_FIX + vec2 e0 = normalize(ssPos[1] - ssPos[0] + 1e-8); + vec2 e1 = normalize(ssPos[2] - ssPos[1] + 1e-8); + vec2 e2 = normalize(ssPos[0] - ssPos[2] + 1e-8); + e0 = vec2(-e0.y, e0.x); + e1 = vec2(-e1.y, e1.x); + e2 = vec2(-e2.y, e2.x); + vec2 p0 = gl_FragCoord.xy - ssPos[0]; + vec2 p1 = gl_FragCoord.xy - ssPos[1]; + vec2 p2 = gl_FragCoord.xy - ssPos[2]; + edges.z = abs(dot(e0, p0)); + edges.x = abs(dot(e1, p1)); + edges.y = abs(dot(e2, p2)); +#else + vec3 dx = dFdx(barycentric); + vec3 dy = dFdy(barycentric); + /* per component derivative */ + vec2 d0 = vec2(dx.x, dy.x); + vec2 d1 = vec2(dx.y, dy.y); + vec2 d2 = vec2(dx.z, dy.z); + vec3 d = vec3(length(d0), length(d1), length(d2)); + + edges = abs(vec3(barycentric / d)); +#endif + +#if defined(VERTEX_SELECTION) && defined(EDGE_FIX) + points.x = dot(p0, p0); + points.y = dot(p1, p1); + points.z = dot(p2, p2); + points = sqrt(points); +#else + points = vec3(1e10); +#endif +} + +void colorDist(vec4 color, float dist) +{ + FragColor = (dist < 0) ? color : FragColor; +} + +#ifdef ANTI_ALIASING +void colorDistEdge(vec4 color, float dist) +{ + FragColor.rgb *= FragColor.a; + FragColor = mix(color, FragColor, clamp(dist, 0.0, 1.0)); + FragColor.rgb /= max(1e-8, FragColor.a); +} +#else +#define colorDistEdge colorDist +#endif + +void main() +{ + vec3 e, p; + distToEdgesAndPoints(e, p); + + /* Face */ + FragColor = faceColor; + FragColor.a *= faceAlphaMod; + + /* Edges */ + float sizeEdgeFinal = sizeEdge * edgeScale; + + for (int v = 0; v < 3; ++v) { + if ((flag[v] & EDGE_EXISTS) != 0) { + /* Outer large edge */ + float largeEdge = e[v] - sizeEdgeFinal * LARGE_EDGE_SIZE; + + vec4 large_edge_color = EDIT_MESH_edge_color_outer(flag[v], (flag[0] & FACE_ACTIVE_) != 0, edgesCrease[v], edgesBweight[v]); +#ifdef EDGE_FIX + large_edge_color *= isXray ? 1.0 : EDGE_FIX_ALPHA; +#endif + if (large_edge_color.a != 0.0) { + colorDistEdge(large_edge_color, largeEdge); + } + + /* Inner thin edge */ + float innerEdge = e[v] - sizeEdgeFinal; +#ifdef ANTI_ALIASING + innerEdge += 0.4; +#endif + +#ifdef VERTEX_SELECTION + vec4 inner_edge_color = vec4(vertexColor, 1.0); +#else + vec4 inner_edge_color = EDIT_MESH_edge_color_inner(flag[v], (flag[0] & FACE_ACTIVE_) != 0); +#endif +#ifdef EDGE_FIX + inner_edge_color *= isXray ? 1.0 : EDGE_FIX_ALPHA; +#endif + colorDistEdge(inner_edge_color, innerEdge); + } + } + +#if defined(VERTEX_SELECTION) && defined(EDGE_FIX) + /* Points */ + for (int v = 0; v < 3; ++v) { + if ((flag[v] & EDGE_VERTEX_EXISTS) != 0) { + float size = p[v] - sizeVertex; + vec4 point_color = colorVertex; + point_color = ((flag[v] & EDGE_VERTEX_SELECTED) != 0) ? colorVertexSelect : point_color; + point_color = ((flag[v] & EDGE_VERTEX_ACTIVE) != 0) ? vec4(colorEditMeshActive.xyz, 1.0) : point_color; + colorDist(point_color, size); + } + } +#endif + +#ifdef VERTEX_FACING + FragColor.a *= 1.0 - abs(facing) * 0.4; +#endif + + /* don't write depth if not opaque */ + if (FragColor.a == 0.0) discard; +} diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_geom_edge.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_geom_edge.glsl new file mode 100644 index 00000000000..1a44e4a9e4f --- /dev/null +++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_geom_edge.glsl @@ -0,0 +1,119 @@ + +/* Solid Wirefram implementation + * Mike Erwin, Clément Foucault */ + +layout(lines) in; +layout(triangle_strip, max_vertices=4) out; + +uniform mat4 ProjectionMatrix; +uniform vec2 viewportSize; + +in vec4 pPos[]; +in ivec4 vData[]; +#ifdef VERTEX_FACING +in float vFacing[]; +#endif + +/* these are the same for all vertices + * and does not need interpolation */ +flat out vec3 edgesCrease; +flat out vec3 edgesBweight; +flat out vec4 faceColor; +flat out ivec3 flag; +#ifdef VERTEX_SELECTION +out vec3 vertexColor; +#endif +#ifdef VERTEX_FACING +out float facing; +#endif + +/* See fragment shader */ +flat out vec2 ssPos[3]; + +/* Some bugged AMD drivers need these global variables. See T55961 */ +#ifdef VERTEX_SELECTION +vec3 vertex_color[3]; +#endif + +#ifdef VERTEX_FACING +float v_facing[3]; +#endif + +/* project to screen space */ +vec2 proj(vec4 pos) +{ + return (0.5 * (pos.xy / pos.w) + 0.5) * viewportSize; +} + +void doVertex(int v, vec4 pos) +{ +#ifdef VERTEX_SELECTION + vertexColor = vertex_color[v]; +#endif + +#ifdef VERTEX_FACING + facing = v_facing[v]; +#endif + + gl_Position = pos; + + EmitVertex(); +} + +void main() +{ + /* Face */ + faceColor = vec4(0.0); + + /* Proj Vertex */ + vec2 pos[2] = vec2[2](proj(pPos[0]), proj(pPos[1])); + + /* little optimization use a vec4 to vectorize + * following operations */ + vec4 dirs1, dirs2; + + /* Edge normalized vector */ + dirs1.xy = normalize(pos[1] - pos[0]); + + /* perpendicular to dir */ + dirs1.zw = vec2(-dirs1.y, dirs1.x); + + /* Make it view independent */ + dirs1 *= sizeEdgeFix / viewportSize.xyxy; + + dirs2 = dirs1; + + /* Perspective */ + if (ProjectionMatrix[3][3] == 0.0) { + dirs1 *= pPos[0].w; + dirs2 *= pPos[1].w; + } + +#ifdef VERTEX_SELECTION + vertex_color[0] = EDIT_MESH_vertex_color(vData[0].x).rgb; + vertex_color[1] = EDIT_MESH_vertex_color(vData[1].x).rgb; +#endif + +#ifdef VERTEX_FACING + /* Weird but some buggy AMD drivers need this. */ + v_facing[0] = vFacing[0]; + v_facing[1] = vFacing[1]; +#endif + + /* Edge / Vert data */ + ssPos[0] = ssPos[2] = pos[0]; + ssPos[1] = pos[1]; + flag[0] = flag[2] = (vData[0].x << 8); + flag[1] = (vData[1].x << 8); + doVertex(0, pPos[0] + vec4( dirs1.zw, 0.0, 0.0)); + doVertex(0, pPos[0] + vec4(-dirs1.zw, 0.0, 0.0)); + + flag[2] |= vData[0].y; + edgesCrease[2] = vData[0].z / 255.0; + edgesBweight[2] = vData[0].w / 255.0; + + doVertex(1, pPos[1] + vec4( dirs2.zw, 0.0, 0.0)); + doVertex(1, pPos[1] + vec4(-dirs2.zw, 0.0, 0.0)); + + EndPrimitive(); +} diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_geom_tri.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_geom_tri.glsl new file mode 100644 index 00000000000..a04494d2ec4 --- /dev/null +++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_geom_tri.glsl @@ -0,0 +1,211 @@ + +/* Solid Wirefram implementation + * Mike Erwin, Clément Foucault */ + +layout(triangles) in; + +/* To fix the edge artifacts, we render + * an outline strip around the screenspace + * triangle. Order is important. + * TODO diagram + */ +layout(triangle_strip, max_vertices=12) out; + +uniform mat4 ProjectionMatrix; +uniform vec2 viewportSize; +uniform bool isXray = false; + +in vec4 pPos[]; +in ivec4 vData[]; +#ifdef VERTEX_FACING +in float vFacing[]; +#endif + +/* these are the same for all vertices + * and does not need interpolation */ +flat out vec3 edgesCrease; +flat out vec3 edgesBweight; +flat out vec4 faceColor; +flat out ivec3 flag; + +flat out vec2 ssPos[3]; +#ifdef VERTEX_SELECTION +out vec3 vertexColor; +#endif +#ifdef VERTEX_FACING +out float facing; +#endif + +#ifdef ANTI_ALIASING +#define Z_OFFSET -0.0005 +#else +#define Z_OFFSET 0.0 +#endif + +/* Some bugged AMD drivers need these global variables. See T55961 */ +#ifdef VERTEX_SELECTION +vec3 vertex_color[3]; +#endif + +#ifdef VERTEX_FACING +float v_facing[3]; +#endif + +/* project to screen space */ +vec2 proj(vec4 pos) +{ + return (0.5 * (pos.xy / pos.w) + 0.5) * viewportSize; +} + +void doVertex(int v) +{ +#ifdef VERTEX_SELECTION + vertexColor = vertex_color[v]; +#endif + +#ifdef VERTEX_FACING + facing = v_facing[v]; +#endif + gl_Position = pPos[v]; + + EmitVertex(); +} + +void doVertexOfs(int v, vec2 fixvec) +{ +#ifdef VERTEX_SELECTION + vertexColor = vertex_color[v]; +#endif + +#ifdef VERTEX_FACING + facing = v_facing[v]; +#endif + float z_ofs = Z_OFFSET * ((ProjectionMatrix[3][3] == 0.0) ? 1.0 : 0.0); + gl_Position = pPos[v] + vec4(fixvec * pPos[v].w, z_ofs, 0.0); + + EmitVertex(); +} + +void mask_edge_flag(int v, ivec3 eflag) +{ + int vaf = (v + 1) % 3; + + /* Only shade the edge that we are currently drawing. + * (fix corner bleeding) */ + flag = eflag & ~EDGE_VERTEX_EXISTS; + flag[vaf] &= ~EDGE_EXISTS; + flag[v] &= ~EDGE_EXISTS; +} + +vec2 compute_fixvec(int i) +{ + int i1 = (i + 1) % 3; + int i2 = (i + 2) % 3; + /* This fix the case when 2 vertices are perfectly aligned + * and corner vectors have nowhere to go. + * ie: length(cornervec[i]) == 0 */ + const float epsilon = 1e-2; /* in pixel so not that much */ + const vec2 bias[3] = vec2[3]( + vec2( epsilon, epsilon), + vec2(-epsilon, epsilon), + vec2( 0.0, -epsilon) + ); + vec2 v1 = ssPos[i] + bias[i]; + vec2 v2 = ssPos[i1] + bias[i1]; + vec2 v3 = ssPos[i2] + bias[i2]; + /* Edge normalized vector */ + vec2 dir = normalize(v2 - v1); + vec2 dir2 = normalize(v3 - v1); + /* perpendicular to dir */ + vec2 perp = vec2(-dir.y, dir.x); + /* Backface case */ + if (dot(perp, dir2) > 0.0) { + perp = -perp; + } + /* Make it view independent */ + return perp * sizeEdgeFix / viewportSize; +} + +void main() +{ + /* Edge */ + ivec3 eflag; + for (int v = 0; v < 3; ++v) { + eflag[v] = vData[v].y | (vData[v].x << 8); + edgesCrease[v] = vData[v].z / 255.0; + edgesBweight[v] = vData[v].w / 255.0; + } + + /* Face */ + vec4 fcol; + if ((vData[0].x & FACE_ACTIVE) != 0) + fcol = colorFaceSelect; + else if ((vData[0].x & FACE_SELECTED) != 0) + fcol = colorFaceSelect; + else if ((vData[0].x & FACE_FREESTYLE) != 0) + fcol = colorFaceFreestyle; + else + fcol = colorFace; + + /* Vertex */ + ssPos[0] = proj(pPos[0]); + ssPos[1] = proj(pPos[1]); + ssPos[2] = proj(pPos[2]); + +#ifdef VERTEX_SELECTION + vertex_color[0] = EDIT_MESH_vertex_color(vData[0].x).rgb; + vertex_color[1] = EDIT_MESH_vertex_color(vData[1].x).rgb; + vertex_color[2] = EDIT_MESH_vertex_color(vData[2].x).rgb; +#endif + +#ifdef VERTEX_FACING + /* Weird but some buggy AMD drivers need this. */ + v_facing[0] = vFacing[0]; + v_facing[1] = vFacing[1]; + v_facing[2] = vFacing[2]; +#endif + + /* Remember that we are assuming the last vertex + * of a triangle is the provoking vertex (decide what flat attribs are). */ + + if ((eflag[2] & EDGE_EXISTS) != 0) { + /* Do 0 -> 1 edge strip */ + faceColor = vec4(fcol.rgb, 0.0); + mask_edge_flag(0, eflag); + + vec2 fixvec = compute_fixvec(0); + doVertexOfs(0, fixvec); + doVertexOfs(1, fixvec); + } + + doVertex(0); + doVertex(1); + + /* Do face triangle */ + faceColor = fcol; + flag = (isXray) ? ivec3(0) : eflag; + doVertex(2); + faceColor.a = 0.0; /* to not let face color bleed */ + + if ((eflag[0] & EDGE_EXISTS) != 0) { + /* Do 1 -> 2 edge strip */ + mask_edge_flag(1, eflag); + + vec2 fixvec = compute_fixvec(1); + doVertexOfs(1, fixvec); + doVertexOfs(2, fixvec); + } + EndPrimitive(); + + if ((eflag[1] & EDGE_EXISTS) != 0) { + /* Do 2 -> 0 edge strip */ + mask_edge_flag(2, eflag); + doVertex(2); + doVertex(0); + + vec2 fixvec = compute_fixvec(2); + doVertexOfs(2, fixvec); + doVertexOfs(0, fixvec); + EndPrimitive(); + } +} diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_ghost_clear_vert.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_ghost_clear_vert.glsl new file mode 100644 index 00000000000..3fd4d263aa2 --- /dev/null +++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_ghost_clear_vert.glsl @@ -0,0 +1,7 @@ + +in vec2 pos; + +void main() +{ + gl_Position = vec4(pos, 1.0, 1.0); +} diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_mix_frag.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_mix_frag.glsl new file mode 100644 index 00000000000..8f94a105332 --- /dev/null +++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_mix_frag.glsl @@ -0,0 +1,22 @@ + +out vec4 FragColor; + +uniform sampler2D wireColor; +uniform sampler2D wireDepth; +uniform sampler2D sceneDepth; +uniform float alpha; + +void main() +{ + ivec2 uv = ivec2(gl_FragCoord.xy); + float wire_depth = texelFetch(wireDepth, uv, 0).r; + float scene_depth = texelFetch(sceneDepth, uv, 0).r; + vec4 wire_color = texelFetch(wireColor, uv, 0).rgba; + + FragColor = wire_color; + + /* Modulate alpha if occluded */ + if (wire_depth > scene_depth) { + FragColor.a *= alpha; + } +} diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_points_vert.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_points_vert.glsl new file mode 100644 index 00000000000..3886213ce49 --- /dev/null +++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_points_vert.glsl @@ -0,0 +1,49 @@ + +uniform mat3 NormalMatrix; +uniform mat4 ProjectionMatrix; +uniform mat4 ModelViewMatrix; +uniform mat4 ModelViewProjectionMatrix; +uniform float ofs = 3e-5; + +in vec3 pos; +in ivec4 data; +#ifdef VERTEX_FACING +in vec3 vnor; +#endif + +out vec4 finalColor; + +void main() +{ + finalColor = colorVertex; + finalColor = ((data.x & VERTEX_SELECTED) != 0) ? colorVertexSelect : finalColor; + finalColor = ((data.x & VERTEX_ACTIVE) != 0) ? vec4(colorEditMeshActive.xyz, 1.0) : finalColor; + + gl_PointSize = sizeVertex * 2.0; + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + gl_Position.z -= ofs * ((ProjectionMatrix[3][3] == 0.0) ? 1.0 : 0.0); + + /* Make selected and active vertex always on top. */ + if ((data.x & VERTEX_SELECTED) != 0) { + gl_Position.z -= 1e-7; + } + if ((data.x & VERTEX_ACTIVE) != 0) { + gl_Position.z -= 1e-7; + } + +#ifdef VERTEX_FACING + vec4 vPos = ModelViewMatrix * vec4(pos, 1.0); + vec3 view_normal = normalize(NormalMatrix * vnor); + vec3 view_vec = (ProjectionMatrix[3][3] == 0.0) + ? normalize(vPos.xyz) + : vec3(0.0, 0.0, 1.0); + float facing = dot(view_vec, view_normal); + + finalColor.a *= 1.0 - abs(facing) * 0.4; +#endif + + if ((data.x & VERTEX_EXISTS) == 0) { + gl_Position = vec4(0.0); + gl_PointSize = 0.0; + } +} diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_vert.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_vert.glsl new file mode 100644 index 00000000000..e4268188e09 --- /dev/null +++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_vert.glsl @@ -0,0 +1,102 @@ + +/* Solid Wirefram implementation + * Mike Erwin, Clément Foucault */ + +uniform mat3 NormalMatrix; +uniform mat4 ProjectionMatrix; +uniform mat4 ModelViewMatrix; +uniform mat4 ModelViewProjectionMatrix; +uniform ivec4 dataMask = ivec4(0xFF); + +uniform float ofs = 1e-5; + +uniform isamplerBuffer dataBuffer; + +in vec3 pos; +#ifdef VERTEX_FACING +in vec3 vnor; +#endif + +#ifdef EDGE_FIX +in ivec4 data; + +out vec4 pPos; +out ivec4 vData; +# ifdef VERTEX_FACING +out float vFacing; +# endif + +void main() +{ + pPos = ModelViewProjectionMatrix * vec4(pos, 1.0); + pPos.z -= ofs * ((ProjectionMatrix[3][3] == 0.0) ? 1.0 : 0.0); + vData = data & dataMask; +# ifdef VERTEX_FACING + vec4 vpos = ModelViewMatrix * vec4(pos, 1.0); + vec3 view_normal = normalize(NormalMatrix * vnor); + vec3 view_vec = (ProjectionMatrix[3][3] == 0.0) + ? normalize(vpos.xyz) + : vec3(0.0, 0.0, 1.0); + vFacing = dot(view_vec, view_normal); +# endif +} + +#else /* EDGE_FIX */ + +flat out vec3 edgesCrease; +flat out vec3 edgesBweight; +flat out vec4 faceColor; +flat out ivec3 flag; +# ifdef VERTEX_SELECTION +out vec3 vertexColor; +# endif +# ifdef VERTEX_FACING +out float facing; +# endif + +out vec3 barycentric; + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + gl_Position.z -= ofs * ((ProjectionMatrix[3][3] == 0.0) ? 1.0 : 0.0); + + int v_0 = (gl_VertexID / 3) * 3; + int vidx = gl_VertexID % 3; + barycentric = vec3(equal(ivec3(0, 1, 2), ivec3(vidx))); + + /* Edge */ + ivec4 vData[3], data = ivec4(0); + ivec3 eflag; + for (int v = 0; v < 3; ++v) { + data = texelFetch(dataBuffer, v_0 + v); + vData[v] = data & dataMask; + flag[v] = eflag[v] = vData[v].y | (vData[v].x << 8); + edgesCrease[v] = vData[v].z / 255.0; + edgesBweight[v] = vData[v].w / 255.0; + } + + /* Face */ + if ((vData[0].x & FACE_ACTIVE) != 0) + faceColor = colorFaceSelect; + else if ((vData[0].x & FACE_SELECTED) != 0) + faceColor = colorFaceSelect; + else if ((vData[0].x & FACE_FREESTYLE) != 0) + faceColor = colorFaceFreestyle; + else + faceColor = colorFace; + +# ifdef VERTEX_SELECTION + vertexColor = EDIT_MESH_vertex_color(vData[vidx].x).rgb; +# endif +# ifdef VERTEX_FACING + vec4 vPos = ModelViewMatrix * vec4(pos, 1.0); + vec3 view_normal = normalize(NormalMatrix * vnor); + vec3 view_vec = (ProjectionMatrix[3][3] == 0.0) + ? normalize(vPos.xyz) + : vec3(0.0, 0.0, 1.0); + facing = dot(view_vec, view_normal); +# endif +} + +#endif diff --git a/source/blender/draw/modes/shaders/edit_normals_geom.glsl b/source/blender/draw/modes/shaders/edit_normals_geom.glsl new file mode 100644 index 00000000000..d17823f2f5a --- /dev/null +++ b/source/blender/draw/modes/shaders/edit_normals_geom.glsl @@ -0,0 +1,15 @@ + +layout(points) in; +layout(line_strip, max_vertices=2) out; + +flat in vec4 v1[1]; +flat in vec4 v2[1]; + +void main() +{ + gl_Position = v1[0]; + EmitVertex(); + gl_Position = v2[0]; + EmitVertex(); + EndPrimitive(); +} diff --git a/source/blender/draw/modes/shaders/edit_normals_vert.glsl b/source/blender/draw/modes/shaders/edit_normals_vert.glsl new file mode 100644 index 00000000000..3ce7e618511 --- /dev/null +++ b/source/blender/draw/modes/shaders/edit_normals_vert.glsl @@ -0,0 +1,30 @@ + +uniform mat4 ModelViewProjectionMatrix; +uniform mat3 NormalMatrix; +uniform mat4 ProjectionMatrix; +uniform float normalSize; + +in vec3 pos; + +#ifdef LOOP_NORMALS +in vec3 lnor; +#define nor lnor + +#elif defined(FACE_NORMALS) +in vec4 norAndFlag; +#define nor norAndFlag.xyz +#else + +in vec3 vnor; +#define nor vnor +#endif + +flat out vec4 v1; +flat out vec4 v2; + +void main() +{ + v1 = ModelViewProjectionMatrix * vec4(pos, 1.0); + vec3 n = normalize(NormalMatrix * nor); /* viewspace */ + v2 = v1 + ProjectionMatrix * vec4(n * normalSize, 0.0); +} diff --git a/source/blender/draw/modes/shaders/object_empty_axes_vert.glsl b/source/blender/draw/modes/shaders/object_empty_axes_vert.glsl new file mode 100644 index 00000000000..10e8805ef55 --- /dev/null +++ b/source/blender/draw/modes/shaders/object_empty_axes_vert.glsl @@ -0,0 +1,29 @@ + +uniform mat4 ViewProjectionMatrix; +uniform vec3 screenVecs[3]; + +/* ---- Instantiated Attribs ---- */ +in float axis; /* position on the axis. [0.0-1.0] is X axis, [1.0-2.0] is Y, etc... */ +in vec2 screenPos; + +/* ---- Per instance Attribs ---- */ +in vec3 color; +in float size; +in mat4 InstanceModelMatrix; + +flat out vec4 finalColor; + +void main() +{ + float draw_size = 4.0 * size; + vec3 chosen_axis = InstanceModelMatrix[int(axis)].xyz; + vec3 loc = InstanceModelMatrix[3].xyz; + vec3 wpos = loc + chosen_axis * fract(axis) * draw_size; + vec3 spos = screenVecs[0].xyz * screenPos.x + screenVecs[1].xyz * screenPos.y; + /* Scale uniformly by axis length */ + spos *= length(chosen_axis) * draw_size; + + gl_Position = ViewProjectionMatrix * vec4(wpos + spos, 1.0); + + finalColor = vec4(color, 1.0); +} diff --git a/source/blender/draw/modes/shaders/object_empty_image_frag.glsl b/source/blender/draw/modes/shaders/object_empty_image_frag.glsl new file mode 100644 index 00000000000..e47b28d80c6 --- /dev/null +++ b/source/blender/draw/modes/shaders/object_empty_image_frag.glsl @@ -0,0 +1,33 @@ + +flat in vec4 finalColor; + +#ifndef USE_WIRE +in vec2 texCoord_interp; +#endif + +out vec4 fragColor; + +#ifndef USE_WIRE +uniform sampler2D image; +#endif + +uniform int depthMode; + +void main() +{ +#ifdef USE_WIRE + fragColor = finalColor; +#else + fragColor = finalColor * texture(image, texCoord_interp); +#endif + + if (depthMode == DEPTH_BACK) { + gl_FragDepth = 0.999999; + } + else if (depthMode == DEPTH_FRONT) { + gl_FragDepth = 0.000001; + } + else if (depthMode == DEPTH_UNCHANGED) { + gl_FragDepth = gl_FragCoord.z; + } +} diff --git a/source/blender/draw/modes/shaders/object_empty_image_vert.glsl b/source/blender/draw/modes/shaders/object_empty_image_vert.glsl new file mode 100644 index 00000000000..3469e37358e --- /dev/null +++ b/source/blender/draw/modes/shaders/object_empty_image_vert.glsl @@ -0,0 +1,32 @@ +uniform mat4 ModelViewProjectionMatrix; +uniform float aspectX; +uniform float aspectY; +uniform float size; +uniform vec2 offset; +#ifdef USE_WIRE +uniform vec3 color; +#else +uniform vec4 objectColor; +#endif + +in vec2 texCoord; +in vec2 pos; + +flat out vec4 finalColor; + +#ifndef USE_WIRE +out vec2 texCoord_interp; +#endif + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4( + (pos + offset) * (size * vec2(aspectX, aspectY)), + 0.0, 1.0); +#ifdef USE_WIRE + finalColor = vec4(color, 1.0); +#else + texCoord_interp = texCoord; + finalColor = objectColor; +#endif +} diff --git a/source/blender/draw/modes/shaders/object_grid_frag.glsl b/source/blender/draw/modes/shaders/object_grid_frag.glsl new file mode 100644 index 00000000000..35a95e809df --- /dev/null +++ b/source/blender/draw/modes/shaders/object_grid_frag.glsl @@ -0,0 +1,246 @@ + +/* Infinite grid + * Author: Clément Foucault */ + +out vec4 FragColor; + +uniform mat4 ProjectionMatrix; +uniform vec3 cameraPos; +uniform vec3 planeNormal; +uniform vec3 planeAxes; +uniform vec3 eye; +uniform vec4 gridSettings; +uniform vec2 viewportSize; +uniform vec4 screenvecs[3]; +uniform float lineKernel = 0.0; +uniform float gridOneOverLogSubdiv; +uniform sampler2D depthBuffer; + +#define gridDistance gridSettings.x +#define gridResolution gridSettings.y +#define gridScale gridSettings.z +#define gridSubdiv gridSettings.w + +uniform int gridFlag; + +#define AXIS_X (1 << 0) +#define AXIS_Y (1 << 1) +#define AXIS_Z (1 << 2) +#define GRID (1 << 3) +#define PLANE_XY (1 << 4) +#define PLANE_XZ (1 << 5) +#define PLANE_YZ (1 << 6) +#define GRID_BACK (1 << 9) /* grid is behind objects */ + +#define M_1_SQRTPI 0.5641895835477563 /* 1/sqrt(pi) */ + +/** + * We want to know how much a pixel is covered by a line. + * We replace the square pixel with acircle of the same area and try to find the intersection area. + * The area we search is the circular segment. https://en.wikipedia.org/wiki/Circular_segment + * The formula for the area uses inverse trig function and is quite complexe. + * Instead, we approximate it by using the smoothstep function and a 1.05 factor to the disc radius. + **/ +#define DISC_RADIUS (M_1_SQRTPI * 1.05) +#define GRID_LINE_SMOOTH_START (0.5 - DISC_RADIUS) +#define GRID_LINE_SMOOTH_END (0.5 + DISC_RADIUS) + +float get_grid(vec2 co, vec2 fwidthCos, float grid_size) +{ + float half_size = grid_size / 2.0; + /* triangular wave pattern, amplitude is [0, half_size] */ + vec2 grid_domain = abs(mod(co + half_size, grid_size) - half_size); + /* modulate by the absolute rate of change of the coordinates + * (make lines have the same width under perspective) */ + grid_domain /= fwidthCos; + + /* collapse waves */ + float line_dist = min(grid_domain.x, grid_domain.y); + + return 1.0 - smoothstep(GRID_LINE_SMOOTH_START, GRID_LINE_SMOOTH_END, line_dist - lineKernel); +} + +vec3 get_axes(vec3 co, vec3 fwidthCos, float line_size) +{ + vec3 axes_domain = abs(co); + /* modulate by the absolute rate of change of the coordinates + * (make line have the same width under perspective) */ + axes_domain /= fwidthCos; + + return 1.0 - smoothstep(GRID_LINE_SMOOTH_START, GRID_LINE_SMOOTH_END, axes_domain - (line_size + lineKernel)); +} + +vec3 get_floor_pos(vec2 uv, out vec3 wPos) +{ + vec3 camera_vec, camera_pos, corner_pos; + vec3 floored_pos = planeAxes * floor(screenvecs[2].xyz); + corner_pos = screenvecs[2].xyz - floored_pos; + + vec3 pixel_pos = corner_pos + uv.x * screenvecs[0].xyz + uv.y * screenvecs[1].xyz; + + /* if perspective */ + if (ProjectionMatrix[3][3] == 0.0) { + camera_pos = cameraPos - floored_pos; + camera_vec = normalize(pixel_pos - camera_pos); + } + else { + camera_pos = pixel_pos; + camera_vec = normalize(eye); + } + + float plane_normal_dot_camera_vec = dot(planeNormal, camera_vec); + float p = -dot(planeNormal, camera_pos); + if (plane_normal_dot_camera_vec != 0) { + p /= plane_normal_dot_camera_vec; + } + vec3 plane = camera_pos + camera_vec * p; + + /* fix residual imprecision */ + plane *= planeAxes; + + /* Recover non-offseted world position */ + wPos = plane + floored_pos; + + return plane; +} + +void main() +{ + vec2 sPos = gl_FragCoord.xy / viewportSize; /* Screen [0,1] position */ + + /* To reduce artifacts, use a local version of the positions + * to compute derivatives since they are not position dependent. + * This gets rid of the blocky artifacts. Unfortunately we still + * need the world position for the grid to scale properly from the origin. */ + vec3 gPos, wPos; /* Grid pos., World pos. */ + gPos = get_floor_pos(sPos, wPos); + + vec3 fwidthPos = fwidth(gPos); + + float dist, fade; + /* if persp */ + if (ProjectionMatrix[3][3] == 0.0) { + vec3 viewvec = cameraPos - wPos; + dist = length(viewvec); + viewvec /= dist; + + float angle; + if ((gridFlag & PLANE_XZ) != 0) { + angle = viewvec.y; + } + else if ((gridFlag & PLANE_YZ) != 0) { + angle = viewvec.x; + } + else { + angle = viewvec.z; + } + + angle = 1.0 - abs(angle); + angle *= angle; + fade = 1.0 - angle * angle; + fade *= 1.0 - smoothstep(0.0, gridDistance, dist - gridDistance); + } + else { + dist = abs(gl_FragCoord.z * 2.0 - 1.0); + fade = 1.0 - smoothstep(0.0, 0.5, dist - 0.5); + dist = 1.0; /* avoid branch after */ + + if ((gridFlag & PLANE_XY) != 0) { + float angle = 1.0 - abs(eye.z); + dist = 1.0 + angle * 2.0; + angle *= angle; + fade *= 1.0 - angle * angle; + } + } + + if ((gridFlag & GRID) != 0) { + float grid_res = log(dist * gridResolution) * gridOneOverLogSubdiv; + + float blend = fract(-max(grid_res, 0.0)); + float lvl = floor(grid_res); + + /* from biggest to smallest */ + float scaleA = gridScale * pow(gridSubdiv, max(lvl - 1.0, 0.0)); + float scaleB = gridScale * pow(gridSubdiv, max(lvl + 0.0, 0.0)); + float scaleC = gridScale * pow(gridSubdiv, max(lvl + 1.0, 1.0)); + + vec2 grid_pos, grid_fwidth; + if ((gridFlag & PLANE_XZ) != 0) { + grid_pos = wPos.xz; + grid_fwidth = fwidthPos.xz; + } + else if ((gridFlag & PLANE_YZ) != 0) { + grid_pos = wPos.yz; + grid_fwidth = fwidthPos.yz; + } + else { + grid_pos = wPos.xy; + grid_fwidth = fwidthPos.xy; + } + + float gridA = get_grid(grid_pos, grid_fwidth, scaleA); + float gridB = get_grid(grid_pos, grid_fwidth, scaleB); + float gridC = get_grid(grid_pos, grid_fwidth, scaleC); + + FragColor = colorGrid; + FragColor.a *= gridA * blend; + FragColor = mix(FragColor, mix(colorGrid, colorGridEmphasise, blend), gridB); + FragColor = mix(FragColor, colorGridEmphasise, gridC); + } + else { + FragColor = vec4(colorGrid.rgb, 0.0); + } + + if ((gridFlag & (AXIS_X | AXIS_Y | AXIS_Z)) != 0) { + /* Setup axes 'domains' */ + vec3 axes_dist, axes_fwidth; + + if ((gridFlag & AXIS_X) != 0) { + axes_dist.x = dot(wPos.yz, planeAxes.yz); + axes_fwidth.x = dot(fwidthPos.yz, planeAxes.yz); + } + if ((gridFlag & AXIS_Y) != 0) { + axes_dist.y = dot(wPos.xz, planeAxes.xz); + axes_fwidth.y = dot(fwidthPos.xz, planeAxes.xz); + } + if ((gridFlag & AXIS_Z) != 0) { + axes_dist.z = dot(wPos.xy, planeAxes.xy); + axes_fwidth.z = dot(fwidthPos.xy, planeAxes.xy); + } + + /* Computing all axes at once using vec3 */ + vec3 axes = get_axes(axes_dist, axes_fwidth, 0.1); + + if ((gridFlag & AXIS_X) != 0) { + FragColor.a = max(FragColor.a, axes.x); + FragColor.rgb = (axes.x < 1e-8) ? FragColor.rgb : colorGridAxisX.rgb; + } + if ((gridFlag & AXIS_Y) != 0) { + FragColor.a = max(FragColor.a, axes.y); + FragColor.rgb = (axes.y < 1e-8) ? FragColor.rgb : colorGridAxisY.rgb; + } + if ((gridFlag & AXIS_Z) != 0) { + FragColor.a = max(FragColor.a, axes.z); + FragColor.rgb = (axes.z < 1e-8) ? FragColor.rgb : colorGridAxisZ.rgb; + } + } + + /* Add a small bias so the grid will always + * be on top of a mesh with the same depth. */ + float grid_depth = gl_FragCoord.z - 6e-8 - fwidth(gl_FragCoord.z); + float scene_depth = texture(depthBuffer, sPos).r; + if ((gridFlag & GRID_BACK) != 0) { + fade *= (scene_depth == 1.0) ? 1.0 : 0.0; + } + else { + /* Manual, non hard, depth test: + * Progressively fade the grid below occluders + * (avoids popping visuals due to depth buffer precision) */ + /* Harder settings tend to flicker more, + * but have less "see through" appearance. */ + const float test_hardness = 1e7; + fade *= 1.0 - clamp((grid_depth - scene_depth) * test_hardness, 0.0, 1.0); + } + + FragColor.a *= fade; +} diff --git a/source/blender/draw/modes/shaders/object_grid_vert.glsl b/source/blender/draw/modes/shaders/object_grid_vert.glsl new file mode 100644 index 00000000000..a346973a597 --- /dev/null +++ b/source/blender/draw/modes/shaders/object_grid_vert.glsl @@ -0,0 +1,63 @@ + +/* Infinite grid + * Clément Foucault */ + +uniform mat4 ViewProjectionMatrix; +uniform mat4 ProjectionMatrix; +uniform vec3 cameraPos; +uniform vec4 gridSettings; + +#define gridDistance gridSettings.x +#define gridResolution gridSettings.y +#define gridScale gridSettings.z +#define gridSubdiv gridSettings.w + +uniform int gridFlag; + +#define PLANE_XY (1 << 4) +#define PLANE_XZ (1 << 5) +#define PLANE_YZ (1 << 6) +#define CLIP_Z_POS (1 << 7) +#define CLIP_Z_NEG (1 << 8) + +in vec3 pos; + +void main() +{ + vec3 vert_pos, proj_camera_pos; + + /* Project camera pos to the needed plane */ + if ((gridFlag & PLANE_XY) != 0) { + vert_pos = vec3(pos.x, pos.y, 0.0); + proj_camera_pos = vec3(cameraPos.x, cameraPos.y, 0.0); + } + else if ((gridFlag & PLANE_XZ) != 0) { + vert_pos = vec3(pos.x, 0.0, pos.y); + proj_camera_pos = vec3(cameraPos.x, 0.0, cameraPos.z); + } + else { + vert_pos = vec3(0.0, pos.x, pos.y); + proj_camera_pos = vec3(0.0, cameraPos.y, cameraPos.z); + } + + /* if persp */ + if (ProjectionMatrix[3][3] == 0.0) { + vert_pos *= gridDistance * 2.0; + } + else { + float viewdist = 1.0 / min(abs(ProjectionMatrix[0][0]), abs(ProjectionMatrix[1][1])); + vert_pos *= viewdist * gridDistance * 2.0; + } + + vec3 realPos = proj_camera_pos + vert_pos; + + /* Used for additional Z axis */ + if ((gridFlag & CLIP_Z_POS) != 0) { + realPos.z = max(realPos.z, 0.0); + } + if ((gridFlag & CLIP_Z_NEG) != 0) { + realPos.z = min(-realPos.z, 0.0); + } + + gl_Position = ViewProjectionMatrix * vec4(realPos, 1.0); +} diff --git a/source/blender/draw/modes/shaders/object_lightprobe_grid_vert.glsl b/source/blender/draw/modes/shaders/object_lightprobe_grid_vert.glsl new file mode 100644 index 00000000000..bcdf5adca55 --- /dev/null +++ b/source/blender/draw/modes/shaders/object_lightprobe_grid_vert.glsl @@ -0,0 +1,34 @@ + +uniform mat4 ViewProjectionMatrix; + +uniform float sphere_size; +uniform ivec3 grid_resolution; +uniform vec3 corner; +uniform vec3 increment_x; +uniform vec3 increment_y; +uniform vec3 increment_z; +uniform vec3 screen_vecs[2]; + +uniform int call_id; /* we don't want the builtin callId which would be 0. */ +uniform int baseId; + +flat out uint finalId; + +void main() +{ + vec3 ls_cell_location; + /* Keep in sync with update_irradiance_probe */ + ls_cell_location.z = float(gl_VertexID % grid_resolution.z); + ls_cell_location.y = float((gl_VertexID / grid_resolution.z) % grid_resolution.y); + ls_cell_location.x = float(gl_VertexID / (grid_resolution.z * grid_resolution.y)); + + vec3 ws_cell_location = corner + + (increment_x * ls_cell_location.x + + increment_y * ls_cell_location.y + + increment_z * ls_cell_location.z); + + gl_Position = ViewProjectionMatrix * vec4(ws_cell_location, 1.0); + gl_PointSize = 2.0f; + + finalId = uint(baseId + call_id); +} diff --git a/source/blender/draw/modes/shaders/object_mball_handles_vert.glsl b/source/blender/draw/modes/shaders/object_mball_handles_vert.glsl new file mode 100644 index 00000000000..b1c10feb62c --- /dev/null +++ b/source/blender/draw/modes/shaders/object_mball_handles_vert.glsl @@ -0,0 +1,34 @@ + +/* This shader takes a 2D shape, puts it in 3D Object space such that is stays aligned with view, + * and scales the shape according to per-instance attributes + * Note that if the stiffness is zero, it assumes the scale is directly multiplied by the radius */ + + +uniform mat4 ViewProjectionMatrix; +uniform vec3 screen_vecs[2]; + +/* ---- Instantiated Attribs ---- */ +in vec2 pos; + +/* ---- Per instance Attribs ---- */ +in mat3x4 ScaleTranslationMatrix; +in float radius; +in vec3 color; + +flat out vec4 finalColor; + +void main() +{ + mat3 Scamat = mat3(ScaleTranslationMatrix); + vec4 world_pos = vec4( + ScaleTranslationMatrix[0][3], + ScaleTranslationMatrix[1][3], + ScaleTranslationMatrix[2][3], + 1.0); + + vec3 screen_pos = screen_vecs[0].xyz * pos.x + screen_vecs[1].xyz * pos.y; + world_pos.xyz += Scamat * (screen_pos * radius); + + gl_Position = ViewProjectionMatrix * world_pos; + finalColor = vec4(color, 1.0); +} diff --git a/source/blender/draw/modes/shaders/object_outline_detect_frag.glsl b/source/blender/draw/modes/shaders/object_outline_detect_frag.glsl new file mode 100644 index 00000000000..dbf7f411a20 --- /dev/null +++ b/source/blender/draw/modes/shaders/object_outline_detect_frag.glsl @@ -0,0 +1,88 @@ + +in vec4 uvcoordsvar; + +out vec4 FragColor; + +uniform usampler2D outlineId; +uniform sampler2D outlineDepth; +uniform sampler2D sceneDepth; + +uniform int idOffsets[3]; + +uniform float alphaOcclu; +uniform vec2 viewportSize; + +vec4 convert_id_to_color(int id) +{ + if (id == 0) { + return vec4(0.0); + } + if (id < idOffsets[1]) { + return colorActive; + } + else if (id < idOffsets[2]) { + return colorSelect; + } + else { + return colorTransform; + } +} + +void main() +{ + ivec2 texel = ivec2(gl_FragCoord.xy); + +#ifdef GPU_ARB_texture_gather + vec2 texel_size = 1.0 / vec2(textureSize(outlineId, 0).xy); + vec2 uv = ceil(gl_FragCoord.xy) * texel_size; + + /* Samples order is CW starting from top left. */ + uvec4 tmp1 = textureGather(outlineId, uv - texel_size); + uvec4 tmp2 = textureGather(outlineId, uv); + + uint ref_id = tmp1.y; + uvec4 id = uvec4(tmp1.xz, tmp2.xz); +#else + uvec4 id; + uint ref_id = texelFetch(outlineId, texel, 0).r; + id.x = texelFetchOffset(outlineId, texel, 0, ivec2(-1, 0)).r; + id.y = texelFetchOffset(outlineId, texel, 0, ivec2( 0, -1)).r; + id.z = texelFetchOffset(outlineId, texel, 0, ivec2( 0, 1)).r; + id.w = texelFetchOffset(outlineId, texel, 0, ivec2( 1, 0)).r; +#endif + +#ifdef WIRE + /* We want only 2px outlines. */ + /* TODO optimize, don't sample if we don't need to. */ + id.xy = uvec2(ref_id); +#endif + + bool outline = any(notEqual(id, uvec4(ref_id))); + + ivec2 depth_texel = texel; + /* If texel is an outline but has no valid id ... + * replace id and depth texel by a valid one. + * This keeps the outline thickness consistent everywhere. */ + if (ref_id == 0u && outline) { + depth_texel = (id.x != 0u) ? texel + ivec2(-1, 0) : depth_texel; + depth_texel = (id.y != 0u) ? texel + ivec2( 0, -1) : depth_texel; + depth_texel = (id.z != 0u) ? texel + ivec2( 0, 1) : depth_texel; + depth_texel = (id.w != 0u) ? texel + ivec2( 1, 0) : depth_texel; + + ref_id = (id.x != 0u) ? id.x : ref_id; + ref_id = (id.y != 0u) ? id.y : ref_id; + ref_id = (id.z != 0u) ? id.z : ref_id; + ref_id = (id.w != 0u) ? id.w : ref_id; + } + + float ref_depth = texelFetch(outlineDepth, depth_texel, 0).r; + float scene_depth = texelFetch(sceneDepth, depth_texel, 0).r; + + /* Avoid bad cases of zfighting for occlusion only. */ + const float epsilon = 3.0 / 8388608.0; + bool occluded = (ref_depth > scene_depth + epsilon); + + FragColor = convert_id_to_color(int(ref_id)); + FragColor.a *= (occluded) ? alphaOcclu : 1.0; + FragColor.a = (outline) ? FragColor.a : 0.0; +} diff --git a/source/blender/draw/modes/shaders/object_outline_expand_frag.glsl b/source/blender/draw/modes/shaders/object_outline_expand_frag.glsl new file mode 100644 index 00000000000..7e288cde236 --- /dev/null +++ b/source/blender/draw/modes/shaders/object_outline_expand_frag.glsl @@ -0,0 +1,37 @@ + +in vec4 uvcoordsvar; + +out vec4 FragColor; + +uniform sampler2D outlineColor; + +uniform float alpha; +uniform bool doExpand; + +void main() +{ + ivec2 uv = ivec2(gl_FragCoord.xy); + FragColor = texelFetch(outlineColor, uv, 0).rgba; + + vec4 color[4]; + color[0] = texelFetchOffset(outlineColor, uv, 0, ivec2( 1, 0)).rgba; + color[1] = texelFetchOffset(outlineColor, uv, 0, ivec2( 0, 1)).rgba; + color[2] = texelFetchOffset(outlineColor, uv, 0, ivec2(-1, 0)).rgba; + color[3] = texelFetchOffset(outlineColor, uv, 0, ivec2( 0, -1)).rgba; + + vec4 values = vec4(color[0].a, color[1].a, color[2].a, color[3].a); + + vec4 tests = step(vec4(1e-6), values); /* (color.a != 0.0) */ + bvec4 btests = equal(tests, vec4(1.0)); + + if (FragColor.a != 0.0) { + return; + } + + FragColor = (btests.x) ? color[0] : FragColor; + FragColor = (btests.y) ? color[1] : FragColor; + FragColor = (btests.z) ? color[2] : FragColor; + FragColor = (btests.w) ? color[3] : FragColor; + + FragColor.a *= (!doExpand) ? 0.0 : 1.0; +} diff --git a/source/blender/draw/modes/shaders/object_outline_prepass_frag.glsl b/source/blender/draw/modes/shaders/object_outline_prepass_frag.glsl new file mode 100644 index 00000000000..776adb787ad --- /dev/null +++ b/source/blender/draw/modes/shaders/object_outline_prepass_frag.glsl @@ -0,0 +1,10 @@ +uniform int callId; +uniform int baseId; + +/* using uint because 16bit uint can contain more ids than int. */ +out uint outId; + +void main() +{ + outId = uint(baseId + callId); +} diff --git a/source/blender/draw/modes/shaders/object_outline_prepass_geom.glsl b/source/blender/draw/modes/shaders/object_outline_prepass_geom.glsl new file mode 100644 index 00000000000..1fa0a9137c0 --- /dev/null +++ b/source/blender/draw/modes/shaders/object_outline_prepass_geom.glsl @@ -0,0 +1,40 @@ + +layout(lines_adjacency) in; +layout(line_strip, max_vertices = 2) out; + +uniform mat4 ProjectionMatrix; + +in vec4 pPos[]; +in vec3 vPos[]; + +void main() +{ + bool is_persp = (ProjectionMatrix[3][3] == 0.0); + + vec3 view_vec = (is_persp) ? normalize(vPos[1]) : vec3(0.0, 0.0, -1.0); + + vec3 v10 = vPos[0] - vPos[1]; + vec3 v12 = vPos[2] - vPos[1]; + vec3 v13 = vPos[3] - vPos[1]; + + vec3 n0 = cross(v12, v10); + vec3 n3 = cross(v13, v12); + + float fac0 = dot(view_vec, n0); + float fac3 = dot(view_vec, n3); + + /* If both adjacent verts are facing the camera the same way, + * then it isn't an outline edge. */ + if (sign(fac0) == sign(fac3)) + return; + + /* Don't outline if concave edge. */ + /* That would hide a lot of non useful edge but it flickers badly. + * TODO revisit later... */ + // if (dot(n0, v13) > 0.01) + // return; + + gl_Position = pPos[1]; EmitVertex(); + gl_Position = pPos[2]; EmitVertex(); + EndPrimitive(); +} diff --git a/source/blender/draw/modes/shaders/object_outline_prepass_vert.glsl b/source/blender/draw/modes/shaders/object_outline_prepass_vert.glsl new file mode 100644 index 00000000000..ba824a7c007 --- /dev/null +++ b/source/blender/draw/modes/shaders/object_outline_prepass_vert.glsl @@ -0,0 +1,16 @@ + +uniform mat4 ModelViewMatrix; +uniform mat4 ModelViewProjectionMatrix; + +in vec3 pos; + +out vec4 pPos; +out vec3 vPos; + +void main() +{ + vPos = (ModelViewMatrix * vec4(pos, 1.0)).xyz; + pPos = ModelViewProjectionMatrix * vec4(pos, 1.0); + /* Small bias to always be on top of the geom. */ + pPos.z -= 1e-3; +} diff --git a/source/blender/draw/modes/shaders/object_outline_resolve_frag.glsl b/source/blender/draw/modes/shaders/object_outline_resolve_frag.glsl new file mode 100644 index 00000000000..964ebe72e81 --- /dev/null +++ b/source/blender/draw/modes/shaders/object_outline_resolve_frag.glsl @@ -0,0 +1,27 @@ + +in vec4 uvcoordsvar; + +out vec4 FragColor; + +uniform sampler2D outlineBluredColor; +uniform vec2 rcpDimensions; + +void main() +{ +#ifdef USE_FXAA + float aa_alpha = FxaaPixelShader( + uvcoordsvar.st, + outlineBluredColor, + rcpDimensions, + 1.0, + 0.166, + 0.0833 + ).r; +#endif + + FragColor = texture(outlineBluredColor, uvcoordsvar.st).rgba; + +#ifdef USE_FXAA + FragColor.a = aa_alpha; +#endif +} diff --git a/source/blender/draw/modes/shaders/object_particle_dot_frag.glsl b/source/blender/draw/modes/shaders/object_particle_dot_frag.glsl new file mode 100644 index 00000000000..e8bf7884701 --- /dev/null +++ b/source/blender/draw/modes/shaders/object_particle_dot_frag.glsl @@ -0,0 +1,52 @@ + +uniform vec3 color; +uniform vec3 outlineColor; +uniform sampler1D ramp; + +in vec4 radii; +flat in float finalVal; + +out vec4 fragColor; + +void main() { + float dist = length(gl_PointCoord - vec2(0.5)); + +// transparent outside of point +// --- 0 --- +// smooth transition +// --- 1 --- +// pure outline color +// --- 2 --- +// smooth transition +// --- 3 --- +// pure point color +// ... +// dist = 0 at center of point + + float midStroke = 0.5 * (radii[1] + radii[2]); + + if (dist > midStroke) { + if (finalVal < 0.0) { + fragColor.rgb = outlineColor; + } + else { + fragColor.rgb = texture(ramp, finalVal).rgb; + } + + fragColor.a = mix(1.0, 0.0, smoothstep(radii[1], radii[0], dist)); + } + else { + if (finalVal < 0.0) { + fragColor.rgb = mix(color, outlineColor, smoothstep(radii[3], radii[2], dist)); + } + else { + fragColor.rgb = texture(ramp, finalVal).rgb; + } + + fragColor.a = 1.0; + } + + if (fragColor.a == 0.0) { + discard; + } +} diff --git a/source/blender/draw/modes/shaders/object_particle_dot_vert.glsl b/source/blender/draw/modes/shaders/object_particle_dot_vert.glsl new file mode 100644 index 00000000000..6dfc212a776 --- /dev/null +++ b/source/blender/draw/modes/shaders/object_particle_dot_vert.glsl @@ -0,0 +1,35 @@ + +uniform mat4 ModelViewMatrix; +uniform mat4 ProjectionMatrix; +uniform float pixel_size; +uniform float size; + +in vec3 pos; +in float val; + +out vec4 radii; +flat out float finalVal; + +void main() { + gl_Position = ModelViewMatrix * vec4(pos, 1.0); + + float psize = (ProjectionMatrix[3][3] == 0.0) ? (size / (-gl_Position.z * pixel_size)) : (size / pixel_size); + + gl_PointSize = psize; + + // calculate concentric radii in pixels + float radius = 0.5 * psize; + + // start at the outside and progress toward the center + radii[0] = radius; + radii[1] = radius - 1.0; + radii[2] = radius - 1.0; + radii[3] = radius - 2.0; + + // convert to PointCoord units + radii /= psize; + + gl_Position = ProjectionMatrix * gl_Position; + + finalVal = val; +} diff --git a/source/blender/draw/modes/shaders/object_particle_prim_vert.glsl b/source/blender/draw/modes/shaders/object_particle_prim_vert.glsl new file mode 100644 index 00000000000..54ae319307a --- /dev/null +++ b/source/blender/draw/modes/shaders/object_particle_prim_vert.glsl @@ -0,0 +1,56 @@ + +uniform mat4 ModelViewProjectionMatrix; +uniform mat4 ViewProjectionMatrix; +uniform mat4 ModelViewMatrix; +uniform mat4 ProjectionMatrix; +uniform int screen_space; +uniform float draw_size; +uniform vec3 color; +uniform sampler1D ramp; + +in vec3 pos; +in vec4 rot; +in float val; +in vec3 inst_pos; +in int axis; + +flat out vec4 finalColor; + +vec3 rotate(vec3 vec, vec4 quat) +{ + /* The quaternion representation here stores the w component in the first index */ + return vec + 2.0 * cross(quat.yzw, cross(quat.yzw, vec) + quat.x * vec); +} + +void main() +{ + if (screen_space == 1) { + gl_Position = ModelViewMatrix * vec4(pos, 1.0) + vec4(inst_pos * draw_size, 0.0); + gl_Position = ProjectionMatrix * gl_Position; + } + else { + float size = draw_size; + + if (axis > -1) { + size *= 2; + } + + gl_Position = ModelViewProjectionMatrix * vec4(pos + rotate(inst_pos * size, rot), 1.0); + } + +#ifdef USE_AXIS + if (axis == 0) + finalColor = vec4(1.0, 0.0, 0.0, 1.0); + else if (axis == 1) + finalColor = vec4(0.0, 1.0, 0.0, 1.0); + else + finalColor = vec4(0.0, 0.0, 1.0, 1.0); +#else + if (val < 0.0) { + finalColor = vec4(color, 1.0); + } + else { + finalColor = vec4(texture(ramp, val).rgb, 1.0); + } +#endif +} diff --git a/source/blender/draw/modes/shaders/overlay_face_orientation_frag.glsl b/source/blender/draw/modes/shaders/overlay_face_orientation_frag.glsl new file mode 100644 index 00000000000..5b0ad7863d1 --- /dev/null +++ b/source/blender/draw/modes/shaders/overlay_face_orientation_frag.glsl @@ -0,0 +1,10 @@ +uniform vec3 color_towards = vec3(0.0, 0.0, 1.0); +uniform vec3 color_outwards = vec3(1.0, 0.0, 0.0); + +out vec4 fragColor; + + +void main() +{ + fragColor = vec4(gl_FrontFacing ? color_towards: color_outwards, 0.7); +} diff --git a/source/blender/draw/modes/shaders/overlay_face_orientation_vert.glsl b/source/blender/draw/modes/shaders/overlay_face_orientation_vert.glsl new file mode 100644 index 00000000000..d8a72f28eee --- /dev/null +++ b/source/blender/draw/modes/shaders/overlay_face_orientation_vert.glsl @@ -0,0 +1,7 @@ +uniform mat4 ModelViewProjectionMatrix; +in vec3 pos; + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); +} diff --git a/source/blender/draw/modes/shaders/overlay_face_wireframe_frag.glsl b/source/blender/draw/modes/shaders/overlay_face_wireframe_frag.glsl new file mode 100644 index 00000000000..69af4858a48 --- /dev/null +++ b/source/blender/draw/modes/shaders/overlay_face_wireframe_frag.glsl @@ -0,0 +1,57 @@ +#ifndef SELECT_EDGES +uniform vec3 wireColor; +uniform vec3 rimColor; + +in float facing; +in vec3 barycentric; + +# ifdef LIGHT_EDGES +flat in vec3 edgeSharpness; +# endif + +out vec4 fragColor; +#endif + +float min_v3(vec3 v) { return min(v.x, min(v.y, v.z)); } +float max_v3(vec3 v) { return max(v.x, max(v.y, v.z)); } + +/* In pixels */ +uniform float wireSize = 0.0; /* Expands the core of the wire (part that is 100% wire color) */ +const float wire_smooth = 1.2; /* Smoothing distance after the 100% core. */ + +/* Alpha constants could be exposed in the future. */ +const float front_alpha = 0.35; +const float rim_alpha = 0.75; + +void main() +{ +#ifndef SELECT_EDGES + vec3 dx = dFdx(barycentric); + vec3 dy = dFdy(barycentric); + vec3 d = vec3( + length(vec2(dx.x, dy.x)), + length(vec2(dx.y, dy.y)), + length(vec2(dx.z, dy.z)) + ); + vec3 dist_to_edge = barycentric / d; + +# ifdef LIGHT_EDGES + vec3 fac = abs(dist_to_edge); +# else + float fac = min_v3(abs(dist_to_edge)); +# endif + + fac = smoothstep(wireSize + wire_smooth, wireSize, fac); + + float facing_clamped = clamp((gl_FrontFacing) ? facing : -facing, 0.0, 1.0); + + vec3 final_front_col = mix(rimColor, wireColor, 0.05); + fragColor = mix(vec4(rimColor, rim_alpha), vec4(final_front_col, front_alpha), facing_clamped); + +# ifdef LIGHT_EDGES + fragColor.a *= max_v3(fac * edgeSharpness); +# else + fragColor.a *= fac; +# endif +#endif +} diff --git a/source/blender/draw/modes/shaders/overlay_face_wireframe_geom.glsl b/source/blender/draw/modes/shaders/overlay_face_wireframe_geom.glsl new file mode 100644 index 00000000000..8abb6ecc737 --- /dev/null +++ b/source/blender/draw/modes/shaders/overlay_face_wireframe_geom.glsl @@ -0,0 +1,127 @@ + +/* This shader is only used for intel GPU where the Geom shader is faster + * than doing everything thrice in the vertex shader. */ + +layout(triangles) in; +#ifdef SELECT_EDGES +layout(line_strip, max_vertices = 6) out; +#else +layout(triangle_strip, max_vertices = 3) out; +#endif + +uniform vec2 wireStepParam; + +in vec2 ssPos[]; +in float facingOut[]; + +#ifndef SELECT_EDGES +out vec3 barycentric; +out float facing; +#endif + +#ifdef LIGHT_EDGES +in vec3 obPos[]; +in vec3 vNor[]; +in float forceEdge[]; + +# ifndef SELECT_EDGES +flat out vec3 edgeSharpness; +# endif +#endif + +#define NO_EDGE vec3(10000.0); + +vec3 get_edge_normal(vec3 n1, vec3 n2, vec3 edge) +{ + edge = normalize(edge); + vec3 n = n1 + n2; + float p = dot(edge, n); + return normalize(n - p * edge); +} + +float get_edge_sharpness(vec3 fnor, vec3 vnor) +{ + float sharpness = abs(dot(fnor, vnor)); + return smoothstep(wireStepParam.x, wireStepParam.y, sharpness); +} + +vec3 get_barycentric(bvec3 do_edge, const int v) +{ + int v_n = v; + int v_n1 = (v + 1) % 3; + int v_n2 = (v + 2) % 3; + vec3 bary; + bary[v_n] = do_edge[v_n] ? 0.0 : 1.0; + bary[v_n1] = 1.0; + bary[v_n2] = do_edge[v_n2] ? 0.0 : 1.0; + return bary; +} + +void main(void) +{ + vec3 facings = vec3(facingOut[0], facingOut[1], facingOut[2]); + bvec3 do_edge = greaterThan(abs(facings), vec3(1.0)); + facings = fract(facings) - clamp(-sign(facings), 0.0, 1.0); + +#ifdef SELECT_EDGES + vec3 edgeSharpness; +#endif + +#ifdef LIGHT_EDGES + vec3 edges[3]; + edges[0] = obPos[1] - obPos[0]; + edges[1] = obPos[2] - obPos[1]; + edges[2] = obPos[0] - obPos[2]; + vec3 fnor = normalize(cross(edges[0], -edges[2])); + + edgeSharpness.x = get_edge_sharpness(fnor, get_edge_normal(vNor[0], vNor[1], edges[0])); + edgeSharpness.y = get_edge_sharpness(fnor, get_edge_normal(vNor[1], vNor[2], edges[1])); + edgeSharpness.z = get_edge_sharpness(fnor, get_edge_normal(vNor[2], vNor[0], edges[2])); + edgeSharpness.x = (forceEdge[0] == 1.0) ? 1.0 : edgeSharpness.x; + edgeSharpness.y = (forceEdge[1] == 1.0) ? 1.0 : edgeSharpness.y; + edgeSharpness.z = (forceEdge[2] == 1.0) ? 1.0 : edgeSharpness.z; +#endif + +#ifdef SELECT_EDGES + const float edge_select_threshold = 0.3; + if (edgeSharpness.x > edge_select_threshold) { + gl_Position = gl_in[0].gl_Position; + EmitVertex(); + gl_Position = gl_in[1].gl_Position; + EmitVertex(); + EndPrimitive(); + } + + if (edgeSharpness.y > edge_select_threshold) { + gl_Position = gl_in[1].gl_Position; + EmitVertex(); + gl_Position = gl_in[2].gl_Position; + EmitVertex(); + EndPrimitive(); + } + + if (edgeSharpness.z > edge_select_threshold) { + gl_Position = gl_in[2].gl_Position; + EmitVertex(); + gl_Position = gl_in[0].gl_Position; + EmitVertex(); + EndPrimitive(); + } +#else + barycentric = get_barycentric(do_edge, 0); + gl_Position = gl_in[0].gl_Position; + facing = facings.x; + EmitVertex(); + + barycentric = get_barycentric(do_edge, 1); + gl_Position = gl_in[1].gl_Position; + facing = facings.y; + EmitVertex(); + + barycentric = get_barycentric(do_edge, 2); + gl_Position = gl_in[2].gl_Position; + facing = facings.z; + EmitVertex(); + EndPrimitive(); +#endif +} diff --git a/source/blender/draw/modes/shaders/overlay_face_wireframe_vert.glsl b/source/blender/draw/modes/shaders/overlay_face_wireframe_vert.glsl new file mode 100644 index 00000000000..828bc551cad --- /dev/null +++ b/source/blender/draw/modes/shaders/overlay_face_wireframe_vert.glsl @@ -0,0 +1,177 @@ + +uniform mat4 ModelViewProjectionMatrix; +uniform mat4 ModelViewMatrix; +uniform mat4 ProjectionMatrix; +uniform mat3 NormalMatrix; + +uniform vec2 wireStepParam; +uniform float nearDist; + +uniform samplerBuffer vertData; +uniform usamplerBuffer faceIds; + +#ifdef USE_SCULPT +in vec3 pos; +in vec3 nor; +#endif + +float short_to_unit_float(uint s) +{ + int value = int(s) & 0x7FFF; + if ((s & 0x8000u) != 0u) { + value |= ~0x7FFF; + } + return float(value) / float(0x7FFF); +} + +vec3 get_vertex_nor(uint id) +{ + int v_id = int(id) * 5; /* See vertex format for explanation. */ + /* Fetch compressed normal as float and unpack them. */ + vec2 data; + data.x = texelFetch(vertData, v_id + 3).r; + data.y = texelFetch(vertData, v_id + 4).r; + + uvec2 udata = floatBitsToUint(data); + + vec3 nor; + nor.x = short_to_unit_float(udata.x & 0xFFFFu); + nor.y = short_to_unit_float(udata.x >> 16u); + nor.z = short_to_unit_float(udata.y & 0xFFFFu); + return nor; +} + +vec3 get_vertex_pos(uint id) +{ + int v_id = int(id) * 5; /* See vertex format for explanation. */ + vec3 pos; + pos.x = texelFetch(vertData, v_id).r; + pos.y = texelFetch(vertData, v_id + 1).r; + pos.z = texelFetch(vertData, v_id + 2).r; + return pos; +} + +vec3 get_edge_normal(vec3 n1, vec3 n2, vec3 edge) +{ + edge = normalize(edge); + vec3 n = n1 + n2; + float p = dot(edge, n); + return normalize(n - p * edge); +} + +float get_edge_sharpness(vec3 fnor, vec3 vnor) +{ + float sharpness = abs(dot(fnor, vnor)); + return smoothstep(wireStepParam.x, wireStepParam.y, sharpness); +} + +#ifdef USE_GEOM_SHADER + +# ifdef LIGHT_EDGES +out vec3 obPos; +out vec3 vNor; +out float forceEdge; +# endif +out float facingOut; /* abs(facing) > 1.0 if we do edge */ + +void main() +{ +# ifndef USE_SCULPT + uint v_id = texelFetch(faceIds, gl_VertexID).r; + + bool do_edge = (v_id & (1u << 30u)) != 0u; + bool force_edge = (v_id & (1u << 31u)) != 0u; + v_id = (v_id << 2u) >> 2u; + + vec3 pos = get_vertex_pos(v_id); + vec3 nor = get_vertex_nor(v_id); +# else + const bool do_edge = true; + const bool force_edge = false; +# endif + + facingOut = normalize(NormalMatrix * nor).z; + facingOut += (do_edge) ? ((facingOut > 0.0) ? 2.0 : -2.0) : 0.0; + + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + +# ifdef LIGHT_EDGES + obPos = pos; + vNor = nor; + forceEdge = float(force_edge); /* meh, could try to also encode it in facingOut */ +# endif +} + +#else /* USE_GEOM_SHADER */ + +# ifdef LIGHT_EDGES +flat out vec3 edgeSharpness; +# endif +out float facing; +out vec3 barycentric; + +void main() +{ + int v_0 = (gl_VertexID / 3) * 3; + int v_n = gl_VertexID % 3; + int v_n1 = (gl_VertexID + 1) % 3; + int v_n2 = (gl_VertexID + 2) % 3; + + /* Getting the same positions for each of the 3 verts. */ + uvec3 v_id; + v_id.x = texelFetch(faceIds, v_0).r; + v_id.y = texelFetch(faceIds, v_0 + 1).r; + v_id.z = texelFetch(faceIds, v_0 + 2).r; + + bvec3 do_edge, force_edge; + do_edge.x = (v_id.x & (1u << 30u)) != 0u; + do_edge.y = (v_id.y & (1u << 30u)) != 0u; + do_edge.z = (v_id.z & (1u << 30u)) != 0u; + force_edge.x = (v_id.x & (1u << 31u)) != 0u; + force_edge.y = (v_id.y & (1u << 31u)) != 0u; + force_edge.z = (v_id.z & (1u << 31u)) != 0u; + v_id = (v_id << 2u) >> 2u; + + vec3 pos[3]; + vec4 p_pos[3]; + + pos[v_n] = get_vertex_pos(v_id[v_n]); + gl_Position = p_pos[v_n] = ModelViewProjectionMatrix * vec4(pos[v_n], 1.0); + + bvec3 bary = equal(ivec3(0, 1, 2), ivec3(v_n1)); + /* This is equivalent to component wise : (do_edge ? bary : 1.0) */ + barycentric = vec3(lessThanEqual(ivec3(do_edge), ivec3(bary))); + +# ifndef LIGHT_EDGES + vec3 nor = get_vertex_nor(v_id[v_n]); +# else + p_pos[v_n1] = ModelViewProjectionMatrix * vec4(pos[v_n1], 1.0); + p_pos[v_n2] = ModelViewProjectionMatrix * vec4(pos[v_n2], 1.0); + + pos[v_n1] = get_vertex_pos(v_id[v_n1]); + pos[v_n2] = get_vertex_pos(v_id[v_n2]); + + vec3 edges[3]; + edges[0] = pos[1] - pos[0]; + edges[1] = pos[2] - pos[1]; + edges[2] = pos[0] - pos[2]; + vec3 fnor = normalize(cross(edges[0], -edges[2])); + + vec3 nors[3]; + nors[0] = get_vertex_nor(v_id.x); + nors[1] = get_vertex_nor(v_id.y); + nors[2] = get_vertex_nor(v_id.z); + edgeSharpness.x = get_edge_sharpness(fnor, get_edge_normal(nors[0], nors[1], edges[0])); + edgeSharpness.y = get_edge_sharpness(fnor, get_edge_normal(nors[1], nors[2], edges[1])); + edgeSharpness.z = get_edge_sharpness(fnor, get_edge_normal(nors[2], nors[0], edges[2])); + edgeSharpness.x = force_edge.x ? 1.0 : edgeSharpness.x; + edgeSharpness.y = force_edge.y ? 1.0 : edgeSharpness.y; + edgeSharpness.z = force_edge.z ? 1.0 : edgeSharpness.z; + + vec3 nor = nors[v_n]; +# endif + + facing = normalize(NormalMatrix * nor).z; +} + +#endif /* USE_GEOM_SHADER */ diff --git a/source/blender/draw/modes/shaders/paint_texture_frag.glsl b/source/blender/draw/modes/shaders/paint_texture_frag.glsl new file mode 100644 index 00000000000..4305e20ce7b --- /dev/null +++ b/source/blender/draw/modes/shaders/paint_texture_frag.glsl @@ -0,0 +1,11 @@ + +in vec2 uv_interp; +out vec4 fragColor; + +uniform sampler2D image; +uniform float alpha = 1.0; + +void main() +{ + fragColor = vec4(texture(image, uv_interp).rgb, alpha); +} diff --git a/source/blender/draw/modes/shaders/paint_texture_vert.glsl b/source/blender/draw/modes/shaders/paint_texture_vert.glsl new file mode 100644 index 00000000000..4ce12e048fa --- /dev/null +++ b/source/blender/draw/modes/shaders/paint_texture_vert.glsl @@ -0,0 +1,15 @@ + +uniform mat4 ModelViewProjectionMatrix; + +in vec2 uv; +in vec3 pos; + +out vec2 uv_interp; + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + + uv_interp = uv; + +} diff --git a/source/blender/draw/modes/shaders/paint_vert_frag.glsl b/source/blender/draw/modes/shaders/paint_vert_frag.glsl new file mode 100644 index 00000000000..5ea8c11ff9a --- /dev/null +++ b/source/blender/draw/modes/shaders/paint_vert_frag.glsl @@ -0,0 +1,26 @@ + +flat in int finalFlag; +out vec4 fragColor; + +#define VERTEX_SELECTED (1 << 0) +#define VERTEX_HIDE (1 << 4) + +void main() +{ + if (bool(finalFlag & VERTEX_HIDE)) { + discard; + } + + vec2 centered = gl_PointCoord - vec2(0.5); + float dist_squared = dot(centered, centered); + const float rad_squared = 0.25; + const vec4 colSel = vec4(1.0, 1.0, 1.0, 1.0); + const vec4 colUnsel = vec4(0.0, 0.0, 0.0, 1.0); + + // round point with jaggy edges + if (dist_squared > rad_squared) { + discard; + } + + fragColor = bool(finalFlag & VERTEX_SELECTED) ? colSel : colUnsel; +} diff --git a/source/blender/draw/modes/shaders/paint_vertex_frag.glsl b/source/blender/draw/modes/shaders/paint_vertex_frag.glsl new file mode 100644 index 00000000000..3ff264a5e22 --- /dev/null +++ b/source/blender/draw/modes/shaders/paint_vertex_frag.glsl @@ -0,0 +1,18 @@ + +in vec3 finalColor; + +out vec4 fragColor; +uniform float white_factor = 1.0; + +vec3 linear_to_srgb_attrib(vec3 c) { + c = max(c, vec3(0.0)); + vec3 c1 = c * 12.92; + vec3 c2 = 1.055 * pow(c, vec3(1.0 / 2.4)) - 0.055; + return mix(c1, c2, step(vec3(0.0031308), c)); +} + +void main() +{ + fragColor.rgb = mix(linear_to_srgb_attrib(finalColor), vec3(1.0), white_factor); + fragColor.a = 1.0; +} diff --git a/source/blender/draw/modes/shaders/paint_vertex_vert.glsl b/source/blender/draw/modes/shaders/paint_vertex_vert.glsl new file mode 100644 index 00000000000..178f77c6b9c --- /dev/null +++ b/source/blender/draw/modes/shaders/paint_vertex_vert.glsl @@ -0,0 +1,21 @@ + +uniform mat4 ModelViewProjectionMatrix; + +in vec3 pos; +in vec3 color; + +out vec3 finalColor; + +vec3 srgb_to_linear_attrib(vec3 c) { + c = max(c, vec3(0.0)); + vec3 c1 = c * (1.0 / 12.92); + vec3 c2 = pow((c + 0.055) * (1.0 / 1.055), vec3(2.4)); + return mix(c1, c2, step(vec3(0.04045), c)); +} + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + + finalColor = srgb_to_linear_attrib(color); +} diff --git a/source/blender/draw/modes/shaders/paint_weight_frag.glsl b/source/blender/draw/modes/shaders/paint_weight_frag.glsl new file mode 100644 index 00000000000..faa36f5535e --- /dev/null +++ b/source/blender/draw/modes/shaders/paint_weight_frag.glsl @@ -0,0 +1,97 @@ + +in vec2 weight_interp; /* (weight, alert) */ + +out vec4 fragColor; + +uniform float opacity = 1.0; +uniform sampler1D colorramp; + +uniform bool drawContours = false; + +float contours(float value, float steps, float width_px, float max_rel_width, float gradient) +{ + /* Minimum visible and minimum full strength line width in screen space for fade out. */ + const float min_width_px = 1.3, fade_width_px = 2.3; + /* Line is thinner towards the increase in the weight gradient by this factor. */ + const float hi_bias = 2.0; + + /* Don't draw lines at 0 or 1. */ + float rel_value = value * steps; + + if (rel_value < 0.5 || rel_value > steps - 0.5) + return 0.0; + + /* Check if completely invisible due to fade out. */ + float rel_gradient = gradient * steps; + float rel_min_width = min_width_px * rel_gradient; + + if (max_rel_width <= rel_min_width) + return 0.0; + + /* Main shape of the line, accounting for width bias and maximum weight space width. */ + float rel_width = width_px * rel_gradient; + + float offset = fract(rel_value + 0.5) - 0.5; + + float base_alpha = 1.0 - max(offset * hi_bias, -offset) / min(max_rel_width, rel_width); + + /* Line fadeout when too thin in screen space. */ + float rel_fade_width = fade_width_px * rel_gradient; + + float fade_alpha = (max_rel_width - rel_min_width) / (rel_fade_width - rel_min_width); + + return clamp(base_alpha, 0.0, 1.0) * clamp(fade_alpha, 0.0, 1.0); +} + +vec4 contour_grid(float weight, float weight_gradient) +{ + /* Fade away when the gradient is too low to avoid big fills and noise. */ + float flt_eps = max(1e-8, 1e-6 * weight); + + if (weight_gradient <= flt_eps) + return vec4(0.0); + + /* Three levels of grid lines */ + float grid10 = contours(weight, 10.0, 5.0, 0.3, weight_gradient); + float grid100 = contours(weight, 100.0, 3.5, 0.35, weight_gradient) * 0.6; + float grid1000 = contours(weight, 1000.0, 2.5, 0.4, weight_gradient) * 0.25; + + /* White lines for 0.1 and 0.01, and black for 0.001 */ + vec4 grid = vec4(1.0) * max(grid10, grid100); + + grid.a = max(grid.a, grid1000); + + return grid * clamp((weight_gradient - flt_eps) / flt_eps, 0.0, 1.0); +} + +void main() +{ + float alert = weight_interp.y; + vec4 color; + + /* Missing vertex group alert color. Uniform in practice. */ + if (alert > 1.1) { + color = colorVertexMissingData; + } + /* Weights are available */ + else { + float weight = weight_interp.x; + vec4 weight_color = texture(colorramp, weight, 0); + + /* Contour display */ + if (drawContours) { + /* This must be executed uniformly for all fragments */ + float weight_gradient = length(vec2(dFdx(weight), dFdy(weight))); + + vec4 grid = contour_grid(weight, weight_gradient); + + weight_color = grid + weight_color * (1 - grid.a); + } + + /* Zero weight alert color. Nonlinear blend to reduce impact. */ + color = mix(weight_color, colorVertexUnreferenced, alert * alert); + } + + /* mix with 1.0 -> is like opacity when using multiply blend mode */ + fragColor = vec4(mix(vec3(1.0), color.rgb, opacity), 1.0); +} diff --git a/source/blender/draw/modes/shaders/paint_weight_vert.glsl b/source/blender/draw/modes/shaders/paint_weight_vert.glsl new file mode 100644 index 00000000000..78a3695c82c --- /dev/null +++ b/source/blender/draw/modes/shaders/paint_weight_vert.glsl @@ -0,0 +1,15 @@ + +uniform mat4 ModelViewProjectionMatrix; + +in float weight; +in vec3 pos; + +out vec2 weight_interp; /* (weight, alert) */ + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + + /* Separate actual weight and alerts for independent interpolation */ + weight_interp = max(vec2(weight, -weight), 0.0); +} diff --git a/source/blender/draw/modes/shaders/paint_wire_frag.glsl b/source/blender/draw/modes/shaders/paint_wire_frag.glsl new file mode 100644 index 00000000000..c5d6198fc21 --- /dev/null +++ b/source/blender/draw/modes/shaders/paint_wire_frag.glsl @@ -0,0 +1,25 @@ + +flat in int finalFlag; +out vec4 fragColor; + +#define VERTEX_SELECTED (1 << 0) +#define VERTEX_HIDE (1 << 4) + +void main() +{ + if (bool(finalFlag & VERTEX_HIDE)) { + discard; + } + + /* Apply depth offset by taking slope and distance into account. */ + gl_FragDepth = gl_FragCoord.z - mix(exp2(-10), exp2(-23), gl_FragCoord.z) - 2.0 * fwidth(gl_FragCoord.z); + +#ifdef VERTEX_MODE + vec4 colSel = colorEdgeSelect; + colSel.rgb = clamp(colSel.rgb - 0.2, 0.0, 1.0); +#else + const vec4 colSel = vec4(1.0, 1.0, 1.0, 1.0); +#endif + + fragColor = bool(finalFlag & VERTEX_SELECTED) ? colSel : colorWire; +} diff --git a/source/blender/draw/modes/shaders/paint_wire_vert.glsl b/source/blender/draw/modes/shaders/paint_wire_vert.glsl new file mode 100644 index 00000000000..253c21745e2 --- /dev/null +++ b/source/blender/draw/modes/shaders/paint_wire_vert.glsl @@ -0,0 +1,14 @@ + +uniform mat4 ModelViewProjectionMatrix; + +in vec3 pos; +in int data; + +flat out int finalFlag; + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + + finalFlag = data; +} diff --git a/source/blender/draw/modes/shaders/particle_strand_frag.glsl b/source/blender/draw/modes/shaders/particle_strand_frag.glsl new file mode 100644 index 00000000000..8bb213dbd30 --- /dev/null +++ b/source/blender/draw/modes/shaders/particle_strand_frag.glsl @@ -0,0 +1,23 @@ +uniform mat4 ModelViewProjectionMatrix; + +in vec4 finalColor; +#ifdef USE_POINTS +in vec2 radii; +#endif + +out vec4 fragColor; + +void main() +{ + fragColor = finalColor; + +#ifdef USE_POINTS + float dist = length(gl_PointCoord - vec2(0.5)); + + fragColor.a = mix(finalColor.a, 0.0, smoothstep(radii[1], radii[0], dist)); + + if (fragColor.a == 0.0) { + discard; + } +#endif +} diff --git a/source/blender/draw/modes/shaders/particle_strand_vert.glsl b/source/blender/draw/modes/shaders/particle_strand_vert.glsl new file mode 100644 index 00000000000..9db62a581cb --- /dev/null +++ b/source/blender/draw/modes/shaders/particle_strand_vert.glsl @@ -0,0 +1,73 @@ + +uniform mat4 ModelViewProjectionMatrix; + +in vec3 pos; +in float color; + +out vec4 finalColor; +#ifdef USE_POINTS +out vec2 radii; +#endif + +vec3 weight_to_rgb(float weight) +{ + vec3 r_rgb; + float blend = ((weight / 2.0) + 0.5); + + if (weight <= 0.25) { /* blue->cyan */ + r_rgb[0] = 0.0; + r_rgb[1] = blend * weight * 4.0; + r_rgb[2] = blend; + } + else if (weight <= 0.50) { /* cyan->green */ + r_rgb[0] = 0.0; + r_rgb[1] = blend; + r_rgb[2] = blend * (1.0 - ((weight - 0.25) * 4.0)); + } + else if (weight <= 0.75) { /* green->yellow */ + r_rgb[0] = blend * ((weight - 0.50) * 4.0); + r_rgb[1] = blend; + r_rgb[2] = 0.0; + } + else if (weight <= 1.0) { /* yellow->red */ + r_rgb[0] = blend; + r_rgb[1] = blend * (1.0 - ((weight - 0.75) * 4.0)); + r_rgb[2] = 0.0; + } + else { + /* exceptional value, unclamped or nan, + * avoid uninitialized memory use */ + r_rgb[0] = 1.0; + r_rgb[1] = 0.0; + r_rgb[2] = 1.0; + } + + return r_rgb; +} + +#define DECOMPRESS_RANGE 1.0039 + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + +#ifdef USE_WEIGHT + finalColor = vec4(weight_to_rgb(color * DECOMPRESS_RANGE), 1.0); +#else + finalColor = mix(colorWire, colorEdgeSelect, color); +#endif + +#ifdef USE_POINTS + gl_PointSize = sizeVertex; + + /* calculate concentric radii in pixels */ + float radius = 0.5 * sizeVertex; + + /* start at the outside and progress toward the center */ + radii[0] = radius; + radii[1] = radius - 1.0; + + /* convert to PointCoord units */ + radii /= sizeVertex; +#endif +} diff --git a/source/blender/draw/modes/shaders/sculpt_mask_vert.glsl b/source/blender/draw/modes/shaders/sculpt_mask_vert.glsl new file mode 100644 index 00000000000..e76d21eb43a --- /dev/null +++ b/source/blender/draw/modes/shaders/sculpt_mask_vert.glsl @@ -0,0 +1,19 @@ + +uniform mat4 ModelViewProjectionMatrix; + +in vec3 pos; +in float msk; + +#ifdef SHADE_FLAT +flat out vec4 finalColor; +#else +out vec4 finalColor; +#endif + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + + float mask = 1.0 - msk * 0.75; + finalColor = vec4(mask, mask, mask, 1.0); +} diff --git a/source/blender/draw/modes/shaders/volume_velocity_vert.glsl b/source/blender/draw/modes/shaders/volume_velocity_vert.glsl new file mode 100644 index 00000000000..574c434920e --- /dev/null +++ b/source/blender/draw/modes/shaders/volume_velocity_vert.glsl @@ -0,0 +1,115 @@ + +uniform mat4 ModelViewProjectionMatrix; + +uniform sampler3D velocityX; +uniform sampler3D velocityY; +uniform sampler3D velocityZ; +uniform float displaySize = 1.0; +uniform float slicePosition; +uniform int sliceAxis; /* -1 is no slice, 0 is X, 1 is Y, 2 is Z. */ + +flat out vec4 finalColor; + +const vec3 corners[4] = vec3[4]( + vec3(0.0, 0.2, -0.5), + vec3(-0.2 * 0.866, -0.2 * 0.5, -0.5), + vec3(0.2 * 0.866, -0.2 * 0.5, -0.5), + vec3(0.0, 0.0, 0.5) +); + +const int indices[12] = int[12](0, 1, 1, 2, 2, 0, 0, 3, 1, 3, 2, 3); + +/* Straight Port from BKE_defvert_weight_to_rgb() + * TODO port this to a color ramp. */ +vec3 weight_to_color(float weight) +{ + vec3 r_rgb = vec3(0.0); + float blend = ((weight / 2.0) + 0.5); + + if (weight <= 0.25) { /* blue->cyan */ + r_rgb.g = blend * weight * 4.0; + r_rgb.b = blend; + } + else if (weight <= 0.50) { /* cyan->green */ + r_rgb.g = blend; + r_rgb.b = blend * (1.0 - ((weight - 0.25) * 4.0)); + } + else if (weight <= 0.75) { /* green->yellow */ + r_rgb.r = blend * ((weight - 0.50) * 4.0); + r_rgb.g = blend; + } + else if (weight <= 1.0) { /* yellow->red */ + r_rgb.r = blend; + r_rgb.g = blend * (1.0 - ((weight - 0.75) * 4.0)); + } + else { + /* exceptional value, unclamped or nan, + * avoid uninitialized memory use */ + r_rgb = vec3(1.0, 0.0, 1.0); + } + + return r_rgb; +} + +mat3 rotation_from_vector(vec3 v) +{ + /* Add epsilon to avoid NaN. */ + vec3 N = normalize(v + 1e-8); + vec3 UpVector = abs(N.z) < 0.99999 ? vec3(0.0,0.0,1.0) : vec3(1.0,0.0,0.0); + vec3 T = normalize(cross(UpVector, N)); + vec3 B = cross(N, T); + return mat3(T, B, N); +} + +void main() +{ +#ifdef USE_NEEDLE + int cell = gl_VertexID / 12; +#else + int cell = gl_VertexID / 2; +#endif + + ivec3 volume_size = textureSize(velocityX, 0); + float voxel_size = 1.0 / float(max(max(volume_size.x, volume_size.y), volume_size.z)); + + ivec3 cell_ofs = ivec3(0); + ivec3 cell_div = volume_size; + if (sliceAxis == 0) { + cell_ofs.x = int(slicePosition * float(volume_size.x)); + cell_div.x = 1; + } + else if (sliceAxis == 1) { + cell_ofs.y = int(slicePosition * float(volume_size.y)); + cell_div.y = 1; + } + else if (sliceAxis == 2) { + cell_ofs.z = int(slicePosition * float(volume_size.z)); + cell_div.z = 1; + } + + ivec3 cell_co; + cell_co.x = cell % cell_div.x; + cell_co.y = (cell / cell_div.x) % cell_div.y; + cell_co.z = cell / (cell_div.x * cell_div.y); + cell_co += cell_ofs; + + vec3 pos = (vec3(cell_co) + 0.5) / vec3(volume_size); + pos = pos * 2.0 - 1.0; + + vec3 velocity; + velocity.x = texelFetch(velocityX, cell_co, 0).r; + velocity.y = texelFetch(velocityY, cell_co, 0).r; + velocity.z = texelFetch(velocityZ, cell_co, 0).r; + + finalColor = vec4(weight_to_color(length(velocity)), 1.0); + +#ifdef USE_NEEDLE + mat3 rot_mat = rotation_from_vector(velocity); + vec3 rotated_pos = rot_mat * corners[indices[gl_VertexID % 12]]; + pos += rotated_pos * length(velocity) * displaySize * voxel_size; +#else + pos += (((gl_VertexID % 2) == 1) ? velocity : vec3(0.0)) * displaySize * voxel_size; +#endif + + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); +} |