import bpy
from mathutils.geometry import intersect_line_plane
import math
[docs]
class Illumination():
def __init__(self, *, process, spaceProfile):
self._process = process
self._spaceProfile = spaceProfile
self._illuminationMaterial = self._createIlluminationMaterial()
def _createIlluminationMaterial(self):
ilspDomain = self._process.ilspDomain
illuminationNumber = 0
illuminationBasicName = ilspDomain.name + '_illumination_'
for mat in bpy.data.materials:
if illuminationBasicName in mat.name:
number = int(mat.name.split(illuminationBasicName)[1])
if number >= illuminationNumber:
illuminationNumber = number + 1
materialName = illuminationBasicName + str(illuminationNumber)
illuminationMaterial = bpy.data.materials.new(materialName)
if ilspDomain.data.materials:
ilspDomain.data.materials[0] = illuminationMaterial
else:
ilspDomain.data.materials.append(illuminationMaterial)
illuminationMaterial.use_nodes = True
illumValues = illuminationMaterial.node_tree.nodes.new(
type="ShaderNodeAttribute")
colorRamp = illuminationMaterial.node_tree.nodes.new(
type="ShaderNodeValToRGB")
mathMultiply = illuminationMaterial.node_tree.nodes.new(
type='ShaderNodeMath')
mathMultiply.operation = 'MULTIPLY'
mathMultiply.inputs[1].default_value = 1.0
mathMultiply.name = 'Multiply'
# Add Math Node for addition
mathAdd = illuminationMaterial.node_tree.nodes.new(
type='ShaderNodeMath')
mathAdd.operation = 'ADD'
mathAdd.inputs[1].default_value = 0.0
mathAdd.name = 'Add'
# position = 0.0
# createNew = True
# for elem in colorRamp.color_ramp.elements:
# if math.isclose(elem.position, position, rel_tol=1e-6):
# elem.color = (0.8, 0.8, 0.8, 1)
# createNew = False
# if createNew:
# elem = colorRamp.color_ramp.elements.new(position)
# elem.color = (0.8, 0.8, 0.8, 1)
# for color in self._spaceProfile.colorBar:
# position = color[0]
# elem = colorRamp.color_ramp.elements.new(position)
# elem.color = color[1]
colorRamp.color_ramp.elements.new(0.0)
colorRamp.color_ramp.elements.new(0.0)
colorRamp.color_ramp.elements.new(1.0)
colorRamp.color_ramp.elements.new(1.0)
colorRamp.color_ramp.elements[0].color = (0, 0, 1, 1)
colorRamp.color_ramp.elements[1].color = (0, 0, 1, 1)
colorRamp.color_ramp.elements[2].color = (0, 0, 1, 1)
colorRamp.color_ramp.elements[3].color = (0, 1, 0, 1)
colorRamp.color_ramp.elements[4].color = (1, 0, 0, 1)
colorRamp.color_ramp.elements[5].color = (1, 0, 0, 1)
shader = illuminationMaterial.node_tree.nodes["Principled BSDF"]
output = illuminationMaterial.node_tree.nodes["Material Output"]
illuminationMaterial.node_tree.links.new(
illumValues.outputs['Fac'],
mathMultiply.inputs[0])
illuminationMaterial.node_tree.links.new(
mathMultiply.outputs['Value'],
mathAdd.inputs[0])
illuminationMaterial.node_tree.links.new(
mathAdd.outputs['Value'],
colorRamp.inputs['Fac'])
illuminationMaterial.node_tree.links.new(
colorRamp.outputs['Color'],
shader.inputs['Base Color'])
illuminationMaterial.node_tree.links.new(
shader.outputs['BSDF'],
output.inputs['Surface'])
return illuminationMaterial
[docs]
def simulate(self, laserBeam):
if self._process.processSteps is None:
return
min = float('inf')
max = -float('inf')
wm = bpy.context.window_manager
wm.progress_begin(0, len(self._process.processSteps))
process = self._process
illuminationMaterial = self._illuminationMaterial
ilspDomain = process.ilspDomain
ilspDomainMesh = ilspDomain.data
while process.update():
illumValues = ilspDomainMesh.attributes.new(
name=illuminationMaterial.name + "_" + str(process.stepIndex),
type="FLOAT", domain="FACE")
visibleFaces = self._getVisibleFacesInBeam(ilspDomain, laserBeam)
for visibleFace in visibleFaces:
normal = process.normals[visibleFace.index]
vertexValues = []
for vertex in visibleFace.vertices:
vertexValues.append(laserBeam.getValue(
coords=process.coords[vertex], normal=normal))
val = sum(vertexValues) / len(vertexValues)
if val > max:
max = val
if (val < min) and val > 0.0:
min = val
setattr(ilspDomainMesh.attributes[illumValues.name].data[visibleFace.index], "value", val)
wm.progress_update(process.stepIndex)
wm.progress_end()
illumValuesProcess = []
for att in ilspDomainMesh.attributes:
if illuminationMaterial.name in att.name:
illumValuesProcess.append(att)
for illumValuesIdx in range(1, len(illumValuesProcess)):
illumValues = illumValuesProcess[illumValuesIdx]
illumValuesPrev = illumValuesProcess[illumValuesIdx - 1]
for polygon in ilspDomainMesh.polygons:
if bpy.context.scene.ilsp_process.simulation_type == 'MAXIMUM':
if illumValuesPrev.data[polygon.index].value > illumValues.data[polygon.index].value:
illumValues.data[polygon.index].value = illumValuesPrev.data[polygon.index].value
else:
illumValues.data[polygon.index].value += illumValuesPrev.data[polygon.index].value
if illumValues.data[polygon.index].value > max:
max = illumValues.data[polygon.index].value
if illumValues.data[polygon.index].value < min:
min = illumValues.data[polygon.index].value
# if illumValuesPrev.data[polygon.index].value > illumValues.data[polygon.index].value:
# illumValues.data[polygon.index].value = illumValuesPrev.data[polygon.index].value
return min, max
def _getVisibleFacesInBeam(self, ilspDomain, laserBeam):
# See http//blender.stackexchange.com/questions/57540/automated-way-to-make-select-interior-faces-ignore-select-faces-that-are-visib
bpy.ops.object.mode_set(mode='OBJECT')
matrix_world = ilspDomain.matrix_world
visibleFaces = []
origin = laserBeam.point
direction = laserBeam.axis
normDir = direction
normDir.normalize()
for face in ilspDomain.data.polygons:
faceCenter = matrix_world @ face.center
if laserBeam.inBeam(coords=faceCenter):
newOrigin = intersect_line_plane(faceCenter, faceCenter + direction, origin, direction)
faceIndex = bpy.context.scene.ray_cast(bpy.context.view_layer.depsgraph, newOrigin, normDir)[3]
if faceIndex == face.index:
visibleFaces.append(face)
return visibleFaces