mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 17:31:45 +00:00
now with shader for point loads
This commit is contained in:
committed by
Dion Moult
parent
d915dc9df0
commit
477725529b
@@ -50,11 +50,11 @@ class LoadsDecorator:
|
||||
def __call__(self):
|
||||
# set open gl configurations
|
||||
original_blend = gpu.state.blend_get()
|
||||
gpu.state.blend_set('ADDITIVE')
|
||||
gpu.state.blend_set('ALPHA')
|
||||
original_depth_mask = gpu.state.depth_mask_get()
|
||||
#gpu.state.depth_mask_set(True)
|
||||
gpu.state.depth_mask_set(True)
|
||||
original_depth_test = gpu.state.depth_test_get()
|
||||
gpu.state.depth_test_set('ALWAYS')
|
||||
gpu.state.depth_test_set('LESS_EQUAL')
|
||||
|
||||
self.draw_batch("DistributedLoad")
|
||||
|
||||
@@ -98,8 +98,9 @@ def location_3d_to_region_2d(coord, normal, context):
|
||||
perspective = rv3d.view_perspective
|
||||
view_matrix = rv3d.view_matrix
|
||||
point_view_space = view_matrix @ coord
|
||||
|
||||
|
||||
if perspective == 'ORTHO' or -20 < point_view_space.z < 0:
|
||||
if perspective == 'ORTHO' or -10 < point_view_space.z < 0:
|
||||
prj = rv3d.perspective_matrix @ Vector((coord[0], coord[1], coord[2], 1.0))
|
||||
width_half = context.region.width / 2.0
|
||||
height_half = context.region.height / 2.0
|
||||
|
||||
@@ -49,6 +49,8 @@ class ShowLoads(bpy.types.Operator):
|
||||
return {'PASS_THROUGH'}
|
||||
|
||||
def invoke(self, context, event):
|
||||
collection = bpy.data.collections["IfcStructuralItem"]
|
||||
collection.hide_viewport = False
|
||||
LoadsDecorator.install(context)
|
||||
LoadsDecorator.update(context)
|
||||
context.window_manager.modal_handler_add(self)
|
||||
|
||||
@@ -23,11 +23,12 @@ class ShaderInfo:
|
||||
def update(self):
|
||||
self.info = []
|
||||
self.get_linear_loads()
|
||||
self.get_point_loads()
|
||||
if len(self.info):
|
||||
self.is_empty = False
|
||||
|
||||
def get_shader(self):
|
||||
""" param: shader_type: type of shader in ["DistributedLoad", "PointLoad"]
|
||||
def get_shader(self, pattern):
|
||||
""" param: pattern: type of pattern in ["force", "force match", "moment"]
|
||||
return: shader"""
|
||||
if self.shader_type == "DistributedLoad":
|
||||
vert_out = gpu.types.GPUStageInterfaceInfo("my_interface")
|
||||
@@ -57,8 +58,8 @@ class ShaderInfo:
|
||||
"}"
|
||||
)
|
||||
|
||||
|
||||
shader_info.fragment_source(
|
||||
if pattern == "force":
|
||||
shader_info.fragment_source(
|
||||
"void main()"
|
||||
"{"
|
||||
"float x = co.x;"
|
||||
@@ -80,7 +81,74 @@ class ShaderInfo:
|
||||
|
||||
"float top = step(abs(y-f),0.2*1.2*spacing);"
|
||||
"float d = clamp(0.1+top+b+c,0.0,0.5)*mask;"
|
||||
"if (d == 0.0) discard;"
|
||||
"FragColor = vec4(color.xyz,d*color.w);"
|
||||
"}"
|
||||
)
|
||||
|
||||
if pattern == "force match":
|
||||
shader_info.fragment_source(
|
||||
"void main()"
|
||||
"{"
|
||||
"float y = co.y;"
|
||||
"float x = step(0.,y)*(co.z-co.x)+step(y,0.)*(co.x);"
|
||||
"float abs_y = abs(y);"
|
||||
|
||||
"float a = abs(mod(abs_y,spacing)-0.5*spacing)*5.0;"
|
||||
"float a2 = mod(x,3.0*spacing);"
|
||||
"float b = step(a,a2)*step(a2,1.2*spacing);"
|
||||
"float c = step(0.8*spacing,mod(abs_y+0.4*spacing,spacing))"
|
||||
"*(step(1.2*spacing,a2))*step(a2,2.5*spacing);"
|
||||
"float sinvalue = forces.x;"
|
||||
"float quadraticvalue = forces.y;"
|
||||
"float linearvalue = forces.z;"
|
||||
"x = co.x/co.z;"
|
||||
"float f = (sin(x*3.1416)*sinvalue"
|
||||
"+(-4.*x*x+4.*x)*quadraticvalue"
|
||||
"+linearvalue)/maxload;"
|
||||
"float mask = step(0.,y)*step(y,f)+step(y,0.)*step(f,y);"
|
||||
|
||||
"float top = step(abs(y-f),0.2*1.2*spacing);"
|
||||
"float d = clamp(0.1+top+b+c,0.0,0.5)*mask;"
|
||||
"if (d == 0.0) discard;"
|
||||
"FragColor = vec4(color.xyz,d*color.w);"
|
||||
"}"
|
||||
)
|
||||
|
||||
if pattern == "moment":
|
||||
shader_info.fragment_source(
|
||||
"void main()"
|
||||
"{"
|
||||
"float x = step(co.y,0.)*(co.x)+step(0.,co.y)*(co.z-co.x);"
|
||||
"float y = step(co.y,-0.00001)*(co.y)+step(0.,co.y)*(0.-co.y);"
|
||||
"x = mod((0.5/spacing)*x,1.4)-0.7;"
|
||||
"y = mod((0.5/spacing)*y,1.4)-0.7;"
|
||||
"float abs_y = abs(y);"
|
||||
"vec2 st = vec2(1.9*x,y);"
|
||||
"vec2 orig = vec2(0.,0.);"
|
||||
|
||||
"float circ = step(distance(st,orig),0.33)*step(0.27,distance(st,orig));"
|
||||
"float tri_mask = step(st.y,st.x)+step(-st.x,st.y);"
|
||||
"float circ_arrow = step(st.x,4.0*st.y-0.75)*step(0.25*st.y-0.34,st.x)*(1.-tri_mask);"
|
||||
|
||||
"float circmask = step(distance(st,orig),0.1)+step(0.5,distance(st,orig))+step(st.x,0.);"
|
||||
"float body = step(-0.03,st.y)*step(st.y,0.03)*step(-0.3,x)*step(x,0.576);"
|
||||
"float body_arrow = step(-0.5+3.*st.y,x)*step(-0.5-3.*st.y,x)*step(x,-0.3);"
|
||||
"float d = clamp(circmask*(body+body_arrow)+circ_arrow+circ*tri_mask,0.,1.);"
|
||||
|
||||
"float sinvalue = forces.x;"
|
||||
"float quadraticvalue = forces.y;"
|
||||
"float linearvalue = forces.z;"
|
||||
"x = co.x/co.z;"
|
||||
"float f = (sin(x*3.1416)*sinvalue"
|
||||
"+(-4.*x*x+4.*x)*quadraticvalue"
|
||||
"+linearvalue)/maxload;"
|
||||
"float mask = step(0.,co.y)*step(co.y,f)+step(co.y,0.)*step(f,co.y);"
|
||||
|
||||
"float top = step(abs(co.y-f),0.2*1.2*spacing);"
|
||||
|
||||
"d = clamp(0.1+top+d,0.0,0.5)*mask;"
|
||||
"if (d == 0.0) discard;"
|
||||
"FragColor = vec4(color.xyz,d*color.w);"
|
||||
"}"
|
||||
)
|
||||
@@ -89,12 +157,158 @@ class ShaderInfo:
|
||||
del vert_out
|
||||
del shader_info
|
||||
return shader
|
||||
|
||||
def get_point_shader(self, pattern):
|
||||
""" param: pattern: type of pattern in ["arrow", "circ arrow"]
|
||||
return: shader"""
|
||||
vert_out = gpu.types.GPUStageInterfaceInfo("my_interface")
|
||||
vert_out.smooth('VEC3', "co")
|
||||
|
||||
shader_info = gpu.types.GPUShaderCreateInfo()
|
||||
shader_info.push_constant('MAT4', "viewProjectionMatrix")
|
||||
shader_info.push_constant('VEC4', "color")
|
||||
shader_info.push_constant('FLOAT', "spacing")
|
||||
|
||||
shader_info.vertex_in(0, 'VEC3', "position")
|
||||
shader_info.vertex_in(1, 'VEC3', "coord")
|
||||
|
||||
shader_info.vertex_out(vert_out)
|
||||
shader_info.fragment_out(0, 'VEC4', "FragColor")
|
||||
|
||||
shader_info.vertex_source(
|
||||
"void main()"
|
||||
"{"
|
||||
" gl_Position = viewProjectionMatrix * vec4(position, 1.0f);"
|
||||
" co = coord;"
|
||||
"}"
|
||||
)
|
||||
|
||||
if pattern == "arrow":
|
||||
shader_info.fragment_source(
|
||||
"void main()"
|
||||
"{"
|
||||
"float body = step(abs(co.x),0.2*spacing)*step(2.*spacing,co.y);"
|
||||
"float arrow = step(3.5*abs(co.x)+0.02,abs(co.y))*step(co.y,2.*spacing)*step(0.,co.y);"
|
||||
"float d = clamp(body+arrow,0.0,0.5);"
|
||||
"if (d == 0.0) discard;"
|
||||
"FragColor = vec4(color.xyz,d*color.w);"
|
||||
"}"
|
||||
)
|
||||
|
||||
if pattern == "circ arrow":
|
||||
shader_info.fragment_source(
|
||||
"void main()"
|
||||
"{"
|
||||
"float circ = step(distance(co.xy,vec2(0.,0.)),0.33)*step(0.27,distance(co.xy,vec2(0.,0.)));"
|
||||
"float mask = step(co.y,co.x)+step(-co.x,co.y);"
|
||||
"float circ_arrow = step(co.x,4.0*co.y-0.75)*step(0.25*co.y-0.34,co.x)*(1.-mask);"
|
||||
"float d = clamp(circ_arrow+circ*mask,0.0,0.5);"
|
||||
"if (d == 0.0) discard;"
|
||||
"FragColor = vec4(color.xyz,d*color.w);"
|
||||
"}"
|
||||
)
|
||||
|
||||
shader = gpu.shader.create_from_info(shader_info)
|
||||
del vert_out
|
||||
del shader_info
|
||||
return shader
|
||||
|
||||
def get_point_loads(self):
|
||||
list_of_point_connections = tool.Ifc.get().by_type("IfcStructuralPointConnection")
|
||||
for conn in list_of_point_connections:
|
||||
activity_list = [getattr(a, 'RelatedStructuralActivity', None) for a in getattr(conn, 'AssignedStructuralActivity', None)
|
||||
if getattr(a, 'RelatedStructuralActivity', None).is_a() in ['IfcStructuralPointAction']]
|
||||
if len(activity_list) == 0:
|
||||
continue
|
||||
blender_object = IfcStore.get_element(getattr(conn, 'GlobalId', None))
|
||||
if blender_object.type == 'MESH':
|
||||
conn_location = blender_object.matrix_world @ blender_object.data.vertices[0].co
|
||||
#get local coordinates of the connection
|
||||
loads = self.get_point_loads_list(activity_list)
|
||||
self.get_point_shader_args(loads, conn_location)
|
||||
|
||||
def get_point_shader_args(self,loads, location):
|
||||
indices = []
|
||||
text_info = []
|
||||
direction_dict = {
|
||||
"fx": (Vector((1,0,0)),Vector((0,1,0)),Vector((0,0,1))),
|
||||
"fy": (Vector((0,1,0)),Vector((1,0,0)),Vector((0,0,1))),
|
||||
"fz": (Vector((0,0,1)),Vector((0,1,0)),Vector((1,0,0))),
|
||||
"mx": (Vector((0,1,0)),Vector((0,0,1))),
|
||||
"my": (Vector((1,0,0)),Vector((0,0,1))),
|
||||
"mz": (Vector((1,0,0)),Vector((0,1,0))),
|
||||
}
|
||||
keys = ["fx","fy","fz","mx","my","mz"]
|
||||
for i, key in enumerate(keys):
|
||||
if loads[i] == 0:
|
||||
continue
|
||||
color = (1,0,0,1)
|
||||
if i in [1,4]:
|
||||
color = (0,1,0,1)
|
||||
elif i in [2,5]:
|
||||
color = (0,0,1,1)
|
||||
d1 = -(direction_dict[key][0]*loads[i]).normalized()
|
||||
if i < 3:
|
||||
d2 = direction_dict[key][1]
|
||||
d3 = direction_dict[key][2]
|
||||
p1 = location
|
||||
p2 = location + d1 + d2
|
||||
p3 = location + d1 - d2
|
||||
p4 = location + d1 + d3
|
||||
p5 = location + d1 - d3
|
||||
position = [p1,p2,p3,p4,p5]
|
||||
indices = [(0,1,2),(0,3,4)]
|
||||
c1 = (0,0,0)
|
||||
c2 = (1,1,0)
|
||||
c3 = (-1,1,0)
|
||||
coords_for_shader = [c1,c2,c3,c2,c3]
|
||||
shader = self.get_point_shader("arrow")
|
||||
self.info.append(
|
||||
{
|
||||
"shader": shader,
|
||||
"args": {"position": position,"coord": coords_for_shader},
|
||||
"indices": indices,
|
||||
"uniforms": [["color", color],["spacing", 0.2]]
|
||||
}
|
||||
)
|
||||
else:
|
||||
d2 = d2 = direction_dict[key][1]
|
||||
p1 = location - d2
|
||||
p2 = location + d1 + d2
|
||||
p3 = location - d1 + d2
|
||||
position = [p1,p2,p3]
|
||||
indices = [(0,1,2)]
|
||||
c1 = (-1,0,0)
|
||||
c2 = (1,1,0)
|
||||
c3 = (1,-1,0)
|
||||
coords_for_shader = [c1,c2,c3]
|
||||
shader = self.get_point_shader("circ arrow")
|
||||
self.info.append(
|
||||
{
|
||||
"shader": shader,
|
||||
"args": {"position": position,"coord": coords_for_shader},
|
||||
"indices": indices,
|
||||
"uniforms": [["color", color]]#,["spacing", 0.2]]
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
|
||||
def get_point_loads_list(self,activity_list):
|
||||
result_list = [0,0,0,0,0,0]
|
||||
attr_list = ['ForceX','ForceY','ForceZ','MomentX','MomentY','MomentZ']
|
||||
for activity in activity_list:
|
||||
load = activity.AppliedLoad
|
||||
for i, attr in enumerate(attr_list):
|
||||
value = 0 if getattr(load, attr, 0) is None else getattr(load, attr, 0)
|
||||
result_list[i] += value
|
||||
return result_list
|
||||
|
||||
|
||||
def get_linear_loads(self): #for now it only works for distributed loads
|
||||
coords = []
|
||||
position = []
|
||||
indices = []
|
||||
load_info = []
|
||||
sin_quad_lin = []
|
||||
coords_for_shader = []
|
||||
color = []
|
||||
text_info = []
|
||||
@@ -145,7 +359,7 @@ class ShaderInfo:
|
||||
"my": z_axis if is_local else Vector((-1,0,1)) if y_match else Vector((0,1,0)).cross(x_axis).normalized(),
|
||||
"mz": y_axis if is_local else Vector((-1,1,0)) if z_match else Vector((0,0,1)).cross(x_axis).normalized()
|
||||
}
|
||||
shader = self.get_shader()
|
||||
match_dict = {'fx': x_match, 'fy': y_match, 'fz': z_match}
|
||||
member_length = Vector(end_co-start_co).length
|
||||
loads_dict, maxforce = get_loads_per_direction(activity_list,global_to_local,member_length)
|
||||
keys = ["fx","fy","fz","mx","my","mz"]
|
||||
@@ -161,32 +375,40 @@ class ShaderInfo:
|
||||
color_axis = (1,0,0,1)
|
||||
if 'y' in key:
|
||||
color_axis = (0,1,0,1)
|
||||
|
||||
if 'f' in key:
|
||||
if match_dict[key]:
|
||||
shader = self.get_shader("force match")
|
||||
else:
|
||||
shader = self.get_shader("force")
|
||||
else:
|
||||
shader = self.get_shader("moment")
|
||||
|
||||
addindex = len(coords)
|
||||
addindex = len(position)
|
||||
counter = 0
|
||||
for i in range(len(polyline)-1):
|
||||
current = Vector(polyline[i]+[0])
|
||||
nextitem = Vector(polyline[i+1]+[0])
|
||||
|
||||
if any([current.y, nextitem.y,constant,quadratic,sinus]): #if there is load in the z direction
|
||||
negative = -direction + start_co + x_axis*current.x
|
||||
negative = -1*direction + start_co + x_axis*current.x
|
||||
positive = direction + start_co + x_axis*current.x
|
||||
coords.append(negative)
|
||||
position.append(negative)
|
||||
coords_for_shader.append((current.x, 1.0,member_length))
|
||||
load_info.append((sinus, quadratic, current.y + constant))
|
||||
sin_quad_lin.append((sinus, quadratic, current.y + constant))
|
||||
color.append(color_axis)
|
||||
#info to render load value
|
||||
x = current.x/member_length
|
||||
func = sin(x*3.1416)*sinus + (-4.*x*x+4.*x)*quadratic+constant+current.y
|
||||
if func:
|
||||
text_info.append(
|
||||
{"position": -direction*func/maxforce + start_co + x_axis*current.x,
|
||||
{"position": -1*direction*func/maxforce + start_co + x_axis*current.x,
|
||||
"normal": direction.cross(x_axis).normalized(), "text": f'{func:.2f} '}
|
||||
)
|
||||
maxforce = max(maxforce,abs(func))
|
||||
coords.append(positive)
|
||||
position.append(positive)
|
||||
coords_for_shader.append((current[0],-1.0,member_length))
|
||||
load_info.append((sinus, quadratic, current.y + constant))
|
||||
sin_quad_lin.append((sinus, quadratic, current.y + constant))
|
||||
color.append(color_axis)
|
||||
|
||||
indices.append((0 + counter + addindex,
|
||||
@@ -196,38 +418,38 @@ class ShaderInfo:
|
||||
2 + counter + addindex,
|
||||
1 + counter + addindex))
|
||||
if i == len(polyline)-2:
|
||||
negative = -direction + start_co + x_axis*nextitem.x
|
||||
negative = -1*direction + start_co + x_axis*nextitem.x
|
||||
positive = direction + start_co + x_axis*nextitem.x
|
||||
coords.append(negative)
|
||||
position.append(negative)
|
||||
coords_for_shader.append((nextitem.x, 1.0,member_length))
|
||||
load_info.append((sinus, quadratic, nextitem.y + constant))
|
||||
sin_quad_lin.append((sinus, quadratic, nextitem.y + constant))
|
||||
color.append(color_axis)
|
||||
#info to render load value
|
||||
x = nextitem.x/member_length
|
||||
func = sin(x*3.1416)*sinus + (-4.*x*x+4.*x)*quadratic+constant+nextitem.y
|
||||
if func:
|
||||
text_info.append(
|
||||
{"position": -direction*func/maxforce + start_co + x_axis*nextitem.x,
|
||||
{"position": -1*direction*func/maxforce + start_co + x_axis*nextitem.x,
|
||||
"normal": direction.cross(x_axis).normalized(), "text": f'{func:.2f} '}
|
||||
)
|
||||
maxforce = max(maxforce,abs(func))
|
||||
coords.append(positive)
|
||||
position.append(positive)
|
||||
coords_for_shader.append((nextitem.x,-1.0,member_length))
|
||||
load_info.append((sinus, quadratic, nextitem.y + constant))
|
||||
sin_quad_lin.append((sinus, quadratic, nextitem.y + constant))
|
||||
color.append(color_axis)
|
||||
|
||||
counter += 2
|
||||
if len(coords):
|
||||
if len(position):
|
||||
self.info.append(
|
||||
{
|
||||
"shader": shader,
|
||||
"args": {"position": coords, "sin_quad_lin_forces": load_info,"coord": coords_for_shader},
|
||||
"args": {"position": position, "sin_quad_lin_forces": sin_quad_lin,"coord": coords_for_shader},
|
||||
"indices": indices,
|
||||
"uniforms": [["color", color_axis],["spacing", 0.2],["maxload",maxforce]]
|
||||
}
|
||||
)
|
||||
coords = []
|
||||
load_info = []
|
||||
position = []
|
||||
sin_quad_lin = []
|
||||
coords_for_shader = []
|
||||
indices = []
|
||||
for info in self.info:
|
||||
@@ -272,12 +494,12 @@ def get_loads_per_direction(activity_list,global_to_local,member_length):
|
||||
final_list.append([0.0,0.0,0.0,0.0,0.0,0.0,0.0])
|
||||
final_list.append([member_length,0.0,0.0,0.0,0.0,0.0,0.0])
|
||||
|
||||
elif len(final_list) and any(const+quad+sinus):
|
||||
if final_list[0][0]: #if first item location is not 0 append an item at the zero
|
||||
elif len(final_list):
|
||||
if final_list[0][0] and any(const+quad+sinus): #if first item location is not 0 append an item at the zero
|
||||
final_list = [[0.0,0.0,0.0,0.0,0.0,0.0,0.0]]+final_list
|
||||
else:
|
||||
del final_list[0]
|
||||
if abs(final_list[-1][0] - member_length) > 0.01:
|
||||
if abs(final_list[-1][0] - member_length) > 0.01 and any(const+quad+sinus):
|
||||
final_list.append([member_length,0.0,0.0,0.0,0.0,0.0,0.0])
|
||||
else:
|
||||
del final_list[-1]
|
||||
@@ -430,7 +652,7 @@ def get_loads_dict(activity_list,global_to_local):
|
||||
Locations attribute of IfcLoadConfiguration
|
||||
dict{
|
||||
"pos": float, -> local position along curve length
|
||||
"descr": string, -> describe if the item is at the star, middle or end of the list
|
||||
"descr": string, -> describe if the item is at the start, middle or end of the list
|
||||
"forces": Vector, -> linear force applied at that point
|
||||
"moments": Vector -> linear moment applied at that point
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user