Created
April 27, 2023 12:55
-
-
Save Andrej730/93dd9411620a4e4880b228aef71095ed to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# minimal shader example to create smoothed polylines on Metal | |
import bpy | |
import gpu | |
from gpu_extras.batch import batch_for_shader | |
polyline_vert_glsl = """ | |
// emits 6 vertex per each line | |
// see: https://projects.blender.org/blender/blender/issues/107332 | |
#pragma USE_SSBO_VERTEX_FETCH(TriangleList, 6) | |
/* Clips point to near clip plane before perspective divide. */ | |
vec4 clip_line_point_homogeneous_space(vec4 p, vec4 q) | |
{ | |
if (p.z < -p.w) { | |
/* Just solves p + (q - p) * A; for A when p.z / p.w = -1.0. */ | |
float denom = q.z - p.z + q.w - p.w; | |
if (denom == 0.0) { | |
/* No solution. */ | |
return p; | |
} | |
float A = (-p.z - p.w) / denom; | |
p = p + (q - p) * A; | |
} | |
return p; | |
} | |
void do_vertex(int index, vec4 pos, vec2 ofs, float flip) | |
{ | |
smoothline = flip * (lineWidth + SMOOTH_WIDTH * float(lineSmooth)) * 0.5; | |
gl_Position = pos; | |
gl_Position.xy += flip * ofs * pos.w; | |
} | |
void main() | |
{ | |
/** Determine output quad primitive structure. */ | |
/* Index of the quad primitive. Each quad corresponds to one line in the input primitive. */ | |
int quad_id = gl_VertexID / 6; | |
/* Determine vertex within the quad (A, B, C)(A, C, D). */ | |
int quad_vertex_id = gl_VertexID % 6; | |
uint src_index_a; | |
uint src_index_b; | |
if (vertex_fetch_get_input_prim_type() == GPU_PRIM_LINE_STRIP) { | |
src_index_a = quad_id; | |
src_index_b = quad_id + 1; | |
} | |
else if (vertex_fetch_get_input_prim_type() == GPU_PRIM_LINES) { | |
src_index_a = quad_id * 2; | |
src_index_b = quad_id * 2 + 1; | |
} | |
else if (vertex_fetch_get_input_prim_type() == GPU_PRIM_LINE_LOOP) { | |
src_index_a = quad_id; | |
src_index_b = quad_id + 1; | |
if (quad_id == vertex_fetch_get_input_vert_count() - 1) { | |
src_index_b = 0; | |
} | |
} | |
else { | |
src_index_a = 0; | |
src_index_b = 0; | |
} | |
/* Fetch input attributes for line prims -- either provided as vec2 or vec3 -- So we need to | |
* query the type. */ | |
vec3 in_pos0, in_pos1; | |
in_pos0 = vec3(0.0); | |
in_pos1 = vec3(0.0); | |
if (vertex_fetch_get_attr_type(pos) == GPU_SHADER_ATTR_TYPE_VEC4) { | |
in_pos0 = vertex_fetch_attribute(src_index_a, pos, vec4).xyz; | |
in_pos1 = vertex_fetch_attribute(src_index_b, pos, vec4).xyz; | |
} | |
else if (vertex_fetch_get_attr_type(pos) == GPU_SHADER_ATTR_TYPE_VEC3) { | |
in_pos0 = vertex_fetch_attribute(src_index_a, pos, vec3); | |
in_pos1 = vertex_fetch_attribute(src_index_b, pos, vec3); | |
} | |
else if (vertex_fetch_get_attr_type(pos) == GPU_SHADER_ATTR_TYPE_VEC2) { | |
in_pos0 = vec3(vertex_fetch_attribute(src_index_a, pos, vec2), 0.0); | |
in_pos1 = vec3(vertex_fetch_attribute(src_index_b, pos, vec2), 0.0); | |
} | |
/* Calculate Vertex shader for both points in Line. */ | |
vec4 out_pos0 = ModelViewProjectionMatrix * vec4(in_pos0, 1.0); | |
vec4 out_pos1 = ModelViewProjectionMatrix * vec4(in_pos1, 1.0); | |
/*** Geometry Shader Alternative. ***/ | |
vec4 p0 = clip_line_point_homogeneous_space(out_pos0, out_pos1); | |
vec4 p1 = clip_line_point_homogeneous_space(out_pos1, out_pos0); | |
vec2 e = normalize(((p1.xy / p1.w) - (p0.xy / p0.w)) * viewportSize.xy); | |
vec2 ofs = vec2(-e.y, e.x); | |
ofs /= viewportSize.xy; | |
ofs *= lineWidth + SMOOTH_WIDTH * float(lineSmooth); | |
if (quad_vertex_id == 0) { | |
do_vertex(0, p0, ofs, 1.0); | |
} | |
else if (quad_vertex_id == 1 || quad_vertex_id == 3) { | |
do_vertex(0, p0, ofs, -1.0); | |
} | |
else if (quad_vertex_id == 2 || quad_vertex_id == 5) { | |
do_vertex(1, p1, ofs, 1.0); | |
} | |
else if (quad_vertex_id == 4) { | |
do_vertex(1, p1, ofs, -1.0); | |
} | |
} | |
""" | |
polyline_frag_glsl = """ | |
void main() | |
{ | |
fragColor = vec4(1.0, 1.0, 0.0, 1.0); | |
if (lineSmooth) { | |
fragColor.a *= clamp((lineWidth + SMOOTH_WIDTH) * 0.5 - abs(smoothline), 0.0, 1.0); | |
} | |
} | |
""" | |
from mathutils import Vector | |
coords = [(1, 1, 1), (-2, 0, 0), (-2, -1, 3), (0, 1, 1)] | |
offset_vector = Vector([0,0,1]) | |
coords = [Vector(c) - offset_vector for c in coords] | |
def draw(): | |
print('DRAW------------------') | |
vert_out = gpu.types.GPUStageInterfaceInfo("vert_interface") | |
vert_out.smooth('FLOAT', "smoothline") | |
shader_info = gpu.types.GPUShaderCreateInfo() | |
shader_info.define("SMOOTH_WIDTH", "2.0") | |
shader_info.push_constant('MAT4', "ModelViewProjectionMatrix") | |
shader_info.push_constant("FLOAT", "lineWidth") | |
shader_info.push_constant("INT", "lineSmooth") | |
shader_info.push_constant("VEC2", "viewportSize") | |
shader_info.vertex_in(0, 'VEC3', 'pos') | |
shader_info.vertex_out(vert_out) | |
shader_info.fragment_out(0, 'VEC4', 'fragColor') | |
shader_info.vertex_source(polyline_vert_glsl) | |
shader_info.fragment_source(polyline_frag_glsl) | |
shader = gpu.shader.create_from_info(shader_info) | |
batch = batch_for_shader(shader, 'LINES', {"pos": coords}) | |
shader.bind() | |
shader.uniform_float("lineWidth", 5.0) | |
shader.uniform_int("lineSmooth", 1) | |
region = bpy.context.area | |
shader.uniform_float("viewportSize", [region.width, region.height]) | |
gpu.state.blend_set("ALPHA") | |
batch.draw(shader) | |
bpy.types.SpaceView3D.draw_handler_add(draw, (), 'WINDOW', 'POST_VIEW') | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment