forked from LeenkxTeam/LNXSDK
merge upstream
This commit is contained in:
@ -2297,6 +2297,8 @@ class LeenkxExporter:
|
||||
out_particlesys = {
|
||||
'name': particleRef[1]["structName"],
|
||||
'type': 0 if psettings.type == 'EMITTER' else 1, # HAIR
|
||||
'auto_start': psettings.lnx_auto_start,
|
||||
'is_unique': psettings.lnx_is_unique,
|
||||
'loop': psettings.lnx_loop,
|
||||
# Emission
|
||||
'count': int(psettings.count * psettings.lnx_count_mult),
|
||||
@ -2813,6 +2815,7 @@ class LeenkxExporter:
|
||||
body_flags['animated'] = rb.kinematic
|
||||
body_flags['trigger'] = bobject.lnx_rb_trigger
|
||||
body_flags['ccd'] = bobject.lnx_rb_ccd
|
||||
body_flags['interpolate'] = bobject.lnx_rb_interpolate
|
||||
body_flags['staticObj'] = is_static
|
||||
body_flags['useDeactivation'] = rb.use_deactivation
|
||||
x['parameters'].append(lnx.utils.get_haxe_json_string(body_params))
|
||||
@ -3037,7 +3040,7 @@ class LeenkxExporter:
|
||||
|
||||
rbw = self.scene.rigidbody_world
|
||||
if rbw is not None and rbw.enabled:
|
||||
out_trait['parameters'] = [str(rbw.time_scale), str(rbw.substeps_per_frame), str(rbw.solver_iterations)]
|
||||
out_trait['parameters'] = [str(rbw.time_scale), str(rbw.substeps_per_frame), str(rbw.solver_iterations), str(wrd.lnx_physics_fixed_step)]
|
||||
|
||||
if phys_pkg == 'bullet' or phys_pkg == 'oimo':
|
||||
debug_draw_mode = 1 if wrd.lnx_physics_dbg_draw_wireframe else 0
|
||||
|
@ -87,6 +87,7 @@ def on_operator_post(operator_id: str) -> None:
|
||||
target_obj.lnx_rb_trigger = source_obj.lnx_rb_trigger
|
||||
target_obj.lnx_rb_deactivation_time = source_obj.lnx_rb_deactivation_time
|
||||
target_obj.lnx_rb_ccd = source_obj.lnx_rb_ccd
|
||||
target_obj.lnx_rb_interpolate = source_obj.lnx_rb_interpolate
|
||||
target_obj.lnx_rb_collision_filter_mask = source_obj.lnx_rb_collision_filter_mask
|
||||
|
||||
elif operator_id == "NODE_OT_new_node_tree":
|
||||
|
@ -1,31 +1,34 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class GetParticleDataNode(LnxLogicTreeNode):
|
||||
"""Returns the data of the given Particle System."""
|
||||
bl_idname = 'LNGetParticleDataNode'
|
||||
bl_label = 'Get Particle Data'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.inputs.new('LnxNodeSocketObject', 'Object')
|
||||
self.inputs.new('LnxIntSocket', 'Slot')
|
||||
|
||||
self.outputs.new('LnxStringSocket', 'Name')
|
||||
self.outputs.new('LnxFloatSocket', 'Particle Size')
|
||||
self.outputs.new('LnxIntSocket', 'Frame Start')
|
||||
self.outputs.new('LnxIntSocket', 'Frame End')
|
||||
self.outputs.new('LnxIntSocket', 'Lifetime')
|
||||
self.outputs.new('LnxFloatSocket', 'Lifetime Random')
|
||||
self.outputs.new('LnxIntSocket', 'Emit From')
|
||||
|
||||
self.outputs.new('LnxVectorSocket', 'Velocity')
|
||||
self.outputs.new('LnxFloatSocket', 'Velocity Random')
|
||||
self.outputs.new('LnxVectorSocket', 'Gravity')
|
||||
self.outputs.new('LnxFloatSocket', 'Weight Gravity')
|
||||
|
||||
self.outputs.new('LnxFloatSocket', 'Speed')
|
||||
|
||||
self.outputs.new('LnxFloatSocket', 'Time')
|
||||
self.outputs.new('LnxFloatSocket', 'Lap')
|
||||
self.outputs.new('LnxFloatSocket', 'Lap Time')
|
||||
self.outputs.new('LnxIntSocket', 'Count')
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class GetParticleDataNode(LnxLogicTreeNode):
|
||||
"""Returns the data of the given Particle System."""
|
||||
bl_idname = 'LNGetParticleDataNode'
|
||||
bl_label = 'Get Particle Data'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.inputs.new('LnxNodeSocketObject', 'Object')
|
||||
self.inputs.new('LnxIntSocket', 'Slot')
|
||||
|
||||
self.outputs.new('LnxStringSocket', 'Name')
|
||||
self.outputs.new('LnxFloatSocket', 'Particle Size')
|
||||
self.outputs.new('LnxIntSocket', 'Frame Start')
|
||||
self.outputs.new('LnxIntSocket', 'Frame End')
|
||||
self.outputs.new('LnxIntSocket', 'Lifetime')
|
||||
self.outputs.new('LnxFloatSocket', 'Lifetime Random')
|
||||
self.outputs.new('LnxIntSocket', 'Emit From')
|
||||
self.outputs.new('LnxBoolSocket', 'Auto Start')
|
||||
self.outputs.new('LnxBoolSocket', 'Is Unique')
|
||||
self.outputs.new('LnxBoolSocket', 'Loop')
|
||||
|
||||
self.outputs.new('LnxVectorSocket', 'Velocity')
|
||||
self.outputs.new('LnxFloatSocket', 'Velocity Random')
|
||||
self.outputs.new('LnxVectorSocket', 'Gravity')
|
||||
self.outputs.new('LnxFloatSocket', 'Weight Gravity')
|
||||
|
||||
self.outputs.new('LnxFloatSocket', 'Speed')
|
||||
|
||||
self.outputs.new('LnxFloatSocket', 'Time')
|
||||
self.outputs.new('LnxFloatSocket', 'Lap')
|
||||
self.outputs.new('LnxFloatSocket', 'Lap Time')
|
||||
self.outputs.new('LnxIntSocket', 'Count')
|
||||
|
@ -1,58 +1,67 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class SetParticleDataNode(LnxLogicTreeNode):
|
||||
"""Sets the parameters of the given particle system."""
|
||||
bl_idname = 'LNSetParticleDataNode'
|
||||
bl_label = 'Set Particle Data'
|
||||
lnx_version = 1
|
||||
|
||||
def remove_extra_inputs(self, context):
|
||||
while len(self.inputs) > 3:
|
||||
self.inputs.remove(self.inputs[-1])
|
||||
if self.property0 == 'Particle Size':
|
||||
self.add_input('LnxFloatSocket', 'Particle Size')
|
||||
if self.property0 == 'Frame End':
|
||||
self.add_input('LnxIntSocket', 'Frame End')
|
||||
if self.property0 == 'Frame Start':
|
||||
self.add_input('LnxIntSocket', 'Frame Start')
|
||||
if self.property0 == 'Lifetime':
|
||||
self.add_input('LnxIntSocket', 'Lifetime')
|
||||
if self.property0 == 'Lifetime Random':
|
||||
self.add_input('LnxFloatSocket', 'Lifetime Random')
|
||||
if self.property0 == 'Emit From':
|
||||
self.add_input('LnxIntSocket', 'Emit From')
|
||||
if self.property0 == 'Velocity':
|
||||
self.add_input('LnxVectorSocket', 'Velocity')
|
||||
if self.property0 == 'Velocity Random':
|
||||
self.add_input('LnxFloatSocket', 'Velocity Random')
|
||||
if self.property0 == 'Weight Gravity':
|
||||
self.add_input('LnxFloatSocket', 'Weight Gravity')
|
||||
if self.property0 == 'Speed':
|
||||
self.add_input('LnxFloatSocket', 'Speed')
|
||||
|
||||
|
||||
property0: HaxeEnumProperty(
|
||||
'property0',
|
||||
items = [('Particle Size', 'Particle Size', 'for the system'),
|
||||
('Frame Start', 'Frame Start', 'for the system'),
|
||||
('Frame End', 'Frame End', 'for the system'),
|
||||
('Lifetime', 'Lifetime', 'for the instance'),
|
||||
('Lifetime Random', 'Lifetime Random', 'for the system'),
|
||||
('Emit From', 'Emit From', 'for the system (Vertices:0 Faces:1 Volume: 2)'),
|
||||
('Velocity', 'Velocity', 'for the instance'),
|
||||
('Velocity Random', 'Velocity Random', 'for the system'),
|
||||
('Weight Gravity', 'Weight Gravity', 'for the instance'),
|
||||
('Speed', 'Speed', 'for the instance')],
|
||||
name='', default='Speed', update=remove_extra_inputs)
|
||||
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxIntSocket', 'Slot')
|
||||
self.add_input('LnxFloatSocket', 'Speed', default_value=1.0)
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
layout.prop(self, 'property0')
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class SetParticleDataNode(LnxLogicTreeNode):
|
||||
"""Sets the parameters of the given particle system."""
|
||||
bl_idname = 'LNSetParticleDataNode'
|
||||
bl_label = 'Set Particle Data'
|
||||
lnx_version = 1
|
||||
|
||||
def remove_extra_inputs(self, context):
|
||||
while len(self.inputs) > 3:
|
||||
self.inputs.remove(self.inputs[-1])
|
||||
if self.property0 == 'Particle Size':
|
||||
self.add_input('LnxFloatSocket', 'Particle Size')
|
||||
if self.property0 == 'Frame End':
|
||||
self.add_input('LnxIntSocket', 'Frame End')
|
||||
if self.property0 == 'Frame Start':
|
||||
self.add_input('LnxIntSocket', 'Frame Start')
|
||||
if self.property0 == 'Lifetime':
|
||||
self.add_input('LnxIntSocket', 'Lifetime')
|
||||
if self.property0 == 'Lifetime Random':
|
||||
self.add_input('LnxFloatSocket', 'Lifetime Random')
|
||||
if self.property0 == 'Emit From':
|
||||
self.add_input('LnxIntSocket', 'Emit From')
|
||||
if self.property0 == 'Auto Start':
|
||||
self.add_input('LnxBoolSocket', 'Auto Start')
|
||||
if self.property0 == 'Is Unique':
|
||||
self.add_input('LnxBoolSocket', 'Is Unique')
|
||||
if self.property0 == 'Loop':
|
||||
self.add_input('LnxBoolSocket', 'Loop')
|
||||
if self.property0 == 'Velocity':
|
||||
self.add_input('LnxVectorSocket', 'Velocity')
|
||||
if self.property0 == 'Velocity Random':
|
||||
self.add_input('LnxFloatSocket', 'Velocity Random')
|
||||
if self.property0 == 'Weight Gravity':
|
||||
self.add_input('LnxFloatSocket', 'Weight Gravity')
|
||||
if self.property0 == 'Speed':
|
||||
self.add_input('LnxFloatSocket', 'Speed')
|
||||
|
||||
|
||||
property0: HaxeEnumProperty(
|
||||
'property0',
|
||||
items = [('Particle Size', 'Particle Size', 'for the system'),
|
||||
('Frame Start', 'Frame Start', 'for the system'),
|
||||
('Frame End', 'Frame End', 'for the system'),
|
||||
('Lifetime', 'Lifetime', 'for the instance'),
|
||||
('Lifetime Random', 'Lifetime Random', 'for the system'),
|
||||
('Emit From', 'Emit From', 'for the system (Vertices:0 Faces:1 Volume: 2)'),
|
||||
('Auto Start', 'Auto Start', 'for the system'),
|
||||
('Is Unique', 'Is Unique', 'for the system'),
|
||||
('Loop', 'Loop', 'for the system'),
|
||||
('Velocity', 'Velocity', 'for the instance'),
|
||||
('Velocity Random', 'Velocity Random', 'for the system'),
|
||||
('Weight Gravity', 'Weight Gravity', 'for the instance'),
|
||||
('Speed', 'Speed', 'for the instance')],
|
||||
name='', default='Speed', update=remove_extra_inputs)
|
||||
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxIntSocket', 'Slot')
|
||||
self.add_input('LnxFloatSocket', 'Speed', default_value=1.0)
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
layout.prop(self, 'property0')
|
||||
|
@ -0,0 +1,11 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class AutoExposureGetNode(LnxLogicTreeNode):
|
||||
"""Returns the auto exposure post-processing settings."""
|
||||
bl_idname = 'LNAutoExposureGetNode'
|
||||
bl_label = 'Get Auto Exposure Settings'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_output('LnxFloatSocket', 'Strength')
|
||||
self.add_output('LnxFloatSocket', 'Speed')
|
@ -1,11 +1,20 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class ChromaticAberrationGetNode(LnxLogicTreeNode):
|
||||
"""Returns the chromatic aberration post-processing settings."""
|
||||
"""Returns the chromatic aberration post-processing settings.
|
||||
Type: Simple 0 Spectral 1.
|
||||
"""
|
||||
bl_idname = 'LNChromaticAberrationGetNode'
|
||||
bl_label = 'Get CA Settings'
|
||||
lnx_version = 1
|
||||
lnx_version = 2
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_output('LnxFloatSocket', 'Strength')
|
||||
self.add_output('LnxFloatSocket', 'Samples')
|
||||
self.add_output('LnxIntSocket', 'Type')
|
||||
|
||||
def get_replacement_node(self, node_tree: bpy.types.NodeTree):
|
||||
if self.lnx_version not in (0, 1):
|
||||
raise LookupError()
|
||||
|
||||
return NodeReplacement.Identity(self)
|
@ -21,6 +21,7 @@ class CameraGetNode(LnxLogicTreeNode):
|
||||
self.add_output('LnxFloatSocket', 'Film Grain')#11
|
||||
self.add_output('LnxFloatSocket', 'Sharpen')#12
|
||||
self.add_output('LnxFloatSocket', 'Vignette')#13
|
||||
self.add_output('LnxFloatSocket', 'Exposure')#14
|
||||
|
||||
def get_replacement_node(self, node_tree: bpy.types.NodeTree):
|
||||
if self.lnx_version not in (0, 3):
|
||||
|
@ -0,0 +1,12 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class SharpenGetNode(LnxLogicTreeNode):
|
||||
"""Returns the sharpen post-processing settings."""
|
||||
bl_idname = 'LNSharpenGetNode'
|
||||
bl_label = 'Get Sharpen Settings'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_output('LnxColorSocket', 'Color')
|
||||
self.add_output('LnxFloatSocket', 'Size')
|
||||
self.add_output('LnxFloatSocket', 'Strength')
|
@ -0,0 +1,12 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class VolumetricFogGetNode(LnxLogicTreeNode):
|
||||
"""Returns the volumetric fog post-processing settings."""
|
||||
bl_idname = 'LNVolumetricFogGetNode'
|
||||
bl_label = 'Get Volumetric Fog Settings'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_output('LnxColorSocket', 'Color')
|
||||
self.add_output('LnxFloatSocket', 'Amount A')
|
||||
self.add_output('LnxFloatSocket', 'Amount B')
|
@ -0,0 +1,12 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class VolumetricLightGetNode(LnxLogicTreeNode):
|
||||
"""Returns the volumetric light post-processing settings."""
|
||||
bl_idname = 'LNVolumetricLightGetNode'
|
||||
bl_label = 'Get Volumetric Light Settings'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_output('LnxColorSocket', 'Air Color')
|
||||
self.add_output('LnxFloatSocket', 'Air Turbidity')
|
||||
self.add_output('LnxIntSocket', 'Steps')
|
@ -0,0 +1,14 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class AutoExposureSetNode(LnxLogicTreeNode):
|
||||
"""Set the sharpen post-processing settings."""
|
||||
bl_idname = 'LNAutoExposureSetNode'
|
||||
bl_label = 'Set Auto Exposure Settings'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxFloatSocket', 'Strength', default_value=1)
|
||||
self.add_input('LnxFloatSocket', 'Speed', default_value=1)
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
@ -1,14 +1,23 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class ChromaticAberrationSetNode(LnxLogicTreeNode):
|
||||
"""Set the chromatic aberration post-processing settings."""
|
||||
"""Set the chromatic aberration post-processing settings.
|
||||
Type: Simple 0 Spectral 1.
|
||||
"""
|
||||
bl_idname = 'LNChromaticAberrationSetNode'
|
||||
bl_label = 'Set CA Settings'
|
||||
lnx_version = 1
|
||||
lnx_version = 2
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxFloatSocket', 'Strength', default_value=2.0)
|
||||
self.add_input('LnxIntSocket', 'Samples', default_value=32)
|
||||
self.add_input('LnxIntSocket', 'Type', default_value=0)
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
|
||||
def get_replacement_node(self, node_tree: bpy.types.NodeTree):
|
||||
if self.lnx_version not in (0, 1):
|
||||
raise LookupError()
|
||||
|
||||
return NodeReplacement.Identity(self)
|
@ -4,27 +4,74 @@ class CameraSetNode(LnxLogicTreeNode):
|
||||
"""Set the post-processing effects of a camera."""
|
||||
bl_idname = 'LNCameraSetNode'
|
||||
bl_label = 'Set Camera Post Process'
|
||||
lnx_version = 4
|
||||
lnx_version = 5
|
||||
|
||||
|
||||
def remove_extra_inputs(self, context):
|
||||
while len(self.inputs) > 1:
|
||||
self.inputs.remove(self.inputs[-1])
|
||||
if self.property0 == 'F-stop':
|
||||
self.add_input('LnxFloatSocket', 'F-stop', default_value=1.0)#0
|
||||
if self.property0 == 'Shutter Time':
|
||||
self.add_input('LnxFloatSocket', 'Shutter Time', default_value=2.8333)#1
|
||||
if self.property0 == 'ISO':
|
||||
self.add_input('LnxFloatSocket', 'ISO', default_value=100.0)#2
|
||||
if self.property0 == 'Exposure Compensation':
|
||||
self.add_input('LnxFloatSocket', 'Exposure Compensation', default_value=0.0)#3
|
||||
if self.property0 == 'Fisheye Distortion':
|
||||
self.add_input('LnxFloatSocket', 'Fisheye Distortion', default_value=0.01)#4
|
||||
if self.property0 == 'Auto Focus':
|
||||
self.add_input('LnxBoolSocket', 'Auto Focus', default_value=True)#5
|
||||
if self.property0 == 'DoF Distance':
|
||||
self.add_input('LnxFloatSocket', 'DoF Distance', default_value=10.0)#6
|
||||
if self.property0 == 'DoF Length':
|
||||
self.add_input('LnxFloatSocket', 'DoF Length', default_value=160.0)#7
|
||||
if self.property0 == 'DoF F-Stop':
|
||||
self.add_input('LnxFloatSocket', 'DoF F-Stop', default_value=128.0)#8
|
||||
if self.property0 == 'Tonemapping':
|
||||
self.add_input('LnxBoolSocket', 'Tonemapping', default_value=False)#9
|
||||
if self.property0 == 'Distort':
|
||||
self.add_input('LnxFloatSocket', 'Distort', default_value=2.0)#10
|
||||
if self.property0 == 'Film Grain':
|
||||
self.add_input('LnxFloatSocket', 'Film Grain', default_value=2.0)#11
|
||||
if self.property0 == 'Sharpen':
|
||||
self.add_input('LnxFloatSocket', 'Sharpen', default_value=0.25)#12
|
||||
if self.property0 == 'Vignette':
|
||||
self.add_input('LnxFloatSocket', 'Vignette', default_value=0.7)#13
|
||||
if self.property0 == 'Exposure':
|
||||
self.add_input('LnxFloatSocket', 'Exposure', default_value=1)#14
|
||||
|
||||
|
||||
property0: HaxeEnumProperty(
|
||||
'property0',
|
||||
items = [('F-stop', 'F-stop', 'F-stop'),
|
||||
('Shutter Time', 'Shutter Time', 'Shutter Time'),
|
||||
('ISO', 'ISO', 'ISO'),
|
||||
('Exposure Compensation', 'Exposure Compensation', 'Exposure Compensation'),
|
||||
('Fisheye Distortion', 'Fisheye Distortion', 'Fisheye Distortion'),
|
||||
('Auto Focus', 'Auto Focus', 'Auto Focus'),
|
||||
('DoF Distance', 'DoF Distance', 'DoF Distance'),
|
||||
('DoF Length', 'DoF Length', 'DoF Length'),
|
||||
('DoF F-Stop', 'DoF F-Stop', 'DoF F-Stop'),
|
||||
('Tonemapping', 'Tonemapping', 'Tonemapping'),
|
||||
('Distort', 'Distort', 'Distort'),
|
||||
('Film Grain', 'Film Grain', 'Film Grain'),
|
||||
('Sharpen', 'Sharpen', 'Sharpen'),
|
||||
('Vignette', 'Vignette', 'Vignette'),
|
||||
('Exposure', 'Exposure', 'Exposure')],
|
||||
name='', default='F-stop', update=remove_extra_inputs)
|
||||
|
||||
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxFloatSocket', 'F-stop', default_value=1.0)#0
|
||||
self.add_input('LnxFloatSocket', 'Shutter Time', default_value=2.8333)#1
|
||||
self.add_input('LnxFloatSocket', 'ISO', default_value=100.0)#2
|
||||
self.add_input('LnxFloatSocket', 'Exposure Compensation', default_value=0.0)#3
|
||||
self.add_input('LnxFloatSocket', 'Fisheye Distortion', default_value=0.01)#4
|
||||
self.add_input('LnxBoolSocket', 'Auto Focus', default_value=True)#5
|
||||
self.add_input('LnxFloatSocket', 'DoF Distance', default_value=10.0)#6
|
||||
self.add_input('LnxFloatSocket', 'DoF Length', default_value=160.0)#7
|
||||
self.add_input('LnxFloatSocket', 'DoF F-Stop', default_value=128.0)#8
|
||||
self.add_input('LnxBoolSocket', 'Tonemapping', default_value=False)#9
|
||||
self.add_input('LnxFloatSocket', 'Distort', default_value=2.0)#10
|
||||
self.add_input('LnxFloatSocket', 'Film Grain', default_value=2.0)#11
|
||||
self.add_input('LnxFloatSocket', 'Sharpen', default_value=0.25)#12
|
||||
self.add_input('LnxFloatSocket', 'Vignette', default_value=0.7)#13
|
||||
self.add_input('LnxFloatSocket', 'F-stop', default_value=1.0)
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
layout.prop(self, 'property0')
|
||||
|
||||
def get_replacement_node(self, node_tree: bpy.types.NodeTree):
|
||||
if self.lnx_version not in range(0, 4):
|
||||
raise LookupError()
|
||||
|
@ -0,0 +1,15 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class SharpenSetNode(LnxLogicTreeNode):
|
||||
"""Set the sharpen post-processing settings."""
|
||||
bl_idname = 'LNSharpenSetNode'
|
||||
bl_label = 'Set Sharpen Settings'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxColorSocket', 'Color', default_value=[0.0, 0.0, 0.0, 1.0])
|
||||
self.add_input('LnxFloatSocket', 'Size', default_value=2.5)
|
||||
self.add_input('LnxFloatSocket', 'Strength', default_value=0.25)
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
@ -0,0 +1,15 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class VolumetricFogSetNode(LnxLogicTreeNode):
|
||||
"""Set the volumetric fog post-processing settings."""
|
||||
bl_idname = 'LNVolumetricFogSetNode'
|
||||
bl_label = 'Set Volumetric Fog Settings'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxColorSocket', 'Color', default_value=[0.5, 0.6, 0.7, 1.0])
|
||||
self.add_input('LnxFloatSocket', 'Amount A', default_value=0.25)
|
||||
self.add_input('LnxFloatSocket', 'Amount B', default_value=0.50)
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
@ -0,0 +1,15 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class VolumetricLightSetNode(LnxLogicTreeNode):
|
||||
"""Set the volumetric light post-processing settings."""
|
||||
bl_idname = 'LNVolumetricLightSetNode'
|
||||
bl_label = 'Set Volumetric Light Settings'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxColorSocket', 'Air Color', default_value=[1.0, 1.0, 1.0, 1.0])
|
||||
self.add_input('LnxFloatSocket', 'Air Turbidity', default_value=1)
|
||||
self.add_input('LnxIntSocket', 'Steps', default_value=20)
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
@ -4,12 +4,13 @@ class RpConfigNode(LnxLogicTreeNode):
|
||||
"""Sets the post process quality."""
|
||||
bl_idname = 'LNRpConfigNode'
|
||||
bl_label = 'Set Post Process Quality'
|
||||
lnx_version = 1
|
||||
lnx_version = 2
|
||||
property0: HaxeEnumProperty(
|
||||
'property0',
|
||||
items = [('SSGI', 'SSGI', 'SSGI'),
|
||||
('SSR', 'SSR', 'SSR'),
|
||||
('Bloom', 'Bloom', 'Bloom'),
|
||||
('CA', 'CA', 'CA'),
|
||||
('GI', 'GI', 'GI'),
|
||||
('Motion Blur', 'Motion Blur', 'Motion Blur')
|
||||
],
|
||||
@ -23,3 +24,10 @@ class RpConfigNode(LnxLogicTreeNode):
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
layout.prop(self, 'property0')
|
||||
|
||||
|
||||
def get_replacement_node(self, node_tree: bpy.types.NodeTree):
|
||||
if self.lnx_version not in (0, 1):
|
||||
raise LookupError()
|
||||
|
||||
return NodeReplacement.Identity(self)
|
@ -40,11 +40,11 @@ def add_world_defs():
|
||||
if rpdat.rp_hdr == False:
|
||||
wrd.world_defs += '_LDR'
|
||||
|
||||
if wrd.lnx_light_ies_texture != '':
|
||||
if lnx.utils.get_active_scene().world.lnx_light_ies_texture == True:
|
||||
wrd.world_defs += '_LightIES'
|
||||
assets.add_embedded_data('iestexture.png')
|
||||
|
||||
if wrd.lnx_light_clouds_texture != '':
|
||||
if lnx.utils.get_active_scene().world.lnx_light_clouds_texture == True:
|
||||
wrd.world_defs += '_LightClouds'
|
||||
assets.add_embedded_data('cloudstexture.png')
|
||||
|
||||
|
@ -82,28 +82,37 @@ def parse_clamp(node: bpy.types.ShaderNodeClamp, out_socket: bpy.types.NodeSocke
|
||||
|
||||
|
||||
def parse_valtorgb(node: bpy.types.ShaderNodeValToRGB, out_socket: bpy.types.NodeSocket, state: ParserState) -> Union[floatstr, vec3str]:
|
||||
# Alpha (TODO: make ColorRamp calculation vec4-based and split afterwards)
|
||||
if out_socket == node.outputs[1]:
|
||||
return '1.0'
|
||||
|
||||
input_fac: bpy.types.NodeSocket = node.inputs[0]
|
||||
|
||||
alpha_out = out_socket == node.outputs[1]
|
||||
fac: str = c.parse_value_input(input_fac) if input_fac.is_linked else c.to_vec1(input_fac.default_value)
|
||||
interp = node.color_ramp.interpolation
|
||||
elems = node.color_ramp.elements
|
||||
|
||||
|
||||
if len(elems) == 1:
|
||||
return c.to_vec3(elems[0].color)
|
||||
|
||||
# Write color array
|
||||
# The last entry is included twice so that the interpolation
|
||||
# between indices works (no out of bounds error)
|
||||
cols_var = c.node_name(node.name).upper() + '_COLS'
|
||||
if alpha_out:
|
||||
return c.to_vec1(elems[0].color[3]) # Return alpha from the color
|
||||
else:
|
||||
return c.to_vec3(elems[0].color) # Return RGB
|
||||
|
||||
name_prefix = c.node_name(node.name).upper()
|
||||
|
||||
if alpha_out:
|
||||
cols_var = name_prefix + '_ALPHAS'
|
||||
else:
|
||||
cols_var = name_prefix + '_COLS'
|
||||
|
||||
if state.current_pass == ParserPass.REGULAR:
|
||||
cols_entries = ', '.join(f'vec3({elem.color[0]}, {elem.color[1]}, {elem.color[2]})' for elem in elems)
|
||||
cols_entries += f', vec3({elems[len(elems) - 1].color[0]}, {elems[len(elems) - 1].color[1]}, {elems[len(elems) - 1].color[2]})'
|
||||
state.curshader.add_const("vec3", cols_var, cols_entries, array_size=len(elems) + 1)
|
||||
if alpha_out:
|
||||
cols_entries = ', '.join(f'{elem.color[3]}' for elem in elems)
|
||||
# Add last value twice to avoid out of bounds access
|
||||
cols_entries += f', {elems[len(elems) - 1].color[3]}'
|
||||
state.curshader.add_const("float", cols_var, cols_entries, array_size=len(elems) + 1)
|
||||
else:
|
||||
# Create array of RGB values for color output
|
||||
cols_entries = ', '.join(f'vec3({elem.color[0]}, {elem.color[1]}, {elem.color[2]})' for elem in elems)
|
||||
cols_entries += f', vec3({elems[len(elems) - 1].color[0]}, {elems[len(elems) - 1].color[1]}, {elems[len(elems) - 1].color[2]})'
|
||||
state.curshader.add_const("vec3", cols_var, cols_entries, array_size=len(elems) + 1)
|
||||
|
||||
fac_var = c.node_name(node.name) + '_fac' + state.get_parser_pass_suffix()
|
||||
state.curshader.write(f'float {fac_var} = {fac};')
|
||||
@ -121,21 +130,22 @@ def parse_valtorgb(node: bpy.types.ShaderNodeValToRGB, out_socket: bpy.types.Nod
|
||||
|
||||
# Linear interpolation
|
||||
else:
|
||||
# Write factor array
|
||||
facs_var = c.node_name(node.name).upper() + '_FACS'
|
||||
# Write factor array - same for both color and alpha
|
||||
facs_var = name_prefix + '_FACS'
|
||||
if state.current_pass == ParserPass.REGULAR:
|
||||
facs_entries = ', '.join(str(elem.position) for elem in elems)
|
||||
# Add one more entry at the rightmost position so that the
|
||||
# interpolation between indices works (no out of bounds error)
|
||||
# Add one more entry at the rightmost position to avoid out of bounds access
|
||||
facs_entries += ', 1.0'
|
||||
state.curshader.add_const("float", facs_var, facs_entries, array_size=len(elems) + 1)
|
||||
|
||||
# Mix color
|
||||
# Calculation for interpolation position
|
||||
prev_stop_fac = f'{facs_var}[{index_var}]'
|
||||
next_stop_fac = f'{facs_var}[{index_var} + 1]'
|
||||
prev_stop_col = f'{cols_var}[{index_var}]'
|
||||
next_stop_col = f'{cols_var}[{index_var} + 1]'
|
||||
rel_pos = f'({fac_var} - {prev_stop_fac}) * (1.0 / ({next_stop_fac} - {prev_stop_fac}))'
|
||||
|
||||
# Use mix function for both alpha and color outputs (mix works on floats too)
|
||||
return f'mix({prev_stop_col}, {next_stop_col}, max({rel_pos}, 0.0))'
|
||||
|
||||
if bpy.app.version > (3, 2, 0):
|
||||
|
@ -1,3 +1,4 @@
|
||||
import bpy
|
||||
import lnx.utils
|
||||
import lnx.material.mat_state as mat_state
|
||||
|
||||
@ -10,6 +11,48 @@ else:
|
||||
|
||||
def write(vert, particle_info=None, shadowmap=False):
|
||||
|
||||
ramp_el_len = 0
|
||||
|
||||
ramp_positions = []
|
||||
ramp_colors_b = []
|
||||
size_over_time_factor = 0
|
||||
|
||||
use_rotations = False
|
||||
rotation_mode = 'NONE'
|
||||
rotation_factor_random = 0
|
||||
phase_factor = 0
|
||||
phase_factor_random = 0
|
||||
|
||||
for obj in bpy.data.objects:
|
||||
for psys in obj.particle_systems:
|
||||
psettings = psys.settings
|
||||
|
||||
if psettings.instance_object:
|
||||
if psettings.instance_object.active_material:
|
||||
# FIXME: Different particle systems may share the same particle object. This ideally should check the correct `ParticleSystem` using an id or name in the particle's object material.
|
||||
if psettings.instance_object.active_material.name.replace(".", "_") == vert.context.matname:
|
||||
# Rotation data
|
||||
use_rotations = psettings.use_rotations
|
||||
rotation_mode = psettings.rotation_mode
|
||||
rotation_factor_random = psettings.rotation_factor_random
|
||||
phase_factor = psettings.phase_factor
|
||||
phase_factor_random = psettings.phase_factor_random
|
||||
|
||||
# Texture slots data
|
||||
if psettings.texture_slots and len(psettings.texture_slots.items()) != 0:
|
||||
for tex_slot in psettings.texture_slots:
|
||||
if not tex_slot: break
|
||||
if not tex_slot.use_map_size: break # TODO: check also for other influences
|
||||
if tex_slot.texture and tex_slot.texture.use_color_ramp:
|
||||
if tex_slot.texture.color_ramp and tex_slot.texture.color_ramp.elements:
|
||||
ramp_el_len = len(tex_slot.texture.color_ramp.elements.items())
|
||||
for element in tex_slot.texture.color_ramp.elements:
|
||||
ramp_positions.append(element.position)
|
||||
ramp_colors_b.append(element.color[2])
|
||||
size_over_time_factor = tex_slot.size_factor
|
||||
break
|
||||
|
||||
|
||||
# Outs
|
||||
out_index = True if particle_info != None and particle_info['index'] else False
|
||||
out_age = True if particle_info != None and particle_info['age'] else False
|
||||
@ -19,19 +62,50 @@ def write(vert, particle_info=None, shadowmap=False):
|
||||
out_velocity = True if particle_info != None and particle_info['velocity'] else False
|
||||
out_angular_velocity = True if particle_info != None and particle_info['angular_velocity'] else False
|
||||
|
||||
# Force Leenkx to create a new shader per material ID
|
||||
vert.write(f'#ifdef PARTICLE_ID_{vert.context.material.lnx_material_id}')
|
||||
vert.write('#endif')
|
||||
|
||||
vert.add_uniform('mat4 pd', '_particleData')
|
||||
vert.add_uniform('float pd_size_random', '_particleSizeRandom')
|
||||
vert.add_uniform('float pd_random', '_particleRandom')
|
||||
vert.add_uniform('float pd_size', '_particleSize')
|
||||
|
||||
if ramp_el_len != 0:
|
||||
vert.add_const('float', 'P_SIZE_OVER_TIME_FACTOR', str(size_over_time_factor))
|
||||
for i in range(ramp_el_len):
|
||||
vert.add_const('float', f'P_RAMP_POSITION_{i}', str(ramp_positions[i]))
|
||||
vert.add_const('float', f'P_RAMP_COLOR_B_{i}', str(ramp_colors_b[i]))
|
||||
|
||||
str_tex_hash = "float fhash(float n) { return fract(sin(n) * 43758.5453); }\n"
|
||||
vert.add_function(str_tex_hash)
|
||||
|
||||
|
||||
if (ramp_el_len != 0):
|
||||
str_ramp_scale = "float get_ramp_scale(float age) {\n"
|
||||
|
||||
for i in range(ramp_el_len):
|
||||
if i == 0:
|
||||
str_ramp_scale += f"if (age <= P_RAMP_POSITION_{i + 1})"
|
||||
elif i == ramp_el_len - 1:
|
||||
str_ramp_scale += f"return P_RAMP_COLOR_B_{ramp_el_len - 1};"
|
||||
break
|
||||
else:
|
||||
str_ramp_scale += f"else if (age <= P_RAMP_POSITION_{i + 1})"
|
||||
str_ramp_scale += f""" {{
|
||||
float t = (age - P_RAMP_POSITION_{i}) / (P_RAMP_POSITION_{i + 1} - P_RAMP_POSITION_{i});
|
||||
return mix(P_RAMP_COLOR_B_{i}, P_RAMP_COLOR_B_{i + 1}, t);
|
||||
}}
|
||||
"""
|
||||
str_ramp_scale += "}\n"
|
||||
vert.add_function(str_ramp_scale)
|
||||
|
||||
prep = 'float '
|
||||
if out_age:
|
||||
prep = ''
|
||||
vert.add_out('float p_age')
|
||||
# var p_age = lapTime - p.i * spawnRate
|
||||
vert.write(prep + 'p_age = pd[3][3] - gl_InstanceID * pd[0][1];')
|
||||
# p_age -= p_age * fhash(i) * r.lifetime_random;
|
||||
vert.write('p_age -= p_age * fhash(gl_InstanceID) * pd[2][3];')
|
||||
|
||||
# Loop
|
||||
# pd[0][0] - animtime, loop stored in sign
|
||||
@ -43,13 +117,18 @@ def write(vert, particle_info=None, shadowmap=False):
|
||||
if out_lifetime:
|
||||
prep = ''
|
||||
vert.add_out('float p_lifetime')
|
||||
vert.write(prep + 'p_lifetime = pd[0][2];')
|
||||
vert.write(prep + 'p_lifetime = pd[0][2] * (1 - (fhash(gl_InstanceID + 4 * pd[0][3] + pd_random) * pd[2][3]));')
|
||||
# clip with nan
|
||||
vert.write('if (p_age < 0 || p_age > p_lifetime) {')
|
||||
vert.write(' gl_Position /= 0.0;')
|
||||
vert.write(' return;')
|
||||
vert.write('}')
|
||||
|
||||
if (ramp_el_len != 0):
|
||||
vert.write('float n_age = clamp(p_age / p_lifetime, 0.0, 1.0);')
|
||||
vert.write(f'spos.xyz *= 1 + (get_ramp_scale(n_age) - 1) * {size_over_time_factor};')
|
||||
vert.write('spos.xyz *= 1 - (fhash(gl_InstanceID + 3 * pd[0][3] + pd_random) * pd_size_random);')
|
||||
|
||||
# vert.write('p_age /= 2;') # Match
|
||||
|
||||
# object_align_factor / 2 + gxyz
|
||||
@ -57,20 +136,20 @@ def write(vert, particle_info=None, shadowmap=False):
|
||||
if out_velocity:
|
||||
prep = ''
|
||||
vert.add_out('vec3 p_velocity')
|
||||
vert.write(prep + 'p_velocity = vec3(pd[1][0], pd[1][1], pd[1][2]);')
|
||||
vert.write(prep + 'p_velocity = vec3(pd[1][0] * (1 / pd_size), pd[1][1] * (1 / pd_size), pd[1][2] * (1 / pd_size));')
|
||||
|
||||
vert.write('p_velocity.x += fhash(gl_InstanceID) * pd[1][3] - pd[1][3] / 2;')
|
||||
vert.write('p_velocity.y += fhash(gl_InstanceID + pd[0][3]) * pd[1][3] - pd[1][3] / 2;')
|
||||
vert.write('p_velocity.z += fhash(gl_InstanceID + 2 * pd[0][3]) * pd[1][3] - pd[1][3] / 2;')
|
||||
vert.write('p_velocity.x += (fhash(gl_InstanceID + pd_random) * 2.0 / pd_size - 1.0 / pd_size) * pd[1][3];')
|
||||
vert.write('p_velocity.y += (fhash(gl_InstanceID + pd_random + pd[0][3]) * 2.0 / pd_size - 1.0 / pd_size) * pd[1][3];')
|
||||
vert.write('p_velocity.z += (fhash(gl_InstanceID + pd_random + 2 * pd[0][3]) * 2.0 / pd_size - 1.0 / pd_size) * pd[1][3];')
|
||||
|
||||
# factor_random = pd[1][3]
|
||||
# p.i = gl_InstanceID
|
||||
# particles.length = pd[0][3]
|
||||
|
||||
# gxyz
|
||||
vert.write('p_velocity.x += (pd[2][0] * p_age) / 5;')
|
||||
vert.write('p_velocity.y += (pd[2][1] * p_age) / 5;')
|
||||
vert.write('p_velocity.z += (pd[2][2] * p_age) / 5;')
|
||||
vert.write('p_velocity.x += (pd[2][0] / (2 * pd_size)) * p_age;')
|
||||
vert.write('p_velocity.y += (pd[2][1] / (2 * pd_size)) * p_age;')
|
||||
vert.write('p_velocity.z += (pd[2][2] / (2 * pd_size)) * p_age;')
|
||||
|
||||
prep = 'vec3 '
|
||||
if out_location:
|
||||
@ -80,6 +159,96 @@ def write(vert, particle_info=None, shadowmap=False):
|
||||
|
||||
vert.write('spos.xyz += p_location;')
|
||||
|
||||
# Rotation
|
||||
if use_rotations:
|
||||
if rotation_mode != 'NONE':
|
||||
vert.write(f'float p_angle = ({phase_factor} + (fhash(gl_InstanceID + pd_random + 5 * pd[0][3])) * {phase_factor_random});')
|
||||
vert.write('p_angle *= 3.141592;')
|
||||
vert.write('float c = cos(p_angle);')
|
||||
vert.write('float s = sin(p_angle);')
|
||||
vert.write('vec3 center = spos.xyz - p_location;')
|
||||
|
||||
match rotation_mode:
|
||||
case 'OB_X':
|
||||
vert.write('vec3 rz = vec3(center.y, -center.x, center.z);')
|
||||
vert.write('vec2 rotation = vec2(rz.y * c - rz.z * s, rz.y * s + rz.z * c);')
|
||||
vert.write('spos.xyz = vec3(rz.x, rotation.x, rotation.y) + p_location;')
|
||||
|
||||
if (not shadowmap):
|
||||
vert.write('wnormal = vec3(wnormal.y, -wnormal.x, wnormal.z);')
|
||||
vert.write('vec2 n_rot = vec2(wnormal.y * c - wnormal.z * s, wnormal.y * s + wnormal.z * c);')
|
||||
vert.write('wnormal = normalize(vec3(wnormal.x, n_rot.x, n_rot.y));')
|
||||
case 'OB_Y':
|
||||
vert.write('vec2 rotation = vec2(center.x * c + center.z * s, -center.x * s + center.z * c);')
|
||||
vert.write('spos.xyz = vec3(rotation.x, center.y, rotation.y) + p_location;')
|
||||
|
||||
if (not shadowmap):
|
||||
vert.write('wnormal = normalize(vec3(wnormal.x * c + wnormal.z * s, wnormal.y, -wnormal.x * s + wnormal.z * c));')
|
||||
case 'OB_Z':
|
||||
vert.write('vec3 rz = vec3(center.y, -center.x, center.z);')
|
||||
vert.write('vec3 ry = vec3(-rz.z, rz.y, rz.x);')
|
||||
vert.write('vec2 rotation = vec2(ry.x * c - ry.y * s, ry.x * s + ry.y * c);')
|
||||
vert.write('spos.xyz = vec3(rotation.x, rotation.y, ry.z) + p_location;')
|
||||
|
||||
if (not shadowmap):
|
||||
vert.write('wnormal = vec3(wnormal.y, -wnormal.x, wnormal.z);')
|
||||
vert.write('wnormal = vec3(-wnormal.z, wnormal.y, wnormal.x);')
|
||||
vert.write('vec2 n_rot = vec2(wnormal.x * c - wnormal.y * s, wnormal.x * s + wnormal.y * c);')
|
||||
vert.write('wnormal = normalize(vec3(n_rot.x, n_rot.y, wnormal.z));')
|
||||
case 'VEL':
|
||||
vert.write('vec3 forward = -normalize(p_velocity);')
|
||||
vert.write('if (length(forward) > 1e-5) {')
|
||||
vert.write('vec3 world_up = vec3(0.0, 0.0, 1.0);')
|
||||
|
||||
vert.write('if (abs(dot(forward, world_up)) > 0.999) {')
|
||||
vert.write('world_up = vec3(-1.0, 0.0, 0.0);')
|
||||
vert.write('}')
|
||||
|
||||
vert.write('vec3 right = cross(world_up, forward);')
|
||||
vert.write('if (length(right) < 1e-5) {')
|
||||
vert.write('forward = -forward;')
|
||||
vert.write('right = cross(world_up, forward);')
|
||||
vert.write('}')
|
||||
vert.write('right = normalize(right);')
|
||||
vert.write('vec3 up = normalize(cross(forward, right));')
|
||||
|
||||
vert.write('mat3 rot = mat3(right, -forward, up);')
|
||||
vert.write('mat3 phase = mat3(vec3(c, 0.0, -s), vec3(0.0, 1.0, 0.0), vec3(s, 0.0, c));')
|
||||
vert.write('mat3 final_rot = rot * phase;')
|
||||
vert.write('spos.xyz = final_rot * center + p_location;')
|
||||
|
||||
if (not shadowmap):
|
||||
vert.write('wnormal = normalize(final_rot * wnormal);')
|
||||
vert.write('}')
|
||||
|
||||
if rotation_factor_random != 0:
|
||||
str_rotate_around = '''vec3 rotate_around(vec3 v, vec3 angle) {
|
||||
// Rotate around X
|
||||
float cx = cos(angle.x);
|
||||
float sx = sin(angle.x);
|
||||
v = vec3(v.x, v.y * cx - v.z * sx, v.y * sx + v.z * cx);
|
||||
// Rotate around Y
|
||||
float cy = cos(angle.y);
|
||||
float sy = sin(angle.y);
|
||||
v = vec3(v.x * cy + v.z * sy, v.y, -v.x * sy + v.z * cy);
|
||||
// Rotate around Z
|
||||
float cz = cos(angle.z);
|
||||
float sz = sin(angle.z);
|
||||
v = vec3(v.x * cz - v.y * sz, v.x * sz + v.y * cz, v.z);
|
||||
return v;
|
||||
}'''
|
||||
vert.add_function(str_rotate_around)
|
||||
|
||||
vert.write(f'''vec3 r_angle = vec3((fhash(gl_InstanceID + pd_random + 6 * pd[0][3]) * 4 - 2) * {rotation_factor_random},
|
||||
(fhash(gl_InstanceID + pd_random + 7 * pd[0][3]) * 4 - 2) * {rotation_factor_random},
|
||||
(fhash(gl_InstanceID + pd_random + 8 * pd[0][3]) * 4 - 2) * {rotation_factor_random});''')
|
||||
vert.write('vec3 r_center = spos.xyz - p_location;')
|
||||
vert.write('r_center = rotate_around(r_center, r_angle);')
|
||||
vert.write('spos.xyz = r_center + p_location;')
|
||||
|
||||
if not shadowmap:
|
||||
vert.write('wnormal = normalize(rotate_around(wnormal, r_angle));')
|
||||
|
||||
# Particle fade
|
||||
if mat_state.material.lnx_particle_flag and lnx.utils.get_rp().lnx_particles == 'On' and mat_state.material.lnx_particle_fade:
|
||||
vert.add_out('float p_fade')
|
||||
|
@ -197,6 +197,10 @@ def init_properties():
|
||||
items=[('Bullet', 'Bullet', 'Bullet'),
|
||||
('Oimo', 'Oimo', 'Oimo')],
|
||||
name="Physics Engine", default='Bullet', update=assets.invalidate_compiler_cache)
|
||||
bpy.types.World.lnx_physics_fixed_step = FloatProperty(
|
||||
name="Fixed Step", default=1/60, min=0, max=1,
|
||||
description="Physics steps for fixed update"
|
||||
)
|
||||
bpy.types.World.lnx_physics_dbg_draw_wireframe = BoolProperty(
|
||||
name="Collider Wireframes", default=False,
|
||||
description="Draw wireframes of the physics collider meshes and suspensions of raycast vehicle simulations"
|
||||
@ -358,6 +362,7 @@ def init_properties():
|
||||
bpy.types.Object.lnx_rb_trigger = BoolProperty(name="Trigger", description="Disable contact response", default=False)
|
||||
bpy.types.Object.lnx_rb_deactivation_time = FloatProperty(name="Deactivation Time", description="Delay putting rigid body into sleep", default=0.0)
|
||||
bpy.types.Object.lnx_rb_ccd = BoolProperty(name="Continuous Collision Detection", description="Improve collision for fast moving objects", default=False)
|
||||
bpy.types.Object.lnx_rb_interpolate = BoolProperty(name="Interpolation", description="Smooths out the object's transform on physics steps", default=False)
|
||||
bpy.types.Object.lnx_rb_collision_filter_mask = bpy.props.BoolVectorProperty(
|
||||
name="Collision Collections Filter Mask",
|
||||
description="Collision collections rigid body interacts with",
|
||||
@ -506,8 +511,9 @@ def init_properties():
|
||||
bpy.types.Light.lnx_clip_end = FloatProperty(name="Clip End", default=50.0)
|
||||
bpy.types.Light.lnx_fov = FloatProperty(name="Field of View", default=0.84)
|
||||
bpy.types.Light.lnx_shadows_bias = FloatProperty(name="Bias", description="Depth offset to fight shadow acne", default=1.0)
|
||||
bpy.types.World.lnx_light_ies_texture = StringProperty(name="IES Texture", default="")
|
||||
bpy.types.World.lnx_light_clouds_texture = StringProperty(name="Clouds Texture", default="")
|
||||
# For world
|
||||
bpy.types.World.lnx_light_ies_texture = BoolProperty(name="IES Texture (iestexture.png)", default=False, update=assets.invalidate_compiler_cache)
|
||||
bpy.types.World.lnx_light_clouds_texture = BoolProperty(name="Clouds Texture (cloudstexture.png)", default=False, update=assets.invalidate_compiler_cache)
|
||||
|
||||
bpy.types.World.lnx_rpcache_list = CollectionProperty(type=bpy.types.PropertyGroup)
|
||||
bpy.types.World.lnx_scripts_list = CollectionProperty(type=bpy.types.PropertyGroup)
|
||||
@ -542,8 +548,10 @@ def init_properties():
|
||||
bpy.types.Node.lnx_watch = BoolProperty(name="Watch", description="Watch value of this node in debug console", default=False)
|
||||
bpy.types.Node.lnx_version = IntProperty(name="Node Version", description="The version of an instanced node", default=0)
|
||||
# Particles
|
||||
bpy.types.ParticleSettings.lnx_count_mult = FloatProperty(name="Multiply Count", description="Multiply particle count when rendering in Leenkx", default=1.0)
|
||||
bpy.types.ParticleSettings.lnx_auto_start = BoolProperty(name="Auto Start", description="Automatically start this particle system on load", default=True)
|
||||
bpy.types.ParticleSettings.lnx_is_unique = BoolProperty(name="Is Unique", description="Make this particle system look different each time it starts", default=False)
|
||||
bpy.types.ParticleSettings.lnx_loop = BoolProperty(name="Loop", description="Loop this particle system", default=False)
|
||||
bpy.types.ParticleSettings.lnx_count_mult = FloatProperty(name="Multiply Count", description="Multiply particle count when rendering in Leenkx", default=1.0)
|
||||
# Actions
|
||||
bpy.types.Action.lnx_root_motion_pos = BoolProperty(name="Root Motion Position", description="Enable position root motion", default=False)
|
||||
bpy.types.Action.lnx_root_motion_rot = BoolProperty(name="Root Motion Rotation", description="Enable rotation root motion", default=False)
|
||||
|
@ -608,6 +608,8 @@ class LnxRPListItem(bpy.types.PropertyGroup):
|
||||
lnx_grain: BoolProperty(name="Film Grain", default=False, update=assets.invalidate_shader_cache)
|
||||
lnx_grain_strength: FloatProperty(name="Strength", default=2.0, update=assets.invalidate_shader_cache)
|
||||
lnx_sharpen: BoolProperty(name="Sharpen", default=False, update=assets.invalidate_shader_cache)
|
||||
lnx_sharpen_color: FloatVectorProperty(name="Color", size=3, default=[0, 0, 0], subtype='COLOR', min=0, max=1, update=assets.invalidate_shader_cache)
|
||||
lnx_sharpen_size: FloatProperty(name="Size", default=2.5, update=assets.invalidate_shader_cache)
|
||||
lnx_sharpen_strength: FloatProperty(name="Strength", default=0.25, update=assets.invalidate_shader_cache)
|
||||
lnx_fog: BoolProperty(name="Volumetric Fog", default=False, update=assets.invalidate_shader_cache)
|
||||
lnx_fog_color: FloatVectorProperty(name="Color", size=3, subtype='COLOR', default=[0.5, 0.6, 0.7], min=0, max=1, update=assets.invalidate_shader_cache)
|
||||
|
@ -205,6 +205,8 @@ class LNX_PT_ParticlesPropsPanel(bpy.types.Panel):
|
||||
if obj == None:
|
||||
return
|
||||
|
||||
layout.prop(obj.settings, 'lnx_auto_start')
|
||||
layout.prop(obj.settings, 'lnx_is_unique')
|
||||
layout.prop(obj.settings, 'lnx_loop')
|
||||
layout.prop(obj.settings, 'lnx_count_mult')
|
||||
|
||||
@ -240,6 +242,7 @@ class LNX_PT_PhysicsPropsPanel(bpy.types.Panel):
|
||||
layout.prop(obj, 'lnx_rb_angular_friction')
|
||||
layout.prop(obj, 'lnx_rb_trigger')
|
||||
layout.prop(obj, 'lnx_rb_ccd')
|
||||
layout.prop(obj, 'lnx_rb_interpolate')
|
||||
|
||||
if obj.soft_body is not None:
|
||||
layout.prop(obj, 'lnx_soft_body_margin')
|
||||
@ -303,8 +306,6 @@ class LNX_PT_DataPropsPanel(bpy.types.Panel):
|
||||
layout.prop(obj.data, 'lnx_clip_end')
|
||||
layout.prop(obj.data, 'lnx_fov')
|
||||
layout.prop(obj.data, 'lnx_shadows_bias')
|
||||
layout.prop(wrd, 'lnx_light_ies_texture')
|
||||
layout.prop(wrd, 'lnx_light_clouds_texture')
|
||||
elif obj.type == 'SPEAKER':
|
||||
layout.prop(obj.data, 'lnx_play_on_start')
|
||||
layout.prop(obj.data, 'lnx_loop')
|
||||
@ -332,6 +333,8 @@ class LNX_PT_WorldPropsPanel(bpy.types.Panel):
|
||||
if world is None:
|
||||
return
|
||||
|
||||
layout.prop(world, 'lnx_light_ies_texture')
|
||||
layout.prop(world, 'lnx_light_clouds_texture')
|
||||
layout.prop(world, 'lnx_use_clouds')
|
||||
col = layout.column(align=True)
|
||||
col.enabled = world.lnx_use_clouds
|
||||
@ -1991,10 +1994,18 @@ class LNX_PT_RenderPathCompositorPanel(bpy.types.Panel):
|
||||
col.prop(rpdat, 'lnx_letterbox_size')
|
||||
layout.separator()
|
||||
|
||||
col = layout.column()
|
||||
col.prop(rpdat, 'lnx_sharpen')
|
||||
col = col.column(align=True)
|
||||
col.enabled = rpdat.lnx_sharpen
|
||||
col.prop(rpdat, 'lnx_sharpen_color')
|
||||
col.prop(rpdat, 'lnx_sharpen_size')
|
||||
col.prop(rpdat, 'lnx_sharpen_strength')
|
||||
layout.separator()
|
||||
|
||||
col = layout.column()
|
||||
draw_conditional_prop(col, 'Distort', rpdat, 'lnx_distort', 'lnx_distort_strength')
|
||||
draw_conditional_prop(col, 'Film Grain', rpdat, 'lnx_grain', 'lnx_grain_strength')
|
||||
draw_conditional_prop(col, 'Sharpen', rpdat, 'lnx_sharpen', 'lnx_sharpen_strength')
|
||||
draw_conditional_prop(col, 'Vignette', rpdat, 'lnx_vignette', 'lnx_vignette_strength')
|
||||
layout.separator()
|
||||
|
||||
@ -2732,8 +2743,33 @@ class LeenkxUpdateListInstalledVSButton(bpy.types.Operator):
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
class LNX_PT_PhysicsProps(bpy.types.Panel):
|
||||
bl_label = "Leenkx Props"
|
||||
bl_space_type = "PROPERTIES"
|
||||
bl_region_type = "WINDOW"
|
||||
bl_context = "scene"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
bl_parent_id = "SCENE_PT_rigid_body_world"
|
||||
|
||||
class LNX_PT_BulletDebugDrawingPanel(bpy.types.Panel):
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.scene.rigidbody_world is not None
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
layout.use_property_decorate = False
|
||||
wrd = bpy.data.worlds['Lnx']
|
||||
|
||||
if wrd.lnx_physics_engine != 'Bullet' and wrd.lnx_physics_engine != 'Oimo':
|
||||
row = layout.row()
|
||||
row.alert = True
|
||||
row.label(text="Physics debug drawing is only supported for the Bullet and Oimo physics engines")
|
||||
|
||||
col = layout.column(align=False)
|
||||
col.prop(wrd, "lnx_physics_fixed_step")
|
||||
|
||||
class LNX_PT_PhysicsDebugDrawingPanel(bpy.types.Panel):
|
||||
bl_label = "Leenkx Debug Drawing"
|
||||
bl_space_type = "PROPERTIES"
|
||||
bl_region_type = "WINDOW"
|
||||
@ -2899,7 +2935,8 @@ __REG_CLASSES = (
|
||||
LeenkxUpdateListAndroidEmulatorButton,
|
||||
LeenkxUpdateListAndroidEmulatorRunButton,
|
||||
LeenkxUpdateListInstalledVSButton,
|
||||
LNX_PT_BulletDebugDrawingPanel,
|
||||
LNX_PT_PhysicsProps,
|
||||
LNX_PT_PhysicsDebugDrawingPanel,
|
||||
LNX_OT_AddArmatureRootMotion,
|
||||
scene.TLM_PT_Settings,
|
||||
scene.TLM_PT_Denoise,
|
||||
|
@ -453,6 +453,7 @@ def write_config(resx, resy):
|
||||
'rp_ssr': rpdat.rp_ssr != 'Off',
|
||||
'rp_ss_refraction': rpdat.rp_ss_refraction != 'Off',
|
||||
'rp_bloom': rpdat.rp_bloom != 'Off',
|
||||
'rp_chromatic_aberration': rpdat.rp_chromatic_aberration != 'Off',
|
||||
'rp_motionblur': rpdat.rp_motionblur != 'Off',
|
||||
'rp_gi': rpdat.rp_voxels != "Off",
|
||||
'rp_dynres': rpdat.rp_dynres
|
||||
@ -772,6 +773,8 @@ const vec3 compoLetterboxColor = vec3(""" + str(round(rpdat.lnx_letterbox_color[
|
||||
if lnx.utils.get_active_scene().view_settings.exposure != 0.0:
|
||||
f.write(
|
||||
"""const float compoExposureStrength = """ + str(round(lnx.utils.get_active_scene().view_settings.exposure * 100) / 100) + """;
|
||||
const float compoSharpenSize = """ + str(round(rpdat.lnx_sharpen_size * 100) / 100) + """;
|
||||
const vec3 compoSharpenColor = vec3(""" + str(round(rpdat.lnx_sharpen_color[0] * 100) / 100) + """, """ + str(round(rpdat.lnx_sharpen_color[1] * 100) / 100) + """, """ + str(round(rpdat.lnx_sharpen_color[2] * 100) / 100) + """);
|
||||
""")
|
||||
|
||||
if rpdat.lnx_fog:
|
||||
|
Reference in New Issue
Block a user