import bpy
import mathutils
import math
from bpy.types import Panel, PropertyGroup
from bpy.props import (BoolProperty, FloatProperty,
FloatVectorProperty)
from . ui_panel import ILSPpanel
from . import laserBeam as lb
[docs]
class LaserMaterial:
def __init__(self):
self._laserMaterial = bpy.data.materials.new('laserMaterial')
self._laserMaterial.use_nodes = True
principledBSDF = self._laserMaterial.node_tree.nodes["Principled BSDF"]
principledBSDF.inputs[0].default_value = (1, 0, 0, 1)
transparentBSDF = self._laserMaterial.node_tree.nodes.new("ShaderNodeBsdfTransparent")
transparentBSDF.inputs[0].default_value = (1, 0, 0, 1)
mixer = self._laserMaterial.node_tree.nodes.new("ShaderNodeMixShader")
mixer.inputs[0].default_value = 0.95
output = self._laserMaterial.node_tree.nodes["Material Output"]
self._laserMaterial.node_tree.links.new(
principledBSDF.outputs['BSDF'],
mixer.inputs[1])
self._laserMaterial.node_tree.links.new(
transparentBSDF.outputs['BSDF'],
mixer.inputs[2])
self._laserMaterial.node_tree.links.new(
mixer.outputs['Shader'],
output.inputs['Surface'])
self._laserMaterial.blend_method = 'BLEND'
@property
def get(self):
return self._laserMaterial
########################################################################
# PROPERTIES
########################################################################
[docs]
class BeamProperties(PropertyGroup):
[docs]
def setDefaultValues(self, context):
pass
[docs]
def check(self, context):
return True
[docs]
def snapCursorToSelected(self):
obj = bpy.context.active_object
if obj and obj.type == 'MESH' and obj.mode == 'EDIT':
bpy.ops.object.mode_set(mode='OBJECT')
mesh = obj.data
selected_verts = [v for v in mesh.vertices if v.select]
if selected_verts:
avg_pos = mathutils.Vector()
for vert in selected_verts:
avg_pos += obj.matrix_world @ vert.co # Convert to world coordinates
avg_pos /= len(selected_verts)
bpy.context.scene.cursor.location = avg_pos
bpy.ops.object.mode_set(mode='EDIT')
point: FloatVectorProperty(
name="Laser Point",
description="Laser Reference Point",
unit='LENGTH',
default=(-5.0, 0.0, 0.0),
size=3,
update=lambda self, context: self.updateLaserBeam(context),
) # type: ignore
axis: FloatVectorProperty(
name="Beam Axis",
description="Laser Beam Axis",
unit='LENGTH',
default=(1.0, 0.0, 0.0),
min=-1,
max=1,
size=3,
update=lambda self, context: self.updateLaserBeam(context),
) # type: ignore
spot_axis: FloatVectorProperty(
name="Spot Horizontal Axis",
description="Spot Horizontal Axis",
unit='LENGTH',
default=(0.0, -1.0, 0.0),
min=-1,
max=1,
size=3
) # type: ignore
[docs]
def deleteLaserBeam(self, context):
if bpy.context.scene.objects.get('laser beam'):
obj = bpy.data.objects['laser beam']
mesh = obj.data
bpy.data.objects.remove(obj)
bpy.data.meshes.remove(mesh)
[docs]
def updateLaserBeam(self, context):
self.deleteLaserBeam(context)
if self.show_beam:
length = self.laser_beam_length
laserBeam = lb.LaserBeam(laserSpot=context.scene.ilsp_spot,
laserBeam=context.scene.ilsp_beam)
radius = laserBeam.spaceProfil.maxRadius
axis = laserBeam.axis
axis.normalize()
point = laserBeam.point + 0.5 * axis * length
bpy.ops.mesh.primitive_cylinder_add(
radius=radius,
depth=length,
enter_editmode=False,
align='WORLD',
location=point,
scale=(1, 1, 1))
beamObj = context.object
#beamObj = bpy.data.objects[-1]
beamObj.name = 'laser beam'
phi = math.atan2(axis.y, axis.x)
theta = math.acos(axis.z)
beamObj.rotation_euler[1] = theta
beamObj.rotation_euler[2] = phi
if 'laserMaterial' not in bpy.data.materials.keys():
self.laser_material = LaserMaterial().get
beamObj.data.materials.append(bpy.data.materials['laserMaterial'])
laser_beam_length: FloatProperty(
name="Laser Beam Scale",
description="Laser Beam Scale",
default=1,
min=1,
max=100,
step=10,
update=lambda self, context: self.updateLaserBeam(context),
) # type: ignore
show_beam: BoolProperty(
name="Show Laser Beam",
description="Show Laser Beam",
default=False,
update=lambda self, context: self.updateLaserBeam(context),
) # type: ignore
########################################################################
# PANELS
########################################################################
[docs]
class ILSP_PT_beam(ILSPpanel, Panel):
bl_label = "Laser Beam"
[docs]
@classmethod
def poll(cls, context):
return True
[docs]
def draw(self, context):
layout = self.layout
layout.use_property_split = False
layout.use_property_decorate = False
beam = context.scene.ilsp_beam
layout.prop(beam, 'point')
layout.prop(beam, 'axis', slider=True)
layout.prop(beam, 'spot_axis', slider=True)
grid = layout.grid_flow(columns=2, align=True)
grid.enabled = True
grid.prop(beam, 'show_beam')
grid.prop(beam, 'laser_beam_length', slider=True)
status = beam.check(context)
try:
len(status)
except Exception:
return
layout.label(text=status[1], icon_value=status[2])