This repository has been archived by the owner on Nov 9, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #107 from dfgHiatus/wizards
Added LOD wizard, general purpose map wizard
- Loading branch information
Showing
3 changed files
with
373 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
using BaseX; | ||
using FrooxEngine.UIX; | ||
using System.Linq; | ||
using static FrooxEngine.LODGroup; | ||
|
||
namespace FrooxEngine | ||
{ | ||
[Category("Add-ons/Wizards")] | ||
public class LODWizard : Component | ||
{ | ||
private const string LOD_GROUP_PREFIX = "<LOD_GROUP>"; | ||
|
||
private const string LOD_1 = "<LOD_1>"; | ||
[Range(0f, 1f, "0.00")] | ||
public readonly Sync<float> ScreenRelativeTransitionHeight_1; | ||
[Range(0f, 1f, "0.00")] | ||
public readonly Sync<float> FadeTransitionWidth_1; | ||
|
||
private const string LOD_2 = "<LOD_2>"; | ||
[Range(0f, 1f, "0.00")] | ||
public readonly Sync<float> ScreenRelativeTransitionHeight_2; | ||
[Range(0f, 1f, "0.00")] | ||
public readonly Sync<float> FadeTransitionWidth_2; | ||
|
||
private const string LOD_3 = "<LOD_3>"; | ||
[Range(0f, 1f, "0.00")] | ||
public readonly Sync<float> ScreenRelativeTransitionHeight_3; | ||
[Range(0f, 1f, "0.00")] | ||
public readonly Sync<float> FadeTransitionWidth_3; | ||
|
||
private const string LOD_4 = "<LOD_4>"; | ||
[Range(0f, 1f, "0.00")] | ||
public readonly Sync<float> ScreenRelativeTransitionHeight_4; | ||
[Range(0f, 1f, "0.00")] | ||
public readonly Sync<float> FadeTransitionWidth_4; | ||
|
||
public readonly SyncRef<Slot> ProcessRoot; | ||
public readonly Sync<bool> CrossFade; | ||
public readonly Sync<bool> AnimateCrossFading; | ||
|
||
protected override void OnAttach() | ||
{ | ||
base.OnAttach(); | ||
CrossFade.Value = false; | ||
AnimateCrossFading.Value = false; | ||
|
||
Slot.Name = "Map Wizard"; | ||
Slot.Tag = "Developer"; | ||
NeosCanvasPanel neosCanvasPanel = Slot.AttachComponent<NeosCanvasPanel>(); | ||
neosCanvasPanel.Panel.AddCloseButton(); | ||
neosCanvasPanel.Panel.Title = this.GetLocalized("LOD Wizard"); | ||
neosCanvasPanel.CanvasSize = new float2(600f, 600f); | ||
neosCanvasPanel.PhysicalHeight = 0.5f; | ||
|
||
UIBuilder ui = new UIBuilder(neosCanvasPanel.Canvas); | ||
ui.VerticalLayout(4f); | ||
ui.Style.MinHeight = 24f; | ||
ui.Style.PreferredHeight = 24f; | ||
UIBuilder uIBuilder = ui; | ||
LocaleString text = "Wizard.LightSources.Header".AsLocaleKey("<b>{0}</b>"); | ||
uIBuilder.Text(in text); | ||
UIBuilder uIBuilder2 = ui; | ||
text = "Wizard.LightSources.ProcessRoot".AsLocaleKey(); | ||
uIBuilder2.Text(in text); | ||
ui.Next("Process Root"); | ||
ui.Current.AttachComponent<RefEditor>().Setup(ProcessRoot); | ||
UIBuilder uIBuilder3 = ui; | ||
|
||
text = "Cross Fade".AsLocaleKey(); | ||
uIBuilder3.HorizontalElementWithLabel(in text, 0.8f, () => ui.BooleanMemberEditor(CrossFade)); | ||
UIBuilder uIBuilder4 = ui; | ||
text = "Animate Cross Fading".AsLocaleKey(); | ||
uIBuilder4.HorizontalElementWithLabel(in text, 0.8f, () => ui.BooleanMemberEditor(AnimateCrossFading)); | ||
|
||
UIBuilder uIBuilder5 = ui; | ||
text = "LOD Group 1 ScreenRelativeTransitionHeight".AsLocaleKey(); | ||
uIBuilder5.HorizontalElementWithLabel(in text, 0.8f, () => ui.PrimitiveMemberEditor(ScreenRelativeTransitionHeight_1)); | ||
UIBuilder uIBuilder6 = ui; | ||
text = "LOD Group 1 FadeTransitionWidth".AsLocaleKey(); | ||
uIBuilder6.HorizontalElementWithLabel(in text, 0.8f, () => ui.PrimitiveMemberEditor(FadeTransitionWidth_1)); | ||
UIBuilder uIBuilder7 = ui; | ||
text = "LOD Group 2 ScreenRelativeTransitionHeight".AsLocaleKey(); | ||
uIBuilder7.HorizontalElementWithLabel(in text, 0.8f, () => ui.PrimitiveMemberEditor(ScreenRelativeTransitionHeight_2)); | ||
UIBuilder uIBuilder8 = ui; | ||
text = "LOD Group 2 FadeTransitionWidth".AsLocaleKey(); | ||
uIBuilder8.HorizontalElementWithLabel(in text, 0.8f, () => ui.PrimitiveMemberEditor(FadeTransitionWidth_2)); | ||
UIBuilder uIBuilder9 = ui; | ||
text = "LOD Group 3 ScreenRelativeTransitionHeight".AsLocaleKey(); | ||
uIBuilder9.HorizontalElementWithLabel(in text, 0.8f, () => ui.PrimitiveMemberEditor(ScreenRelativeTransitionHeight_3)); | ||
UIBuilder uIBuilder10 = ui; | ||
text = "LOD Group 3 FadeTransitionWidth".AsLocaleKey(); | ||
uIBuilder10.HorizontalElementWithLabel(in text, 0.8f, () => ui.PrimitiveMemberEditor(FadeTransitionWidth_3)); | ||
UIBuilder uIBuilder11 = ui; | ||
text = "LOD Group 4 ScreenRelativeTransitionHeight".AsLocaleKey(); | ||
uIBuilder11.HorizontalElementWithLabel(in text, 0.8f, () => ui.PrimitiveMemberEditor(ScreenRelativeTransitionHeight_4)); | ||
UIBuilder uIBuilder12 = ui; | ||
text = "LOD Group 4 FadeTransitionWidth".AsLocaleKey(); | ||
uIBuilder12.HorizontalElementWithLabel(in text, 0.8f, () => ui.PrimitiveMemberEditor(FadeTransitionWidth_4)); | ||
|
||
UIBuilder uIBuilder13 = ui; | ||
text = "-------"; | ||
uIBuilder13.Text(in text); | ||
UIBuilder uIBuilder14 = ui; | ||
text = "Setup LOD Groups".AsLocaleKey(); | ||
uIBuilder14.Button(in text, SetupLODs); | ||
UIBuilder uIBuilder15 = ui; | ||
text = "-------"; | ||
uIBuilder15.Text(in text); | ||
} | ||
|
||
[SyncMethod] | ||
private void SetupLODs(IButton button, ButtonEventData eventData) | ||
{ | ||
var lodGroupCanidate = ProcessRoot.Target.GetComponent<LODGroup>(); | ||
if (lodGroupCanidate == null) | ||
{ | ||
lodGroupCanidate = ProcessRoot.Target.AttachComponent<LODGroup>(); | ||
lodGroupCanidate.CrossFade.Value = CrossFade.Value; | ||
lodGroupCanidate.AnimateCrossFading.Value = AnimateCrossFading.Value; | ||
} | ||
|
||
// Note: Given FrooxEngine's implementation of the AddLOD method, it is impossible to nest LOD groups within eachother. | ||
// This is because it calls Renderers.AddRange(root.GetComponentsInChildren<MeshRenderer>()), which is recursive. | ||
|
||
// In other words, your heirachy should look something like this: | ||
// | ||
// ProcessRoot | ||
// ... | ||
// - ... | ||
// - <LOD_GROUP>My Group | ||
// -- <LOD_1>Level 1 | ||
// -- <LOD_2>Level 2 | ||
// -- <LOD_3>Level 3 | ||
// -- <LOD_4>Level 4 | ||
// -- ... | ||
// - ... | ||
// ... | ||
// | ||
|
||
// Where additional slots are ignored. Here, this would populate ProcessRoot's LODGroup with 4 LODs, | ||
// Adhering to Unity's LOD standard. I don't think this implicity supports the culled state, | ||
// Might be best to have a ColliderUserTracker to drive the entire mesh root. | ||
|
||
LOD lod; | ||
foreach (var child in ProcessRoot.Target.GetAllChildren().Where(x => x.Name.StartsWith(LOD_GROUP_PREFIX))) | ||
{ | ||
switch (child.Name) | ||
{ | ||
case LOD_1: | ||
lod = lodGroupCanidate.AddLOD(ScreenRelativeTransitionHeight_1.Value, child); | ||
lod.FadeTransitionWidth.Value = FadeTransitionWidth_1; | ||
break; | ||
case LOD_2: | ||
lod = lodGroupCanidate.AddLOD(ScreenRelativeTransitionHeight_2.Value, child); | ||
lod.FadeTransitionWidth.Value = FadeTransitionWidth_2; | ||
break; | ||
case LOD_3: | ||
lod = lodGroupCanidate.AddLOD(ScreenRelativeTransitionHeight_3.Value, child); | ||
lod.FadeTransitionWidth.Value = FadeTransitionWidth_3; | ||
break; | ||
case LOD_4: | ||
lod = lodGroupCanidate.AddLOD(ScreenRelativeTransitionHeight_4.Value, child); | ||
lod.FadeTransitionWidth.Value = FadeTransitionWidth_4; | ||
break; | ||
default: | ||
break; | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,199 @@ | ||
using System; | ||
using BaseX; | ||
using FrooxEngine.UIX; | ||
|
||
namespace FrooxEngine | ||
{ | ||
[Category("Add-ons/Wizards")] | ||
public class MapWizard : Component, IDeveloperInterface, IComponent, IComponentBase, IDestroyable, IWorker, IWorldElement, IUpdatable, IChangeable, IAudioUpdatable, IInitializable, ILinkable | ||
{ | ||
public readonly SyncRef<Slot> Root; | ||
|
||
public readonly Sync<bool> ProcessPointLights; | ||
|
||
public readonly Sync<bool> ProcessSpotLights; | ||
|
||
public readonly Sync<bool> ProcessDirectionalLights; | ||
|
||
public readonly Sync<bool> ProcessDisabled; | ||
|
||
public readonly Sync<bool> ProcessColor; | ||
|
||
public readonly Sync<color> Color; | ||
|
||
public readonly SyncRef<TextField> ProcessTags; | ||
|
||
public readonly SyncRef<FloatTextEditorParser> _intensityField; | ||
|
||
public readonly SyncRef<FloatTextEditorParser> _intensityFieldMultiplicative; | ||
|
||
public readonly SyncRef<FloatTextEditorParser> _extentField; | ||
|
||
protected override void OnAttach() | ||
{ | ||
base.OnAttach(); | ||
ProcessPointLights.Value = true; | ||
ProcessSpotLights.Value = true; | ||
ProcessDirectionalLights.Value = true; | ||
ProcessDisabled.Value = false; | ||
ProcessColor.Value = false; | ||
|
||
Slot.Name = "Map Wizard"; | ||
Slot.Tag = "Developer"; | ||
NeosCanvasPanel neosCanvasPanel = Slot.AttachComponent<NeosCanvasPanel>(); | ||
neosCanvasPanel.Panel.AddCloseButton(); | ||
neosCanvasPanel.Panel.Title = this.GetLocalized("Wizard.LightSources.Title"); | ||
neosCanvasPanel.CanvasSize = new float2(600f, 600f); | ||
neosCanvasPanel.PhysicalHeight = 0.5f; | ||
UIBuilder ui = new UIBuilder(neosCanvasPanel.Canvas); | ||
ui.VerticalLayout(4f); | ||
ui.Style.MinHeight = 24f; | ||
ui.Style.PreferredHeight = 24f; | ||
UIBuilder uIBuilder = ui; | ||
LocaleString text = "Wizard.LightSources.Header".AsLocaleKey("<b>{0}</b>"); | ||
uIBuilder.Text(in text); | ||
UIBuilder uIBuilder2 = ui; | ||
text = "Wizard.LightSources.ProcessRoot".AsLocaleKey(); | ||
uIBuilder2.Text(in text); | ||
ui.Next("Root"); | ||
ui.Current.AttachComponent<RefEditor>().Setup(Root); | ||
UIBuilder uIBuilder3 = ui; | ||
text = "Wizard.LightSources.PointLights".AsLocaleKey(); | ||
uIBuilder3.HorizontalElementWithLabel(in text, 0.8f, () => ui.BooleanMemberEditor(ProcessPointLights)); | ||
UIBuilder uIBuilder4 = ui; | ||
text = "Wizard.LightSources.SpotLights".AsLocaleKey(); | ||
uIBuilder4.HorizontalElementWithLabel(in text, 0.8f, () => ui.BooleanMemberEditor(ProcessSpotLights)); | ||
UIBuilder uIBuilder5 = ui; | ||
text = "Wizard.LightSources.DirectionalLights".AsLocaleKey(); | ||
uIBuilder5.HorizontalElementWithLabel(in text, 0.8f, () => ui.BooleanMemberEditor(ProcessDirectionalLights)); | ||
UIBuilder uIBuilder6 = ui; | ||
text = "Wizard.LightSources.DisabledLights".AsLocaleKey(); | ||
uIBuilder6.HorizontalElementWithLabel(in text, 0.8f, () => ui.BooleanMemberEditor(ProcessDisabled)); | ||
SyncRef<TextField> tag = ProcessTags; | ||
UIBuilder uIBuilder7 = ui; | ||
text = "Wizard.LightSources.WithTag".AsLocaleKey(); | ||
tag.Target = uIBuilder7.HorizontalElementWithLabel(in text, 0.8f, () => ui.TextField()); | ||
// UIBuilder uIBuilder8 = ui; | ||
// uIBuilder8.ColorMemberEditor(Color, "LightSources with Color"); | ||
text = "-------"; | ||
|
||
UIBuilder uIBuilder9 = ui; | ||
uIBuilder9.Text(in text); | ||
_intensityField.Target = ui.FloatField(0f, 8f); | ||
UIBuilder uIBuilder10 = ui; | ||
text = "Set light intensity to value".AsLocaleKey(); | ||
uIBuilder10.Button(in text, ChangeIntensity); | ||
text = "-------"; | ||
|
||
uIBuilder10.Text(in text); | ||
_intensityFieldMultiplicative.Target = ui.FloatField(0f, 8f); | ||
UIBuilder uIBuilder11 = ui; | ||
text = "Multiply light intensity by value".AsLocaleKey(); | ||
uIBuilder11.Button(in text, ChangeIntensityMultiplicative); | ||
UIBuilder uIBuilder12 = ui; | ||
text = "-------"; | ||
|
||
UIBuilder uIBuilder13 = ui; | ||
uIBuilder13.Text(in text); | ||
_extentField.Target = ui.FloatField(0f, 50f); | ||
UIBuilder uIBuilder14 = ui; | ||
text = "Set light range to value".AsLocaleKey(); | ||
uIBuilder14.Button(in text, SetExtent); | ||
text = "-------"; | ||
} | ||
protected override void OnStart() | ||
{ | ||
base.OnStart(); | ||
Slot.GetComponentInChildrenOrParents<Canvas>()?.MarkDeveloper(); | ||
} | ||
|
||
[SyncMethod] | ||
private void ChangeIntensity(IButton button, ButtonEventData eventData) | ||
{ | ||
ForeachLight(delegate (Light l) | ||
{ | ||
l.Intensity.Value = _intensityField.Target.ParsedValue; | ||
}); | ||
} | ||
|
||
[SyncMethod] | ||
private void ChangeIntensityMultiplicative(IButton button, ButtonEventData eventData) | ||
{ | ||
ForeachLight(delegate (Light l) | ||
{ | ||
l.Intensity.Value *= _intensityFieldMultiplicative.Target.ParsedValue; | ||
}); | ||
} | ||
|
||
[SyncMethod] | ||
private void SetExtent(IButton button, ButtonEventData eventData) | ||
{ | ||
ForeachLight(delegate (Light l) | ||
{ | ||
switch (l.LightType.Value) | ||
{ | ||
case LightType.Spot: | ||
var globalPosSpot = l.Slot.GlobalPosition; | ||
var spotHit = Physics.RaycastOne(globalPosSpot, l.Slot.Down, _extentField.Target.ParsedValue); | ||
if (spotHit.HasValue) | ||
{ | ||
var clamped = MathX.Clamp(spotHit.Value.Distance, 0, _extentField.Target.ParsedValue); | ||
l.Range.Value = clamped; | ||
l.Intensity.Value = clamped / 10; | ||
} | ||
else | ||
{ | ||
l.Range.Value = _extentField.Target.ParsedValue; | ||
l.Intensity.Value = _extentField.Target.ParsedValue / 10; | ||
} | ||
break; | ||
case LightType.Point: | ||
var globalPosPoint = l.Slot.GlobalPosition; | ||
ICollider pointHit = Physics.SphereBoolSweepOne(globalPosPoint, float3.Zero, _extentField.Target.ParsedValue); | ||
if (pointHit == null) | ||
{ | ||
l.Range.Value = _extentField.Target.ParsedValue; | ||
l.Intensity.Value = _extentField.Target.ParsedValue / 10; | ||
return; | ||
} | ||
for (int i = 0; i < _extentField.Target.ParsedValue; i++) | ||
{ | ||
pointHit = Physics.SphereBoolSweepOne(globalPosPoint, float3.Zero, i); | ||
if (pointHit != null) | ||
break; | ||
} | ||
var dist = MathX.Distance(pointHit.Slot.GlobalPosition, globalPosPoint); | ||
l.Range.Value = dist; | ||
l.Intensity.Value = dist / 10; | ||
break; | ||
} | ||
}); | ||
} | ||
|
||
private void ForeachLight(Action<Light> process) | ||
{ | ||
string tag = ProcessTags.Target.TargetString; | ||
float4 canidate = Color.Value; | ||
foreach (Light componentsInChild in (Root.Target ?? World.RootSlot).GetComponentsInChildren(delegate (Light l) | ||
{ | ||
if (!ProcessDisabled.Value && (!l.Enabled || !l.Slot.IsActive)) | ||
{ | ||
return false; | ||
} | ||
float4 copy = l.Color.Value; | ||
return (string.IsNullOrEmpty(tag) || !(l.Slot.Tag != tag)) && | ||
(!ProcessColor.Value || MathX.Approximately(in copy, in canidate)) && | ||
l.LightType.Value switch | ||
{ | ||
LightType.Point => ProcessPointLights.Value, | ||
LightType.Directional => ProcessDirectionalLights.Value, | ||
LightType.Spot => ProcessSpotLights.Value, | ||
_ => false, | ||
}; | ||
})) | ||
{ | ||
process(componentsInChild); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters