Skip to content

Commit

Permalink
Merge shader create info (#424)
Browse files Browse the repository at this point in the history
* Shaders: Add createinfo for uniform_color_image_2d

* Shaders:  Add createinfo for base_shaders and uniform_color_line_3d

Remove geometry shader for arbitrary line thickness as geometry shaders are not supported on metal

* Shaders: Move id_shader_3d to createinfo

* Selection: Add multisampling to preselection gizmo
  • Loading branch information
hlorus authored Nov 15, 2023
1 parent 0a62127 commit cba040a
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 142 deletions.
50 changes: 39 additions & 11 deletions gizmos/preselection.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,17 +56,45 @@ def test_select(self, context, location):
offscreen = global_data.offscreen
if not offscreen:
return -1
with offscreen.bind():
fb = gpu.state.active_framebuffer_get()
buffer = fb.read_color(mouse_x, mouse_y, 1, 1, 4, 0, "FLOAT")
r, g, b, alpha = buffer[0][0]

if alpha > 0:
index = rgb_to_index(r, g, b)
if index != global_data.hover:
global_data.hover = index
context.area.tag_redraw()
elif global_data.hover != -1:
# TODO: Read buffer only once
PICK_SIZE = 10
for x, y in get_spiral_coords(mouse_x, mouse_y, context.area.width, context.area.height, PICK_SIZE):
with offscreen.bind():
fb = gpu.state.active_framebuffer_get()
buffer = fb.read_color(x, y, 1, 1, 4, 0, "FLOAT")
r, g, b, alpha = buffer[0][0]

if alpha > 0:
index = rgb_to_index(r, g, b)
if index != global_data.hover:
global_data.hover = index
context.area.tag_redraw()
return -1

if global_data.hover != -1:
context.area.tag_redraw()
global_data.hover = -1
return -1


def _spiral(N, M):
x,y = 0,0
dx, dy = 0, -1

for dumb in range(N*M):
if abs(x) == abs(y) and [dx,dy] != [1,0] or x>0 and y == 1-x:
dx, dy = -dy, dx # corner, change direction

if abs(x)>N/2 or abs(y)>M/2: # non-square
dx, dy = -dy, dx # change direction
x, y = -y+dx, x+dy # jump

yield x, y
x, y = x+dx, y+dy

def get_spiral_coords(X: int, Y: int, width: int, height: int, radius: int = 0):
"""Returns a list of coordinates to check starting from given position spiraling out"""

for x, y in _spiral(radius+1,radius+1):
if 0 <= (X+x) <= width and 0 <= (Y+y) <= height:
yield (X+x, Y+y)
16 changes: 7 additions & 9 deletions model/base_entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ def line_width(self):

@property
def line_width_select(self):
return 20 * preferences.get_scale()
return 4 * preferences.get_scale()

def __str__(self):
_, local_index = breakdown_index(self.slvs_index)
Expand Down Expand Up @@ -230,11 +230,9 @@ def draw(self, context):

if not self.is_point():
shader.uniform_bool("dashed", (self.is_dashed(),))

if not self.is_point():
viewport = [context.area.width, context.area.height]
shader.uniform_float("Viewport", viewport)
shader.uniform_float("thickness", self.line_width)
shader.uniform_float("dash_width", 0.05)
shader.uniform_float("dash_factor", 0.3)
gpu.state.line_width_set(self.line_width)

batch.draw(shader)
gpu.shader.unbind()
Expand All @@ -256,10 +254,10 @@ def draw_id(self, context):

shader.uniform_float("color", (*index_to_rgb(self.slvs_index), 1.0))
if not self.is_point():
viewport = [context.area.width, context.area.height]
shader.uniform_float("Viewport", viewport)
shader.uniform_float("thickness", self.line_width_select)
# viewport = [context.area.width, context.area.height]
# shader.uniform_float("Viewport", viewport)
shader.uniform_bool("dashed", (False,))
gpu.state.line_width_set(self.line_width_select)

batch.draw(shader)
gpu.shader.unbind()
Expand Down
194 changes: 72 additions & 122 deletions shaders.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import gpu
from gpu.types import GPUShader
from gpu.types import GPUShader, GPUShaderCreateInfo, GPUStageInterfaceInfo
from gpu.shader import create_from_info
from bpy import app

import sys
Expand All @@ -16,28 +17,16 @@
class Shaders:

base_vertex_shader_3d = """
uniform mat4 ModelViewProjectionMatrix;
in vec3 pos;
void main() {
gl_Position = ModelViewProjectionMatrix * vec4(pos.xyz, 1.0f);
vec2 ssPos = vec2(gl_Position.xy / gl_Position.w);
stipple_start = stipple_pos = ssPos;
}
"""
base_fragment_shader_3d = """
uniform vec4 color;
uniform float dash_width = 10.0;
uniform float dash_factor = 0.40;
uniform vec2 Viewport;
uniform bool dashed = false;
noperspective in vec2 stipple_pos;
flat in vec2 stipple_start;
out vec4 fragColor;
void main() {
float aspect = Viewport.x/Viewport.y;
float distance_along_line = distance(stipple_pos, stipple_start);
float normalized_distance = fract(distance_along_line / dash_width);
Expand All @@ -56,6 +45,31 @@ class Shaders:
}
"""

@classmethod
def get_base_shader_3d_info(cls):

vert_out = GPUStageInterfaceInfo("stipple_pos_interface")
vert_out.no_perspective("VEC2", "stipple_pos")
vert_out.flat("VEC2", "stipple_start")

# NOTE: How to set default values?

shader_info = GPUShaderCreateInfo()
shader_info.push_constant("MAT4", "ModelViewProjectionMatrix")
shader_info.push_constant("VEC4", "color")
shader_info.push_constant("FLOAT", "dash_width")
shader_info.push_constant("FLOAT", "dash_factor")
# shader_info.push_constant("VEC2", "Viewport")
shader_info.push_constant("BOOL", "dashed")
shader_info.vertex_in(0, "VEC3", "pos")
shader_info.vertex_out(vert_out)
shader_info.fragment_out(0, "VEC4", "fragColor")

shader_info.vertex_source(cls.base_vertex_shader_3d)
shader_info.fragment_source(cls.base_fragment_shader_3d)

return shader_info

@staticmethod
@cache
def uniform_color_3d():
Expand All @@ -66,13 +80,21 @@ def uniform_color_3d():
@classmethod
@cache
def uniform_color_image_2d(cls):
vertex_shader = """
uniform mat4 ModelViewProjectionMatrix;
in vec2 pos;
in vec2 texCoord;
out vec2 v_texCoord;
vert_out = GPUStageInterfaceInfo("uniform_color_image_2d_interface")
vert_out.smooth("VEC2", "v_texCoord")

shader_info = GPUShaderCreateInfo()
shader_info.define("blender_srgb_to_framebuffer_space(a)", "a")
shader_info.push_constant("MAT4", "ModelViewProjectionMatrix")
shader_info.push_constant("VEC4", "color")
shader_info.vertex_in(0, "VEC2", "pos")
shader_info.vertex_in(1, "VEC2", "texCoord")
shader_info.sampler(0, "FLOAT_2D", "image")
shader_info.vertex_out(vert_out)
shader_info.fragment_out(0, "VEC4", "fragColor")

shader_info.vertex_source(
"""
void main()
{
gl_Position = (
Expand All @@ -81,24 +103,23 @@ def uniform_color_image_2d(cls):
v_texCoord = texCoord;
}
"""
fragment_shader = """
uniform vec4 color;
uniform sampler2D image;
in vec2 v_texCoord;
out vec4 fragColor;
)
shader_info.fragment_source(
"""
void main()
{
fragColor = blender_srgb_to_framebuffer_space(
texture(image, v_texCoord) * color
);
}
"""
return GPUShader(
vertex_shader,
fragment_shader,
)

shader = create_from_info(shader_info)
del vert_out
del shader_info
return shader

@classmethod
@cache
def id_line_3d(cls):
Expand All @@ -108,113 +129,42 @@ def id_line_3d(cls):
@classmethod
@cache
def uniform_color_line_3d(cls):
geometry_shader = """
layout(lines) in;
layout(triangle_strip, max_vertices = 10) out;

uniform mat4 ModelViewProjectionMatrix;
uniform vec2 Viewport;
uniform float thickness = float(0.1);
/* We leverage hardware interpolation to compute distance along the line. */
noperspective out vec2 stipple_pos; /* In screen space */
flat out vec2 stipple_start; /* In screen space */
out vec2 mTexCoord;
out float alpha;
float aspect = Viewport.x/Viewport.y;
vec2 pxVec = vec2(1.0/Viewport.x,1.0/Viewport.y);
float minLength = length(pxVec);
vec2 get_line_width(vec2 normal, float width){
vec2 offsetvec = vec2(normal * width);
if (length(offsetvec) < minLength){
offsetvec = normalize(offsetvec);
offsetvec *= minLength;
}
return(offsetvec);
}
float get_line_alpha(vec2 normal, float width){
vec2 offsetvec = vec2(normal * width);
float alpha = 1.0;
if (length(offsetvec) < minLength){
alpha *= (length(offsetvec)/minLength);
}
return alpha;
}
void main() {
//calculate line normal
vec4 p1 = gl_in[0].gl_Position;
vec4 p2 = gl_in[1].gl_Position;
vec2 ssp1 = vec2(p1.xy / p1.w);
vec2 ssp2 = vec2(p2.xy / p2.w);
float width = thickness;
vec2 dir = normalize((ssp2 - ssp1) * Viewport.xy);
vec2 normal = vec2(-dir[1], dir[0]);
normal = normalize(normal);
// get offset factor from normal and user input thickness
vec2 offset = get_line_width(normal,width) / Viewport.xy;
float lineAlpha = get_line_alpha(normal,width);
vec4 coords[4];
vec2 texCoords[4];
coords[0] = vec4((ssp1 + offset)*p1.w,p1.z,p1.w);
texCoords[0] = vec2(0,1);
coords[1] = vec4((ssp1 - offset)*p1.w,p1.z,p1.w);
texCoords[1] = vec2(0,0);
coords[2] = vec4((ssp2 + offset)*p2.w,p2.z,p2.w);
texCoords[2] = vec2(0,1);
coords[3] = vec4((ssp2 - offset)*p2.w,p2.z,p2.w);
texCoords[3] = vec2(0,0);
for (int i = 0; i < 4; ++i) {
mTexCoord = texCoords[i];
gl_Position = coords[i];
alpha = lineAlpha;
vec4 stipple_base;
if (i < 2) {
stipple_base = vec4(ssp1*p1.w,p1.z,p1.w);
}
else {
stipple_base = vec4(ssp2*p2.w, p2.z, p2.w);
}
stipple_start = stipple_pos = Viewport * 0.5 * (stipple_base.xy / stipple_base.w);
EmitVertex();
}
EndPrimitive();
}
"""

return GPUShader(
cls.base_vertex_shader_3d,
cls.base_fragment_shader_3d,
geocode=geometry_shader,
)
shader_info = cls.get_base_shader_3d_info()
shader = create_from_info(shader_info)
del shader_info
return shader

@staticmethod
@cache
def id_shader_3d():
vertex_shader = """
uniform mat4 ModelViewProjectionMatrix;
in vec3 pos;
shader_info = GPUShaderCreateInfo()
shader_info.push_constant("MAT4", "ModelViewProjectionMatrix")
shader_info.push_constant("VEC4", "color")
shader_info.vertex_in(0, "VEC3", "pos")
shader_info.fragment_out(0, "VEC4", "fragColor")

shader_info.vertex_source(
"""
void main()
{
gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
}
"""
)

fragment_shader = """
uniform vec4 color;
out vec4 fragColor;
shader_info.fragment_source(
"""
void main()
{
fragColor = color;
}
"""
return GPUShader(vertex_shader, fragment_shader)
)

shader = create_from_info(shader_info)
del shader_info
return shader

@staticmethod
@cache
Expand Down

0 comments on commit cba040a

Please sign in to comment.