Skip to content

Commit 79bf9a6

Browse files
committed
Add basic SopotLight instancing
1 parent 843deeb commit 79bf9a6

12 files changed

Lines changed: 204 additions & 19 deletions

File tree

addons/libmaszyna/e3d/e3d_instancer.gd

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ func _is_submodel_valid(target_node: E3DModelInstance, submodel: E3DSubModel) ->
2222
return false
2323

2424
match submodel.submodel_type:
25-
E3DSubModel.SubModelType.SUBMODEL_TRANSFORM:
25+
E3DSubModel.SubModelType.SUBMODEL_TRANSFORM, \
26+
E3DSubModel.SubModelType.SUBMODEL_FREE_SPOTLIGHT:
2627
return true
2728
E3DSubModel.SubModelType.SUBMODEL_GL_TRIANGLES:
2829
return not target_node.exclude_node_names.any(

addons/libmaszyna/e3d/e3d_light.gd

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
@tool
2+
extends SpotLight3D
3+
4+
var meshes_on: Array[Node3D] = []
5+
var meshes_off: Array[Node3D] = []
6+
7+
@export var enabled: bool = true:
8+
set(v):
9+
enabled = v
10+
_update_state()
11+
12+
func _ready():
13+
_update_state()
14+
15+
func _update_state():
16+
var parent = get_parent()
17+
if parent == null:
18+
return
19+
var light_root = parent.get_parent()
20+
var is_end = parent.name.begins_with("end")
21+
if (!is_end):
22+
var base_name = parent.name.trim_suffix("_on")
23+
var lamp_off_node = light_root.get_node_or_null(NodePath(base_name + "_off"))
24+
parent.visible = enabled
25+
if lamp_off_node != null:
26+
lamp_off_node.visible = !enabled
27+
else:
28+
parent.visible = enabled
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
uid://da34nclo40y7h

addons/libmaszyna/e3d/e3d_nodes_instancer.gd

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,31 @@ extends E3DInstancer
33

44

55
func instantiate(target_node: E3DModelInstance, model: E3DModel, editable: bool = false) -> void:
6-
_do_add_submodels(target_node, target_node, model.submodels, editable)
6+
var lights = []
7+
_do_add_submodels(target_node, target_node, model.submodels, editable, lights)
8+
_link_lights(target_node, lights)
9+
10+
11+
func _link_lights(target_node: E3DModelInstance, lights: Array) -> void:
12+
var all_nodes = target_node.find_children("*", "Node3D", true, true)
13+
var node_map = {}
14+
for node in all_nodes:
15+
node_map[node.name.to_lower()] = node
16+
17+
for light in lights:
18+
var base_name = light.name.to_lower()
19+
20+
var on_suffixes = ["_on", "_xon"]
21+
for suffix in on_suffixes:
22+
var on_node = node_map.get(base_name + suffix)
23+
if on_node:
24+
light.meshes_on.append(on_node)
25+
26+
var off_node = node_map.get(base_name + "_off")
27+
if off_node:
28+
light.meshes_off.append(off_node)
29+
30+
light._update_state()
731

832

933
func clear(target_node: E3DModelInstance) -> void:
@@ -20,11 +44,18 @@ func _do_add_submodels(
2044
target_node:E3DModelInstance,
2145
parent,
2246
submodels,
23-
editable:bool
47+
editable:bool,
48+
lights: Array = []
2449
) -> void:
2550
for submodel in submodels:
2651
if _is_submodel_valid(target_node, submodel):
2752
var child:Node = _create_submodel_instance(target_node, submodel)
53+
if not child:
54+
continue
55+
56+
if child.has_method("_update_state"):
57+
lights.append(child)
58+
2859
_update_submodel_material(target_node, child, submodel)
2960
var internal = InternalMode.INTERNAL_MODE_DISABLED if editable else InternalMode.INTERNAL_MODE_BACK
3061
parent.add_child(child, false, internal)
@@ -33,12 +64,17 @@ func _do_add_submodels(
3364
# Applying transform before adding may cause issues (especially on windows)
3465
if child is Node3D and submodel.transform:
3566
var child_node:Node3D = child as Node3D
36-
child_node.transform = submodel.transform
67+
if child is SpotLight3D:
68+
# Do not scale SpotLight3D to avoid configuration warnings
69+
child_node.position = submodel.transform.origin
70+
child_node.basis = submodel.transform.basis.orthonormalized()
71+
else:
72+
child_node.transform = submodel.transform
3773

3874
if Engine.is_editor_hint():
3975
child.owner = target_node.owner if editable else target_node
4076
if submodel.submodels:
41-
_do_add_submodels(target_node, child, submodel.submodels, editable)
77+
_do_add_submodels(target_node, child, submodel.submodels, editable, lights)
4278

4379

4480
func _create_submodel_instance(target_node: E3DModelInstance, submodel: E3DSubModel):
@@ -56,6 +92,20 @@ func _create_submodel_instance(target_node: E3DModelInstance, submodel: E3DSubMo
5692
obj.visibility_range_begin = submodel.visibility_range_begin
5793
obj.visibility_range_end = submodel.visibility_range_end
5894

95+
E3DSubModel.SubModelType.SUBMODEL_FREE_SPOTLIGHT:
96+
obj = SpotLight3D.new()
97+
obj.set_script(preload("res://addons/libmaszyna/e3d/e3d_light.gd"))
98+
obj.name = submodel.resource_name
99+
obj.light_color = submodel.diffuse_color
100+
obj.light_energy = 10.0
101+
obj.shadow_enabled = true
102+
obj.distance_fade_enabled = true
103+
obj.spot_range = submodel.light_range if submodel.light_range > 0.0 else 20.0
104+
obj.spot_angle = submodel.light_angle
105+
obj.spot_attenuation = submodel.light_attenuation
106+
obj.distance_fade_begin = submodel.near_atten_start
107+
obj.enabled = submodel.visible
108+
59109
if obj:
60110
obj.visible = submodel.visible
61111
return obj

demo/demo_3d.tscn

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,9 @@ fog_enabled = true
5454
fog_sky_affect = 0.4
5555
volumetric_fog_enabled = true
5656
volumetric_fog_density = 0.029
57-
volumetric_fog_anisotropy = 0.9
58-
volumetric_fog_length = 0.5
59-
volumetric_fog_detail_spread = 5.598199
57+
volumetric_fog_anisotropy = 0.0
58+
volumetric_fog_length = 0.4
59+
volumetric_fog_detail_spread = 1.0
6060
volumetric_fog_sky_affect = 0.405
6161
adjustment_enabled = true
6262

@@ -226,6 +226,7 @@ clip_contents = true
226226
layout_mode = 2
227227

228228
[node name="DeveloperConsole" parent="." unique_id=495569075 instance=ExtResource("2_ig825")]
229+
visible = null
229230

230231
[node name="UserSettingsPanel" parent="." unique_id=1798306963 instance=ExtResource("12_eihw1")]
231232

doc_classes/E3DSubModel.xml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,33 @@
2121
<member name="dynamic_material_index" type="int" setter="set_dynamic_material_index" getter="get_dynamic_material_index" default="0">
2222
The index mapping for the dynamic material state.
2323
</member>
24+
<member name="light_angle" type="float" setter="set_light_angle" getter="get_light_angle" default="45.0">
25+
The cone angle of the spotlight in degrees.
26+
</member>
27+
<member name="light_attenuation" type="float" setter="set_light_attenuation" getter="get_light_attenuation" default="1.0">
28+
The attenuation factor of the light source.
29+
</member>
30+
<member name="light_range" type="float" setter="set_light_range" getter="get_light_range" default="0.0">
31+
The maximum range of the light source.
32+
</member>
33+
<member name="near_atten_start" type="float" setter="set_near_atten_start" getter="get_near_atten_start" default="0.0">
34+
Distance where the near attenuation starts (used for halo/aureola effects).
35+
</member>
36+
<member name="near_atten_end" type="float" setter="set_near_atten_end" getter="get_near_atten_end" default="0.0">
37+
Distance where the near attenuation ends.
38+
</member>
39+
<member name="use_near_atten" type="bool" setter="set_use_near_atten" getter="get_use_near_atten" default="false">
40+
If [code]true[/code], near attenuation (halo effects) are enabled for this light source.
41+
</member>
42+
<member name="far_atten_decay" type="int" setter="set_far_atten_decay" getter="get_far_atten_decay" default="0">
43+
The type of distance attenuation (0: none, 1 or 2: inverse distance powers).
44+
</member>
45+
<member name="cos_hotspot_angle" type="float" setter="set_cos_hotspot_angle" getter="get_cos_hotspot_angle" default="0.0">
46+
Cosine of the inner hotspot cone angle.
47+
</member>
48+
<member name="cos_view_angle" type="float" setter="set_cos_view_angle" getter="get_cos_view_angle" default="0.0">
49+
Cosine of the current viewing angle (used for visibility calculation).
50+
</member>
2451
<member name="lights_on_threshold" type="float" setter="set_lights_on_threshold" getter="get_lights_on_threshold" default="0.0">
2552
The ambient light level threshold at which the submodel's self-illumination becomes active.
2653
</member>

src/e3d/E3DModel.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ namespace godot {
77
class E3DModel : public Resource {
88
GDCLASS(E3DModel, Resource)
99
public:
10-
static constexpr int FORMAT_VERSION = 20260504; // must be incremented when public API of E3DModel or
10+
static constexpr int FORMAT_VERSION = 20260510; // must be incremented when public API of E3DModel or
1111
// E3DSubModel is changing
1212
~E3DModel() override;
1313

src/e3d/E3DSubModel.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,34 @@ namespace godot {
128128
BIND_PROPERTY(
129129
Variant::BOOL, "skip_rendering", "skip_rendering", &E3DSubModel::set_skip_rendering,
130130
&E3DSubModel::get_skip_rendering, "p_skip_rendering");
131+
132+
BIND_PROPERTY(
133+
Variant::FLOAT, "light_range", "light_range", &E3DSubModel::set_light_range,
134+
&E3DSubModel::get_light_range, "p_light_range");
135+
BIND_PROPERTY(
136+
Variant::FLOAT, "light_attenuation", "light_attenuation", &E3DSubModel::set_light_attenuation,
137+
&E3DSubModel::get_light_attenuation, "p_light_attenuation");
138+
BIND_PROPERTY(
139+
Variant::FLOAT, "light_angle", "light_angle", &E3DSubModel::set_light_angle,
140+
&E3DSubModel::get_light_angle, "p_light_angle");
141+
BIND_PROPERTY(
142+
Variant::FLOAT, "near_atten_start", "near_atten_start", &E3DSubModel::set_near_atten_start,
143+
&E3DSubModel::get_near_atten_start, "p_near_atten_start");
144+
BIND_PROPERTY(
145+
Variant::FLOAT, "near_atten_end", "near_atten_end", &E3DSubModel::set_near_atten_end,
146+
&E3DSubModel::get_near_atten_end, "p_near_atten_end");
147+
BIND_PROPERTY(
148+
Variant::BOOL, "use_near_atten", "use_near_atten", &E3DSubModel::set_use_near_atten,
149+
&E3DSubModel::get_use_near_atten, "p_use_near_atten");
150+
BIND_PROPERTY(
151+
Variant::INT, "far_atten_decay", "far_atten_decay", &E3DSubModel::set_far_atten_decay,
152+
&E3DSubModel::get_far_atten_decay, "p_far_atten_decay");
153+
BIND_PROPERTY(
154+
Variant::FLOAT, "cos_hotspot_angle", "cos_hotspot_angle", &E3DSubModel::set_cos_hotspot_angle,
155+
&E3DSubModel::get_cos_hotspot_angle, "p_cos_hotspot_angle");
156+
BIND_PROPERTY(
157+
Variant::FLOAT, "cos_view_angle", "cos_view_angle", &E3DSubModel::set_cos_view_angle,
158+
&E3DSubModel::get_cos_view_angle, "p_cos_view_angle");
131159
}
132160

133161
void E3DSubModel::add_child(const Ref<E3DSubModel> &p_sub_model) {

src/e3d/E3DSubModel.hpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,16 @@ namespace godot {
8080
MAKE_MEMBER_GS_NR(bool, visible, true)
8181
MAKE_MEMBER_GS_NR(bool, skip_rendering, false)
8282

83+
MAKE_MEMBER_GS_NR(float, light_range, 0.0)
84+
MAKE_MEMBER_GS_NR(float, light_attenuation, 1.0)
85+
MAKE_MEMBER_GS_NR(float, light_angle, 45.0)
86+
MAKE_MEMBER_GS_NR(float, near_atten_start, 0.0)
87+
MAKE_MEMBER_GS_NR(float, near_atten_end, 0.0)
88+
MAKE_MEMBER_GS_NR(bool, use_near_atten, false)
89+
MAKE_MEMBER_GS_NR(int, far_atten_decay, 0)
90+
MAKE_MEMBER_GS_NR(float, cos_hotspot_angle, 0.0)
91+
MAKE_MEMBER_GS_NR(float, cos_view_angle, 0.0)
92+
8393
void add_child(const Ref<E3DSubModel> &p_sub_model);
8494
void set_parent(E3DSubModel *p_sub_model);
8595
void clear();

src/lighting/TrainLighting.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ namespace godot {
3232
BIND_PROPERTY_W_HINT_RES_ARRAY(
3333
Variant::ARRAY, "light_position_list", "lights/list", &TrainLighting::set_light_position_list,
3434
&TrainLighting::get_light_position_list, "light_position_list", PROPERTY_HINT_TYPE_STRING,
35-
"LighListItem");
35+
"LightListItem");
3636
BIND_PROPERTY_W_HINT(
3737
Variant::INT, "light_source", "light/source", &TrainLighting::set_light_source,
3838
&TrainLighting::get_light_source, "source", PROPERTY_HINT_ENUM,

0 commit comments

Comments
 (0)