Finished the code for radial distribution
This commit is contained in:
87
Editor/Cloner/Control/PropertyGroup.cs
Normal file
87
Editor/Cloner/Control/PropertyGroup.cs
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.UIElements;
|
||||||
|
|
||||||
|
namespace Misaki.ArtToolEditor
|
||||||
|
{
|
||||||
|
public enum HeaderSize
|
||||||
|
{
|
||||||
|
Small,
|
||||||
|
Medium,
|
||||||
|
Large
|
||||||
|
}
|
||||||
|
|
||||||
|
[UxmlElement]
|
||||||
|
public partial class PropertyGroup : VisualElement
|
||||||
|
{
|
||||||
|
private string _headerText = "Property Header";
|
||||||
|
|
||||||
|
[UxmlAttribute]
|
||||||
|
public string HeaderText
|
||||||
|
{
|
||||||
|
get => _headerText;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_headerText = value;
|
||||||
|
header.text = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private HeaderSize _headerSize = HeaderSize.Medium;
|
||||||
|
|
||||||
|
[UxmlAttribute]
|
||||||
|
public HeaderSize HeaderSize
|
||||||
|
{
|
||||||
|
get => _headerSize;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_headerSize = value;
|
||||||
|
SetHeaderStyle(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly Label header;
|
||||||
|
private readonly VisualElement propertyContainer;
|
||||||
|
|
||||||
|
public PropertyGroup()
|
||||||
|
{
|
||||||
|
header = new Label(_headerText) { name = "header" };
|
||||||
|
|
||||||
|
SetHeaderStyle(_headerSize);
|
||||||
|
|
||||||
|
propertyContainer = new VisualElement() { name = "property-content" };
|
||||||
|
|
||||||
|
propertyContainer.style.marginLeft = 8;
|
||||||
|
|
||||||
|
hierarchy.Add(header);
|
||||||
|
hierarchy.Add(propertyContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override VisualElement contentContainer => propertyContainer;
|
||||||
|
|
||||||
|
private void SetHeaderStyle(HeaderSize size)
|
||||||
|
{
|
||||||
|
switch (size)
|
||||||
|
{
|
||||||
|
case HeaderSize.Small:
|
||||||
|
header.style.marginTop = 6;
|
||||||
|
header.style.marginBottom = 4;
|
||||||
|
header.style.fontSize = 11;
|
||||||
|
break;
|
||||||
|
case HeaderSize.Medium:
|
||||||
|
header.style.marginTop = 8;
|
||||||
|
header.style.marginBottom = 6;
|
||||||
|
header.style.fontSize = 12;
|
||||||
|
break;
|
||||||
|
case HeaderSize.Large:
|
||||||
|
header.style.marginTop = 16;
|
||||||
|
header.style.marginBottom = 12;
|
||||||
|
header.style.fontSize = 16;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
header.style.unityFontStyleAndWeight = FontStyle.Bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
2
Editor/Cloner/Control/PropertyGroup.cs.meta
Normal file
2
Editor/Cloner/Control/PropertyGroup.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 61c279d7ffcfe1f4e8aa19345cd14e32
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
<engine:Label text="Object" enable-rich-text="false" style="flex-grow: 1; margin-left: 28px; font-size: 9px; -unity-text-align: middle-left;" />
|
<engine:Label text="Object" enable-rich-text="false" style="flex-grow: 1; margin-left: 28px; font-size: 9px; -unity-text-align: middle-left;" />
|
||||||
<engine:Label text="Frequncy" enable-rich-text="false" name="Label" style="width: 50px; font-size: 9px; -unity-text-align: middle-left;" />
|
<engine:Label text="Frequncy" enable-rich-text="false" name="Label" style="width: 50px; font-size: 9px; -unity-text-align: middle-left;" />
|
||||||
</engine:VisualElement>
|
</engine:VisualElement>
|
||||||
<engine:ListView reorderable="true" reorder-mode="Animated" show-border="true" show-add-remove-footer="true" item-template="project://database/Packages/com.misaki.art-tools/Editor/Cloner/InputObjectItemView.uxml?fileID=9197481963319205126&guid=af925948194d82c44a565c55d8ce0de8&type=3#InputObjectItemView" name="input-objects-listview" binding-source-selection-mode="AutoAssign">
|
<engine:ListView reorderable="true" reorder-mode="Animated" show-border="true" show-add-remove-footer="true" name="input-objects-listview" binding-source-selection-mode="AutoAssign" item-template="project://database/Packages/com.misaki.art-tools/Editor/Cloner/View/ItemTemplate/InputObjectItemTemplate.uxml?fileID=9197481963319205126&guid=af925948194d82c44a565c55d8ce0de8&type=3#InputObjectItemTemplate">
|
||||||
<Bindings>
|
<Bindings>
|
||||||
<engine:DataBinding property="itemsSource" data-source-path="inputObjects" binding-mode="TwoWay" />
|
<engine:DataBinding property="itemsSource" data-source-path="inputObjects" binding-mode="TwoWay" />
|
||||||
</Bindings>
|
</Bindings>
|
||||||
@@ -39,7 +39,7 @@
|
|||||||
<engine:DataBinding property="index" data-source-path="autoGenerate" binding-mode="TwoWay" />
|
<engine:DataBinding property="index" data-source-path="autoGenerate" binding-mode="TwoWay" />
|
||||||
</Bindings>
|
</Bindings>
|
||||||
</engine:DropdownField>
|
</engine:DropdownField>
|
||||||
<engine:DropdownField label="Render Mode" choices="Gameobject,Instancing" index="0" name="render-mode-dropdown">
|
<engine:DropdownField label="Instantiate Mode" choices="GameObject,Instancing" index="0" name="render-mode-dropdown">
|
||||||
<Bindings>
|
<Bindings>
|
||||||
<engine:DataBinding property="index" data-source-path="isRenderInstancing" binding-mode="TwoWay" />
|
<engine:DataBinding property="index" data-source-path="isRenderInstancing" binding-mode="TwoWay" />
|
||||||
</Bindings>
|
</Bindings>
|
||||||
@@ -72,7 +72,7 @@
|
|||||||
</engine:UnsignedIntegerField>
|
</engine:UnsignedIntegerField>
|
||||||
<engine:DropdownField label="Align Normal" choices="Disable,Enable" index="0">
|
<engine:DropdownField label="Align Normal" choices="Disable,Enable" index="0">
|
||||||
<Bindings>
|
<Bindings>
|
||||||
<engine:DataBinding property="index" data-source-path="objectDistributionSetting.alignNormal" binding-mode="TwoWay" />
|
<engine:DataBinding property="index" data-source-path="objectDistributionSetting.isAlignNormal" binding-mode="TwoWay" />
|
||||||
</Bindings>
|
</Bindings>
|
||||||
</engine:DropdownField>
|
</engine:DropdownField>
|
||||||
<Bindings>
|
<Bindings>
|
||||||
@@ -124,22 +124,22 @@
|
|||||||
</engine:IntegerField>
|
</engine:IntegerField>
|
||||||
<engine:Vector3Field label="Position Spacing">
|
<engine:Vector3Field label="Position Spacing">
|
||||||
<Bindings>
|
<Bindings>
|
||||||
<engine:DataBinding property="value" data-source-path="linearDistributionSetting.positionSpacing" source-to-ui-converters="Float3ToVector3Converter" binding-mode="TwoWay" />
|
<engine:DataBinding property="value" data-source-path="linearDistributionSetting.positionSpacing" source-to-ui-converters="Float3ToVector3Converter" binding-mode="TwoWay" ui-to-source-converters="Float3ToVector3Converter" />
|
||||||
</Bindings>
|
</Bindings>
|
||||||
</engine:Vector3Field>
|
</engine:Vector3Field>
|
||||||
<engine:Vector3Field label="Rotation Spacing">
|
<engine:Vector3Field label="Rotation Spacing">
|
||||||
<Bindings>
|
<Bindings>
|
||||||
<engine:DataBinding property="value" data-source-path="linearDistributionSetting.scaleSpacing" source-to-ui-converters="Float3ToVector3Converter" binding-mode="TwoWay" />
|
<engine:DataBinding property="value" data-source-path="linearDistributionSetting.scaleSpacing" source-to-ui-converters="Float3ToVector3Converter" binding-mode="TwoWay" ui-to-source-converters="Float3ToVector3Converter" />
|
||||||
</Bindings>
|
</Bindings>
|
||||||
</engine:Vector3Field>
|
</engine:Vector3Field>
|
||||||
<engine:Vector3Field label="Scale Spacing">
|
<engine:Vector3Field label="Scale Spacing">
|
||||||
<Bindings>
|
<Bindings>
|
||||||
<engine:DataBinding property="value" data-source-path="linearDistributionSetting.scaleSpacing" source-to-ui-converters="Float3ToVector3Converter" binding-mode="TwoWay" />
|
<engine:DataBinding property="value" data-source-path="linearDistributionSetting.scaleSpacing" source-to-ui-converters="Float3ToVector3Converter" binding-mode="TwoWay" ui-to-source-converters="Float3ToVector3Converter" />
|
||||||
</Bindings>
|
</Bindings>
|
||||||
</engine:Vector3Field>
|
</engine:Vector3Field>
|
||||||
<engine:Vector3Field label="Step Rotation">
|
<engine:Vector3Field label="Step Rotation">
|
||||||
<Bindings>
|
<Bindings>
|
||||||
<engine:DataBinding property="value" data-source-path="linearDistributionSetting.stepRotation" source-to-ui-converters="Float3ToVector3Converter" binding-mode="TwoWay" />
|
<engine:DataBinding property="value" data-source-path="linearDistributionSetting.stepRotation" source-to-ui-converters="Float3ToVector3Converter" binding-mode="TwoWay" ui-to-source-converters="Float3ToVector3Converter" />
|
||||||
</Bindings>
|
</Bindings>
|
||||||
</engine:Vector3Field>
|
</engine:Vector3Field>
|
||||||
<Bindings>
|
<Bindings>
|
||||||
@@ -149,12 +149,12 @@
|
|||||||
<engine:VisualElement name="grid-parameter" style="flex-grow: 1;">
|
<engine:VisualElement name="grid-parameter" style="flex-grow: 1;">
|
||||||
<engine:Vector3IntField label="Count">
|
<engine:Vector3IntField label="Count">
|
||||||
<Bindings>
|
<Bindings>
|
||||||
<engine:DataBinding property="value" data-source-path="gridDistributionSetting.count" binding-mode="TwoWay" source-to-ui-converters="int3ToVector3IntConverter" />
|
<engine:DataBinding property="value" data-source-path="gridDistributionSetting.count" binding-mode="TwoWay" source-to-ui-converters="int3ToVector3IntConverter" ui-to-source-converters="int3ToVector3IntConverter" />
|
||||||
</Bindings>
|
</Bindings>
|
||||||
</engine:Vector3IntField>
|
</engine:Vector3IntField>
|
||||||
<engine:Vector3Field label="Spacing">
|
<engine:Vector3Field label="Spacing">
|
||||||
<Bindings>
|
<Bindings>
|
||||||
<engine:DataBinding property="value" data-source-path="gridDistributionSetting.spacing" source-to-ui-converters="Float3ToVector3Converter" binding-mode="TwoWay" />
|
<engine:DataBinding property="value" data-source-path="gridDistributionSetting.spacing" source-to-ui-converters="Float3ToVector3Converter" binding-mode="TwoWay" ui-to-source-converters="Float3ToVector3Converter" />
|
||||||
</Bindings>
|
</Bindings>
|
||||||
</engine:Vector3Field>
|
</engine:Vector3Field>
|
||||||
<engine:EnumField label="Shape" value="Center" type="Misaki.ArtTool.GridShape, Misaki.ArtTool">
|
<engine:EnumField label="Shape" value="Center" type="Misaki.ArtTool.GridShape, Misaki.ArtTool">
|
||||||
@@ -171,12 +171,47 @@
|
|||||||
<engine:DataBinding property="style.display" data-source-path="distributionMode" binding-mode="ToTarget" source-to-ui-converters="GridModeToDisplayStyleConverter" />
|
<engine:DataBinding property="style.display" data-source-path="distributionMode" binding-mode="ToTarget" source-to-ui-converters="GridModeToDisplayStyleConverter" />
|
||||||
</Bindings>
|
</Bindings>
|
||||||
</engine:VisualElement>
|
</engine:VisualElement>
|
||||||
|
<engine:VisualElement name="radial-parameter" style="flex-grow: 1;">
|
||||||
|
<engine:UnsignedIntegerField label="Count" value="5">
|
||||||
|
<Bindings>
|
||||||
|
<engine:DataBinding property="value" data-source-path="radialDistributionSetting.count" binding-mode="TwoWay" />
|
||||||
|
</Bindings>
|
||||||
|
</engine:UnsignedIntegerField>
|
||||||
|
<engine:FloatField label="Radius" value="5">
|
||||||
|
<Bindings>
|
||||||
|
<engine:DataBinding property="value" data-source-path="radialDistributionSetting.radius" binding-mode="TwoWay" />
|
||||||
|
</Bindings>
|
||||||
|
</engine:FloatField>
|
||||||
|
<engine:EnumField label="Plane" value="XZ" type="Misaki.ArtTool.PlaneDirection, Misaki.ArtTool">
|
||||||
|
<Bindings>
|
||||||
|
<engine:DataBinding property="value" data-source-path="radialDistributionSetting.plane" binding-mode="TwoWay" />
|
||||||
|
</Bindings>
|
||||||
|
</engine:EnumField>
|
||||||
|
<engine:FloatField label="Start Angle" value="0">
|
||||||
|
<Bindings>
|
||||||
|
<engine:DataBinding property="value" data-source-path="radialDistributionSetting.angleMinMax.x" binding-mode="TwoWay" />
|
||||||
|
</Bindings>
|
||||||
|
</engine:FloatField>
|
||||||
|
<engine:FloatField label="End Angle" value="360">
|
||||||
|
<Bindings>
|
||||||
|
<engine:DataBinding property="value" data-source-path="radialDistributionSetting.angleMinMax.y" binding-mode="TwoWay" />
|
||||||
|
</Bindings>
|
||||||
|
</engine:FloatField>
|
||||||
|
<engine:DropdownField label="Align" choices="Disable,Enable" index="0">
|
||||||
|
<Bindings>
|
||||||
|
<engine:DataBinding property="index" data-source-path="radialDistributionSetting.align" binding-mode="TwoWay" />
|
||||||
|
</Bindings>
|
||||||
|
</engine:DropdownField>
|
||||||
|
<Bindings>
|
||||||
|
<engine:DataBinding property="style.display" data-source-path="distributionMode" binding-mode="ToTarget" source-to-ui-converters="RadialModeToDisplayStyleConverter" />
|
||||||
|
</Bindings>
|
||||||
|
</engine:VisualElement>
|
||||||
</engine:VisualElement>
|
</engine:VisualElement>
|
||||||
</engine:VisualElement>
|
</engine:VisualElement>
|
||||||
<engine:VisualElement>
|
<engine:VisualElement>
|
||||||
<engine:Label text="Effectors" class="SubHeader" />
|
<engine:Label text="Effectors" class="SubHeader" />
|
||||||
<engine:VisualElement class="PropertyContainer">
|
<engine:VisualElement class="PropertyContainer">
|
||||||
<engine:ListView reorderable="true" reorder-mode="Animated" show-border="true" show-add-remove-footer="true" item-template="project://database/Packages/com.misaki.art-tools/Editor/Cloner/EffectorItemTemplate.uxml?fileID=9197481963319205126&guid=9a72cc6a25b7e104991d25d5c2458b81&type=3#EffectorItemTemplate" name="effectors-listview" binding-source-selection-mode="AutoAssign">
|
<engine:ListView reorderable="true" reorder-mode="Animated" show-border="true" show-add-remove-footer="true" name="effectors-listview" binding-source-selection-mode="AutoAssign" item-template="project://database/Packages/com.misaki.art-tools/Editor/Cloner/View/ItemTemplate/EffectorItemTemplate.uxml?fileID=9197481963319205126&guid=9a72cc6a25b7e104991d25d5c2458b81&type=3#EffectorItemTemplate">
|
||||||
<Bindings>
|
<Bindings>
|
||||||
<engine:DataBinding property="itemsSource" data-source-path="effectors" binding-mode="TwoWay" />
|
<engine:DataBinding property="itemsSource" data-source-path="effectors" binding-mode="TwoWay" />
|
||||||
</Bindings>
|
</Bindings>
|
||||||
@@ -191,6 +226,16 @@
|
|||||||
<engine:DataBinding property="value" data-source-path="debugMode" binding-mode="TwoWay" />
|
<engine:DataBinding property="value" data-source-path="debugMode" binding-mode="TwoWay" />
|
||||||
</Bindings>
|
</Bindings>
|
||||||
</engine:EnumField>
|
</engine:EnumField>
|
||||||
|
<engine:FloatField label="Debug Size" value="0.5">
|
||||||
|
<Bindings>
|
||||||
|
<engine:DataBinding property="value" data-source-path="gizmosSize" binding-mode="TwoWay" />
|
||||||
|
</Bindings>
|
||||||
|
</engine:FloatField>
|
||||||
|
<engine:IntegerField label="Point Count" value="42" enabled="false">
|
||||||
|
<Bindings>
|
||||||
|
<engine:DataBinding property="value" data-source-path="pointSize" binding-mode="ToTarget" />
|
||||||
|
</Bindings>
|
||||||
|
</engine:IntegerField>
|
||||||
</engine:VisualElement>
|
</engine:VisualElement>
|
||||||
</engine:VisualElement>
|
</engine:VisualElement>
|
||||||
<engine:VisualElement>
|
<engine:VisualElement>
|
||||||
|
|||||||
@@ -1,50 +1,41 @@
|
|||||||
<engine:UXML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:engine="UnityEngine.UIElements" xmlns:editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="True">
|
<engine:UXML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:engine="UnityEngine.UIElements" xmlns:editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="True">
|
||||||
<Style src="project://database/Packages/com.misaki.art-tools/Editor/Cloner/View/ClonerEditorStyle.uss?fileID=7433441132597879392&guid=216b892cd94cc624da01dc4947facdcb&type=3#ClonerEditorStyle" />
|
<Style src="project://database/Packages/com.misaki.art-tools/Editor/Cloner/View/ClonerEditorStyle.uss?fileID=7433441132597879392&guid=216b892cd94cc624da01dc4947facdcb&type=3#ClonerEditorStyle" />
|
||||||
<engine:VisualElement data-source-type="Misaki.ArtTool.PushApartEffector, Misaki.ArtTool" style="flex-grow: 1;">
|
<engine:VisualElement data-source-type="Misaki.ArtTool.PushApartEffector, Misaki.ArtTool" style="flex-grow: 1;">
|
||||||
<engine:VisualElement>
|
<Misaki.ArtToolEditor.PropertyGroup header-text="Effector">
|
||||||
<engine:Label text="Effector" class="SubHeader" />
|
<engine:Slider label="Strength" value="42" high-value="1" fill="true" show-input-field="true">
|
||||||
<engine:VisualElement class="PropertyContainer">
|
<Bindings>
|
||||||
<engine:Slider label="Strength" value="42" high-value="1" fill="true" show-input-field="true">
|
<engine:DataBinding property="value" data-source-path="strength" binding-mode="TwoWay" />
|
||||||
<Bindings>
|
</Bindings>
|
||||||
<engine:DataBinding property="value" data-source-path="strength" binding-mode="TwoWay" />
|
</engine:Slider>
|
||||||
</Bindings>
|
</Misaki.ArtToolEditor.PropertyGroup>
|
||||||
</engine:Slider>
|
<Misaki.ArtToolEditor.PropertyGroup header-text="Parameter" name="PropertyGroup">
|
||||||
|
<engine:DropdownField label="Mode" choices="Push,Hide" index="0">
|
||||||
|
<Bindings>
|
||||||
|
<engine:DataBinding property="index" data-source-path="isHideMode" binding-mode="TwoWay" />
|
||||||
|
</Bindings>
|
||||||
|
</engine:DropdownField>
|
||||||
|
<engine:FloatField label="Radius" value="1">
|
||||||
|
<Bindings>
|
||||||
|
<engine:DataBinding property="value" data-source-path="radius" binding-mode="TwoWay" />
|
||||||
|
</Bindings>
|
||||||
|
</engine:FloatField>
|
||||||
|
<engine:UnsignedIntegerField label="Iteration" value="10">
|
||||||
|
<Bindings>
|
||||||
|
<engine:DataBinding property="value" data-source-path="iteration" binding-mode="TwoWay" />
|
||||||
|
</Bindings>
|
||||||
|
</engine:UnsignedIntegerField>
|
||||||
|
</Misaki.ArtToolEditor.PropertyGroup>
|
||||||
|
<Misaki.ArtToolEditor.PropertyGroup header-text="Fields">
|
||||||
|
<engine:VisualElement style="flex-grow: 1; flex-direction: row; margin-top: 4px; margin-right: 4px; margin-bottom: 8px; margin-left: 4px;">
|
||||||
|
<engine:Label text="Enable" enable-rich-text="false" style="font-size: 9px; -unity-text-align: middle-left; margin-left: 4px;" />
|
||||||
|
<engine:Label text="Field" enable-rich-text="false" style="flex-grow: 1; margin-left: 12px; font-size: 9px; -unity-text-align: middle-left;" />
|
||||||
|
<engine:Label text="Blending" enable-rich-text="false" style="width: 100px; font-size: 9px; -unity-text-align: middle-left;" />
|
||||||
</engine:VisualElement>
|
</engine:VisualElement>
|
||||||
</engine:VisualElement>
|
<engine:ListView reorderable="true" reorder-mode="Animated" binding-source-selection-mode="AutoAssign" show-add-remove-footer="true" show-border="true" item-template="project://database/Packages/com.misaki.art-tools/Editor/Cloner/View/ItemTemplate/FieldItemTemplate.uxml?fileID=9197481963319205126&guid=d432ee1ae85c33d4abf54b61fc8a45f5&type=3#FieldItemTemplate" fixed-item-height="45">
|
||||||
<engine:VisualElement>
|
<Bindings>
|
||||||
<engine:Label text="Parameter" class="SubHeader" />
|
<engine:DataBinding property="itemsSource" data-source-path="fieldDataList" binding-mode="TwoWay" />
|
||||||
<engine:VisualElement class="PropertyContainer">
|
</Bindings>
|
||||||
<engine:DropdownField label="Mode" choices="Push,Hide" index="0">
|
</engine:ListView>
|
||||||
<Bindings>
|
</Misaki.ArtToolEditor.PropertyGroup>
|
||||||
<engine:DataBinding property="index" data-source-path="isHideMode" binding-mode="TwoWay" />
|
|
||||||
</Bindings>
|
|
||||||
</engine:DropdownField>
|
|
||||||
<engine:FloatField label="Radius" value="1">
|
|
||||||
<Bindings>
|
|
||||||
<engine:DataBinding property="value" data-source-path="radius" binding-mode="TwoWay" />
|
|
||||||
</Bindings>
|
|
||||||
</engine:FloatField>
|
|
||||||
<engine:UnsignedIntegerField label="Iteration" value="10">
|
|
||||||
<Bindings>
|
|
||||||
<engine:DataBinding property="value" data-source-path="iteration" binding-mode="TwoWay" />
|
|
||||||
</Bindings>
|
|
||||||
</engine:UnsignedIntegerField>
|
|
||||||
</engine:VisualElement>
|
|
||||||
</engine:VisualElement>
|
|
||||||
<engine:VisualElement>
|
|
||||||
<engine:Label text="Fields" class="SubHeader" />
|
|
||||||
<engine:VisualElement class="PropertyContainer" style="flex-grow: 1;">
|
|
||||||
<engine:VisualElement style="flex-grow: 1; flex-direction: row; margin-top: 4px; margin-right: 4px; margin-bottom: 8px; margin-left: 4px;">
|
|
||||||
<engine:Label text="Enable" enable-rich-text="false" style="font-size: 9px; -unity-text-align: middle-left; margin-left: 4px;" />
|
|
||||||
<engine:Label text="Field" enable-rich-text="false" style="flex-grow: 1; margin-left: 12px; font-size: 9px; -unity-text-align: middle-left;" />
|
|
||||||
<engine:Label text="Blending" enable-rich-text="false" style="width: 100px; font-size: 9px; -unity-text-align: middle-left;" />
|
|
||||||
</engine:VisualElement>
|
|
||||||
<engine:ListView reorderable="true" reorder-mode="Animated" binding-source-selection-mode="AutoAssign" show-add-remove-footer="true" show-border="true" item-template="project://database/Packages/com.misaki.art-tools/Editor/Cloner/View/ItemTemplate/FieldItemTemplate.uxml?fileID=9197481963319205126&guid=d432ee1ae85c33d4abf54b61fc8a45f5&type=3#FieldItemTemplate" fixed-item-height="45">
|
|
||||||
<Bindings>
|
|
||||||
<engine:DataBinding property="itemsSource" data-source-path="fieldDataList" binding-mode="TwoWay" />
|
|
||||||
</Bindings>
|
|
||||||
</engine:ListView>
|
|
||||||
</engine:VisualElement>
|
|
||||||
</engine:VisualElement>
|
|
||||||
</engine:VisualElement>
|
</engine:VisualElement>
|
||||||
</engine:UXML>
|
</engine:UXML>
|
||||||
|
|||||||
@@ -9,10 +9,8 @@ using Unity.Mathematics;
|
|||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.Jobs;
|
using UnityEngine.Jobs;
|
||||||
using UnityEngine.Profiling;
|
|
||||||
using UnityEngine.Rendering;
|
using UnityEngine.Rendering;
|
||||||
using UnityEngine.Splines;
|
using UnityEngine.Splines;
|
||||||
using Object = UnityEngine.Object;
|
|
||||||
using Random = Unity.Mathematics.Random;
|
using Random = Unity.Mathematics.Random;
|
||||||
|
|
||||||
namespace Misaki.ArtTool
|
namespace Misaki.ArtTool
|
||||||
@@ -30,26 +28,38 @@ namespace Misaki.ArtTool
|
|||||||
|
|
||||||
public MeshFilter inputMeshFilter;
|
public MeshFilter inputMeshFilter;
|
||||||
public ObjectDistributionSetting objectDistributionSetting;
|
public ObjectDistributionSetting objectDistributionSetting;
|
||||||
|
|
||||||
public SplineContainer inputSplineContainer;
|
public SplineContainer inputSplineContainer;
|
||||||
public SplineDistributionSetting splineDistributionSetting;
|
public SplineDistributionSetting splineDistributionSetting;
|
||||||
|
|
||||||
public LinearDistributionSetting linearDistributionSetting;
|
public LinearDistributionSetting linearDistributionSetting;
|
||||||
|
|
||||||
public GridDistributionSetting gridDistributionSetting;
|
public GridDistributionSetting gridDistributionSetting;
|
||||||
|
|
||||||
public List<EffectorData> effectors;
|
public RadialDistributionSetting radialDistributionSetting;
|
||||||
|
|
||||||
|
public List<EffectorData> effectors = new();
|
||||||
|
|
||||||
public DebugMode debugMode;
|
public DebugMode debugMode;
|
||||||
|
public float gizmosSize = 0.25f;
|
||||||
|
|
||||||
private static readonly ArrayPool<PointData> _pointPool = ArrayPool<PointData>.Shared;
|
private static readonly ArrayPool<PointData> _pointPool = ArrayPool<PointData>.Shared;
|
||||||
private static readonly ArrayPool<int> _intPool = ArrayPool<int>.Shared;
|
|
||||||
|
|
||||||
private int _pointSize;
|
public int pointSize;
|
||||||
private PointData[] _points;
|
private PointData[] _points;
|
||||||
private int[] _instantiateObjects;
|
private List<GameObject> _instantiateObjects = new();
|
||||||
private readonly Dictionary<int, List<Matrix4x4>> _objectGroup = new();
|
private readonly Dictionary<int, List<Matrix4x4>> _objectGroup = new();
|
||||||
|
|
||||||
private bool _isPointsDirty = false;
|
private bool _isPointsDirty = false;
|
||||||
|
|
||||||
private const float GIZMOS_BASE_SIZE = 0.25f;
|
[MenuItem("GameObject/Cloner/Cloner Object")]
|
||||||
|
public static void CreateCloner()
|
||||||
|
{
|
||||||
|
var clonerObject = new GameObject("Cloner");
|
||||||
|
GameObjectUtility.EnsureUniqueNameForSibling(clonerObject);
|
||||||
|
|
||||||
|
clonerObject.AddComponent<Cloner>();
|
||||||
|
}
|
||||||
|
|
||||||
private void OnEnable()
|
private void OnEnable()
|
||||||
{
|
{
|
||||||
@@ -63,11 +73,11 @@ namespace Misaki.ArtTool
|
|||||||
item.effector.propertyChanged += OnPropertyChanged;
|
item.effector.propertyChanged += OnPropertyChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (transform.childCount > 0 && _instantiateObjects.Length == 0)
|
if (transform.childCount > 0 && _instantiateObjects.Count == 0)
|
||||||
{
|
{
|
||||||
for (var i = 0; i < transform.childCount; i++)
|
for (var i = 0; i < transform.childCount; i++)
|
||||||
{
|
{
|
||||||
_instantiateObjects[i] = transform.GetChild(i).GetInstanceID();
|
_instantiateObjects[i] = transform.GetChild(i).gameObject;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -127,14 +137,12 @@ namespace Misaki.ArtTool
|
|||||||
{
|
{
|
||||||
shadowCastingMode = ShadowCastingMode.On
|
shadowCastingMode = ShadowCastingMode.On
|
||||||
};
|
};
|
||||||
Graphics.RenderMeshInstanced(renderParams, objectData.Mesh, 0, item.Value, _pointSize);
|
Graphics.RenderMeshInstanced(renderParams, objectData.Mesh, 0, item.Value, pointSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void GeneratePoints()
|
public void GeneratePoints()
|
||||||
{
|
{
|
||||||
Profiler.BeginSample("GeneratePoints");
|
|
||||||
|
|
||||||
Clear();
|
Clear();
|
||||||
|
|
||||||
switch (distributionMode)
|
switch (distributionMode)
|
||||||
@@ -147,7 +155,7 @@ namespace Misaki.ArtTool
|
|||||||
}
|
}
|
||||||
|
|
||||||
objectDistributionSetting.meshData = new(inputMeshFilter, Allocator.TempJob);
|
objectDistributionSetting.meshData = new(inputMeshFilter, Allocator.TempJob);
|
||||||
_pointSize = objectDistributionSetting.DistributionCount;
|
pointSize = objectDistributionSetting.DistributionCount;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case DistributionMode.Spline:
|
case DistributionMode.Spline:
|
||||||
@@ -161,18 +169,19 @@ namespace Misaki.ArtTool
|
|||||||
splineDistributionSetting.nativeSpline = new(inputSplineContainer.Spline, Allocator.TempJob);
|
splineDistributionSetting.nativeSpline = new(inputSplineContainer.Spline, Allocator.TempJob);
|
||||||
splineDistributionSetting.splineLength = splineDistributionSetting.nativeSpline.CalculateLength(splineDistributionSetting.splineWorldMatrix);
|
splineDistributionSetting.splineLength = splineDistributionSetting.nativeSpline.CalculateLength(splineDistributionSetting.splineWorldMatrix);
|
||||||
|
|
||||||
_pointSize = splineDistributionSetting.DistributionCount;
|
pointSize = splineDistributionSetting.DistributionCount;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DistributionMode.Linear:
|
case DistributionMode.Linear:
|
||||||
_pointSize = (int)linearDistributionSetting.count;
|
pointSize = (int)linearDistributionSetting.count;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DistributionMode.Grid:
|
case DistributionMode.Grid:
|
||||||
_pointSize = gridDistributionSetting.DistributionCount;
|
pointSize = gridDistributionSetting.DistributionCount;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DistributionMode.Radial:
|
case DistributionMode.Radial:
|
||||||
|
pointSize = (int)radialDistributionSetting.count;
|
||||||
break;
|
break;
|
||||||
case DistributionMode.Honeycomb:
|
case DistributionMode.Honeycomb:
|
||||||
break;
|
break;
|
||||||
@@ -183,12 +192,12 @@ namespace Misaki.ArtTool
|
|||||||
// Allocate a empty native collection to avoid job error
|
// Allocate a empty native collection to avoid job error
|
||||||
EnsureNativeCollectionValid();
|
EnsureNativeCollectionValid();
|
||||||
|
|
||||||
if (_pointSize == 0)
|
if (pointSize == 0)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_points = _pointPool.Rent(_pointSize);
|
_points = _pointPool.Rent(pointSize);
|
||||||
|
|
||||||
foreach (var effectorData in effectors)
|
foreach (var effectorData in effectors)
|
||||||
{
|
{
|
||||||
@@ -202,7 +211,7 @@ namespace Misaki.ArtTool
|
|||||||
var pointsGenerationJob = new PointsGenerationJob()
|
var pointsGenerationJob = new PointsGenerationJob()
|
||||||
{
|
{
|
||||||
worldMatrix = worldMatrix,
|
worldMatrix = worldMatrix,
|
||||||
pointSize = _pointSize,
|
pointSize = pointSize,
|
||||||
|
|
||||||
distributionMode = distributionMode,
|
distributionMode = distributionMode,
|
||||||
|
|
||||||
@@ -210,11 +219,12 @@ namespace Misaki.ArtTool
|
|||||||
splineDistributionSetting = splineDistributionSetting,
|
splineDistributionSetting = splineDistributionSetting,
|
||||||
linearDistributionSetting = linearDistributionSetting,
|
linearDistributionSetting = linearDistributionSetting,
|
||||||
gridDistributionSetting = gridDistributionSetting,
|
gridDistributionSetting = gridDistributionSetting,
|
||||||
|
radialDistributionSetting = radialDistributionSetting,
|
||||||
|
|
||||||
points = pointsArray
|
points = pointsArray
|
||||||
};
|
};
|
||||||
|
|
||||||
var handle = pointsGenerationJob.Schedule(_pointSize, 64);
|
var handle = pointsGenerationJob.Schedule(pointSize, 64);
|
||||||
handle.Complete();
|
handle.Complete();
|
||||||
|
|
||||||
pointsArray.CopyTo(_points);
|
pointsArray.CopyTo(_points);
|
||||||
@@ -224,16 +234,11 @@ namespace Misaki.ArtTool
|
|||||||
objectDistributionSetting.meshData.Dispose();
|
objectDistributionSetting.meshData.Dispose();
|
||||||
|
|
||||||
// Switch to managed thread for effectors because of interface
|
// Switch to managed thread for effectors because of interface
|
||||||
Parallel.For(0, _pointSize, i =>
|
Parallel.For(0, pointSize, i =>
|
||||||
{
|
{
|
||||||
for (var e = effectors.Count - 1; e >= 0; e--)
|
for (var e = effectors.Count - 1; e >= 0; e--)
|
||||||
{
|
{
|
||||||
if (!effectors[e].enable)
|
if (!effectors[e].enable || effectors[e].effector == null)
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (effectors[e].effector == null)
|
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -248,8 +253,6 @@ namespace Misaki.ArtTool
|
|||||||
});
|
});
|
||||||
|
|
||||||
_isPointsDirty = false;
|
_isPointsDirty = false;
|
||||||
|
|
||||||
Profiler.EndSample();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EnsureNativeCollectionValid()
|
private void EnsureNativeCollectionValid()
|
||||||
@@ -267,7 +270,7 @@ namespace Misaki.ArtTool
|
|||||||
|
|
||||||
public void InstantiateGameObjectOnPoints()
|
public void InstantiateGameObjectOnPoints()
|
||||||
{
|
{
|
||||||
if (_points == null && _pointSize <= 0)
|
if (_points == null && pointSize <= 0)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -278,7 +281,7 @@ namespace Misaki.ArtTool
|
|||||||
{
|
{
|
||||||
// Use Fisher-Yates Shuffle algorithm to swap value
|
// Use Fisher-Yates Shuffle algorithm to swap value
|
||||||
var random = new Random(seed);
|
var random = new Random(seed);
|
||||||
for (var i = _pointSize - 1; i > 0; i--)
|
for (var i = pointSize - 1; i > 0; i--)
|
||||||
{
|
{
|
||||||
var k = random.NextInt(0, i + 1);
|
var k = random.NextInt(0, i + 1);
|
||||||
(_points[i], _points[k]) = (_points[k], _points[i]);
|
(_points[i], _points[k]) = (_points[k], _points[i]);
|
||||||
@@ -292,7 +295,7 @@ namespace Misaki.ArtTool
|
|||||||
|
|
||||||
var currentIndex = 0;
|
var currentIndex = 0;
|
||||||
var objectIndex = 0;
|
var objectIndex = 0;
|
||||||
while (currentIndex < _pointSize)
|
while (currentIndex < pointSize)
|
||||||
{
|
{
|
||||||
if (!_points[currentIndex].isValid)
|
if (!_points[currentIndex].isValid)
|
||||||
{
|
{
|
||||||
@@ -318,7 +321,7 @@ namespace Misaki.ArtTool
|
|||||||
_objectGroup[objectIndex].Add(_points[currentIndex].matrix);
|
_objectGroup[objectIndex].Add(_points[currentIndex].matrix);
|
||||||
currentIndex++;
|
currentIndex++;
|
||||||
|
|
||||||
if (currentIndex >= _pointSize)
|
if (currentIndex >= pointSize)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -339,22 +342,17 @@ namespace Misaki.ArtTool
|
|||||||
currentIndex = 0;
|
currentIndex = 0;
|
||||||
if (!isRenderInstancing)
|
if (!isRenderInstancing)
|
||||||
{
|
{
|
||||||
if (_instantiateObjects != null)
|
_instantiateObjects.Capacity = pointSize;
|
||||||
{
|
|
||||||
_intPool.Return(_instantiateObjects, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
_instantiateObjects = _intPool.Rent(_pointSize);
|
var transformAccess = new TransformAccessArray(pointSize);
|
||||||
|
var pointsList = new NativeList<float4x4>(pointSize, Allocator.TempJob);
|
||||||
using var transformAccess = new TransformAccessArray(_pointSize);
|
|
||||||
using var pointsList = new NativeList<float4x4>(_pointSize, Allocator.TempJob);
|
|
||||||
|
|
||||||
foreach (var item in _objectGroup)
|
foreach (var item in _objectGroup)
|
||||||
{
|
{
|
||||||
var instantiateCount = item.Value.Count;
|
var instantiateCount = item.Value.Count;
|
||||||
|
|
||||||
using var instanceIDs = new NativeArray<int>(instantiateCount, Allocator.TempJob);
|
var instanceIDs = new NativeArray<int>(instantiateCount, Allocator.TempJob);
|
||||||
using var transformIDs = new NativeArray<int>(instantiateCount, Allocator.TempJob);
|
var transformIDs = new NativeArray<int>(instantiateCount, Allocator.TempJob);
|
||||||
|
|
||||||
GameObject.InstantiateGameObjects(inputObjects[item.Key].gameObject.GetInstanceID(), instantiateCount, instanceIDs, transformIDs);
|
GameObject.InstantiateGameObjects(inputObjects[item.Key].gameObject.GetInstanceID(), instantiateCount, instanceIDs, transformIDs);
|
||||||
|
|
||||||
@@ -363,9 +361,15 @@ namespace Misaki.ArtTool
|
|||||||
transformAccess.Add(transformIDs[i]);
|
transformAccess.Add(transformIDs[i]);
|
||||||
pointsList.Add(item.Value[i]);
|
pointsList.Add(item.Value[i]);
|
||||||
|
|
||||||
_instantiateObjects[currentIndex] = instanceIDs[i];
|
var instantiateObject = (GameObject)Resources.InstanceIDToObject(instanceIDs[i]);
|
||||||
|
instantiateObject.transform.parent = this.transform;
|
||||||
|
_instantiateObjects.Add(instantiateObject);
|
||||||
|
|
||||||
currentIndex++;
|
currentIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
instanceIDs.Dispose();
|
||||||
|
transformIDs.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
var transformAccessJob = new TransformAccessJob()
|
var transformAccessJob = new TransformAccessJob()
|
||||||
@@ -375,6 +379,9 @@ namespace Misaki.ArtTool
|
|||||||
|
|
||||||
var handle = transformAccessJob.Schedule(transformAccess);
|
var handle = transformAccessJob.Schedule(transformAccess);
|
||||||
handle.Complete();
|
handle.Complete();
|
||||||
|
|
||||||
|
transformAccess.Dispose();
|
||||||
|
pointsList.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -383,45 +390,38 @@ namespace Misaki.ArtTool
|
|||||||
if (isClearPoints && _points != null)
|
if (isClearPoints && _points != null)
|
||||||
{
|
{
|
||||||
_pointPool.Return(_points, true);
|
_pointPool.Return(_points, true);
|
||||||
_pointSize = 0;
|
pointSize = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isClearObjects)
|
if (isClearObjects)
|
||||||
{
|
{
|
||||||
_objectGroup.Clear();
|
if (_instantiateObjects == null || _instantiateObjects.Count <= 0)
|
||||||
|
|
||||||
if (_instantiateObjects == null || _instantiateObjects.Length <= 0 || _pointSize <= 0)
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var objectList = ListPool<Object>.Get();
|
for (var i = 0; i < _instantiateObjects.Count; i++)
|
||||||
using var idArray = new NativeArray<int>(_instantiateObjects.Length, Allocator.TempJob);
|
|
||||||
idArray.CopyFrom(_instantiateObjects);
|
|
||||||
|
|
||||||
Resources.InstanceIDToObjectList(idArray, objectList);
|
|
||||||
for (var i = 0; i < objectList.Count; i++)
|
|
||||||
{
|
{
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
DestroyImmediate(objectList[i]);
|
DestroyImmediate(_instantiateObjects[i]);
|
||||||
#else
|
#else
|
||||||
Destroy(child.gameObject);
|
Destroy(_instantiateObjects[i]);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
ListPool<Object>.Release(objectList);
|
_instantiateObjects.Clear();
|
||||||
_intPool.Return(_instantiateObjects, true);
|
_objectGroup.Clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnDrawGizmosSelected()
|
private void OnDrawGizmosSelected()
|
||||||
{
|
{
|
||||||
if (_pointSize <= 0 || _points.Length < _pointSize)
|
if (pointSize <= 0 || _points == null || _points.Length < pointSize)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < _pointSize; i++)
|
for (var i = 0; i < pointSize; i++)
|
||||||
{
|
{
|
||||||
var point = _points[i];
|
var point = _points[i];
|
||||||
|
|
||||||
@@ -440,15 +440,15 @@ namespace Misaki.ArtTool
|
|||||||
|
|
||||||
// Draw the x-axis in red
|
// Draw the x-axis in red
|
||||||
Gizmos.color = Color.red;
|
Gizmos.color = Color.red;
|
||||||
Gizmos.DrawLine(Vector3.zero, Vector3.right * scale * GIZMOS_BASE_SIZE);
|
Gizmos.DrawLine(Vector3.zero, Vector3.right * scale * gizmosSize);
|
||||||
|
|
||||||
// Draw the y-axis in green
|
// Draw the y-axis in green
|
||||||
Gizmos.color = Color.green;
|
Gizmos.color = Color.green;
|
||||||
Gizmos.DrawLine(Vector3.zero, Vector3.up * scale * GIZMOS_BASE_SIZE);
|
Gizmos.DrawLine(Vector3.zero, Vector3.up * scale * gizmosSize);
|
||||||
|
|
||||||
// Draw the z-axis in blue
|
// Draw the z-axis in blue
|
||||||
Gizmos.color = Color.blue;
|
Gizmos.color = Color.blue;
|
||||||
Gizmos.DrawLine(Vector3.zero, Vector3.forward * scale * GIZMOS_BASE_SIZE);
|
Gizmos.DrawLine(Vector3.zero, Vector3.forward * scale * gizmosSize);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DebugMode.Index:
|
case DebugMode.Index:
|
||||||
@@ -472,7 +472,7 @@ namespace Misaki.ArtTool
|
|||||||
Gizmos.color = Color.red;
|
Gizmos.color = Color.red;
|
||||||
}
|
}
|
||||||
|
|
||||||
Gizmos.DrawSphere(point.matrix.c3.xyz, GIZMOS_BASE_SIZE / 2.0f);
|
Gizmos.DrawSphere(point.matrix.GetPosition(), gizmosSize / 2.0f);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -17,14 +17,11 @@ namespace Misaki.ArtTool
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case GridShape.Sphere:
|
case GridShape.Sphere:
|
||||||
var isInsideSphere = ShapeHelper.IsPointInsideSphere(localPosition, 0.0f, setting.count * setting.spacing);
|
isValid = ShapeHelper.IsPointInsideSphere(localPosition, 0.0f, setting.count * setting.spacing);
|
||||||
|
|
||||||
isValid = isInsideSphere;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GridShape.Cylinder:
|
case GridShape.Cylinder:
|
||||||
var isInsideCylinder = ShapeHelper.IsPointInsideCylinder(localPosition, 0.0f, setting.count * setting.spacing);
|
isValid = ShapeHelper.IsPointInsideCylinder(localPosition, 0.0f, setting.count * setting.spacing);
|
||||||
isValid = isInsideCylinder;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
isValid = false;
|
isValid = false;
|
||||||
|
|||||||
@@ -1,80 +1,39 @@
|
|||||||
using Unity.Mathematics;
|
using Unity.Mathematics;
|
||||||
using Random = Unity.Mathematics.Random;
|
|
||||||
|
|
||||||
namespace Misaki.ArtTool
|
namespace Misaki.ArtTool
|
||||||
{
|
{
|
||||||
public static partial class Distribution
|
public static partial class Distribution
|
||||||
{
|
{
|
||||||
public static void ObjectDistribution(int index, ObjectDistributionSetting setting, out float4x4 localMatrix, out bool isValid)
|
public static void ObjectDistribution(int index, ref ObjectDistributionSetting setting, out float4x4 localMatrix, out bool isValid)
|
||||||
{
|
{
|
||||||
var random = new Random();
|
|
||||||
if (index > uint.MaxValue - setting.seed)
|
|
||||||
{
|
|
||||||
random = Random.CreateFromIndex(setting.seed - (uint)index);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
random = Random.CreateFromIndex(setting.seed + (uint)index);
|
|
||||||
}
|
|
||||||
|
|
||||||
var position = float3.zero;
|
|
||||||
var forwardDirection = new float3(0.0f, 0.0f, 1.0f);
|
|
||||||
var upDirection = new float3(0.0f, 1.0f, 0.0f);
|
|
||||||
isValid = false;
|
isValid = false;
|
||||||
|
localMatrix = float4x4.identity;
|
||||||
|
|
||||||
switch (setting.mode)
|
switch (setting.mode)
|
||||||
{
|
{
|
||||||
case ObjectDistributionMode.Surface:
|
case ObjectDistributionMode.Surface:
|
||||||
|
isValid = ShapeHelper.TryGetMatrixOnMeshSurface(index, setting.seed, setting.isAlignNormal, ref setting.meshData, out localMatrix);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ObjectDistributionMode.Volume:
|
case ObjectDistributionMode.Volume:
|
||||||
|
isValid = ShapeHelper.TryGetPositionInMeshVolume(index, setting.seed, ref setting.meshData, out localMatrix);
|
||||||
var meshScale = setting.meshData.worldMatrix.GetScale();
|
|
||||||
var meshPosition = setting.meshData.worldMatrix.c3.xyz;
|
|
||||||
|
|
||||||
position = random.NextFloat3(-setting.meshData.bounds.extents * meshScale + meshPosition, setting.meshData.bounds.extents * meshScale + meshPosition);
|
|
||||||
|
|
||||||
var isInsideMesh = ShapeHelper.IsPointInsideMesh(position, ref setting.meshData);
|
|
||||||
while (!isInsideMesh)
|
|
||||||
{
|
|
||||||
position = random.NextFloat3(-setting.meshData.bounds.extents * meshScale + meshPosition, setting.meshData.bounds.extents * meshScale + meshPosition);
|
|
||||||
isInsideMesh = ShapeHelper.IsPointInsideMesh(position, ref setting.meshData);
|
|
||||||
}
|
|
||||||
isValid = true;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ObjectDistributionMode.Vertex:
|
case ObjectDistributionMode.Vertex:
|
||||||
if (ShapeHelper.GetMeshVertexPosition(index, ref setting.meshData, out var vertexPosition))
|
isValid = ShapeHelper.TryGetMeshVertexMatrix(index, setting.isAlignNormal, ref setting.meshData, out localMatrix);
|
||||||
{
|
|
||||||
position = vertexPosition;
|
|
||||||
isValid = true;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ObjectDistributionMode.Edge:
|
case ObjectDistributionMode.Edge:
|
||||||
if (ShapeHelper.GetMeshEdgePosition(index, ref setting.meshData, out var edgePosition, out var edgeForward, out var edgeUp))
|
isValid = ShapeHelper.TryGetMeshEdgeMatrix(index, setting.isAlignNormal, ref setting.meshData, out localMatrix);
|
||||||
{
|
|
||||||
position = edgePosition;
|
|
||||||
forwardDirection = edgeForward;
|
|
||||||
upDirection = edgeUp;
|
|
||||||
isValid = true;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ObjectDistributionMode.PolygonCenter:
|
case ObjectDistributionMode.PolygonCenter:
|
||||||
if (ShapeHelper.GetMeshPolygonPosition(index, ref setting.meshData, out var polygonPosition))
|
isValid = ShapeHelper.TryGetMeshPolygonMatrix(index, setting.isAlignNormal, ref setting.meshData, out localMatrix);
|
||||||
{
|
|
||||||
position = polygonPosition;
|
|
||||||
isValid = true;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
var rotation = quaternion.LookRotationSafe(forwardDirection, upDirection);
|
|
||||||
|
|
||||||
localMatrix = float4x4.TRS(position, rotation, new float3(1.0f));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
13
Runtime/Cloner/Distribution/RadialDistribution.cs
Normal file
13
Runtime/Cloner/Distribution/RadialDistribution.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
using Unity.Mathematics;
|
||||||
|
|
||||||
|
namespace Misaki.ArtTool
|
||||||
|
{
|
||||||
|
public static partial class Distribution
|
||||||
|
{
|
||||||
|
public static void RadialDistribution(int index, RadialDistributionSetting setting, out float4x4 localMatrix, out bool isValid)
|
||||||
|
{
|
||||||
|
localMatrix = ShapeHelper.GetRadialMatrix(index, setting);
|
||||||
|
isValid = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
2
Runtime/Cloner/Distribution/RadialDistribution.cs.meta
Normal file
2
Runtime/Cloner/Distribution/RadialDistribution.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: c448aeab246b714458fee8084dd0974c
|
||||||
@@ -14,7 +14,7 @@ namespace Misaki.ArtTool
|
|||||||
{
|
{
|
||||||
var currentPoint = points[index];
|
var currentPoint = points[index];
|
||||||
|
|
||||||
var weight = CalculateFieldsWeight(currentPoint.matrix.c3.xyz);
|
var weight = CalculateFieldsWeight(currentPoint.matrix.GetPosition());
|
||||||
if (weight > 0)
|
if (weight > 0)
|
||||||
{
|
{
|
||||||
for (var i = 0; i < iteration; i++)
|
for (var i = 0; i < iteration; i++)
|
||||||
@@ -28,10 +28,10 @@ namespace Misaki.ArtTool
|
|||||||
|
|
||||||
var targetPoint = points[p];
|
var targetPoint = points[p];
|
||||||
|
|
||||||
var distance = math.distance(currentPoint.matrix.c3.xyz, targetPoint.matrix.c3.xyz);
|
var distance = math.distance(currentPoint.matrix.GetPosition(), targetPoint.matrix.GetPosition());
|
||||||
if (distance < radius)
|
if (distance < radius)
|
||||||
{
|
{
|
||||||
var direction = math.normalizesafe(currentPoint.matrix.c3.xyz - targetPoint.matrix.c3.xyz);
|
var direction = math.normalizesafe(currentPoint.matrix.GetPosition() - targetPoint.matrix.GetPosition());
|
||||||
currentPoint.matrix.c3.xyz += (radius - distance) * weight * direction;
|
currentPoint.matrix.c3.xyz += (radius - distance) * weight * direction;
|
||||||
|
|
||||||
//Debug.Log($"Push at index {index} with distance {radius - distance} and direction {direction}");
|
//Debug.Log($"Push at index {index} with distance {radius - distance} and direction {direction}");
|
||||||
|
|||||||
9
Runtime/Cloner/Enums/PlaneDirection.cs
Normal file
9
Runtime/Cloner/Enums/PlaneDirection.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
namespace Misaki.ArtTool
|
||||||
|
{
|
||||||
|
public enum PlaneDirection
|
||||||
|
{
|
||||||
|
XY,
|
||||||
|
ZY,
|
||||||
|
XZ
|
||||||
|
}
|
||||||
|
}
|
||||||
2
Runtime/Cloner/Enums/PlaneDirection.cs.meta
Normal file
2
Runtime/Cloner/Enums/PlaneDirection.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 77fcb516b231dd749b3654e9e1fd1c9f
|
||||||
@@ -4,7 +4,7 @@ namespace Misaki.ArtTool
|
|||||||
{
|
{
|
||||||
internal class FieldHelper
|
internal class FieldHelper
|
||||||
{
|
{
|
||||||
public static float BlendField(float a, float b, float t, BlendingMode blendingMode)
|
internal static float BlendField(float a, float b, float t, BlendingMode blendingMode)
|
||||||
{
|
{
|
||||||
var result = 0.0f;
|
var result = 0.0f;
|
||||||
switch (blendingMode)
|
switch (blendingMode)
|
||||||
@@ -53,7 +53,7 @@ namespace Misaki.ArtTool
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static float ApplyRemapping(float weight, ref RemappingSetting remappingSetting)
|
internal static float ApplyRemapping(float weight, ref RemappingSetting remappingSetting)
|
||||||
{
|
{
|
||||||
if (!remappingSetting.enable)
|
if (!remappingSetting.enable)
|
||||||
{
|
{
|
||||||
|
|||||||
12
Runtime/Cloner/Helper/FormulaHelper.cs
Normal file
12
Runtime/Cloner/Helper/FormulaHelper.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
using Unity.Collections;
|
||||||
|
|
||||||
|
namespace Misaki.ArtTool
|
||||||
|
{
|
||||||
|
internal class FormulaHelper
|
||||||
|
{
|
||||||
|
private void Paras(NativeText inputFormula)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
2
Runtime/Cloner/Helper/FormulaHelper.cs.meta
Normal file
2
Runtime/Cloner/Helper/FormulaHelper.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 7218fdc62c3673347a29f030a4217533
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using Unity.Mathematics;
|
using Unity.Mathematics;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
@@ -98,6 +99,20 @@ namespace Misaki.ArtTool
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
internal static float3 GetPosition(this float4x4 matrix)
|
||||||
|
{
|
||||||
|
return matrix.c3.xyz;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
internal static quaternion GetRotation(this float4x4 matrix)
|
||||||
|
{
|
||||||
|
var scale = new float3(math.length(matrix.c0.xyz), math.length(matrix.c1.xyz), math.length(matrix.c2.xyz));
|
||||||
|
return Quaternion.LookRotation(matrix.c2.xyz / scale.z, matrix.c1.xyz / scale.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
internal static float3 GetScale(this float4x4 matrix)
|
internal static float3 GetScale(this float4x4 matrix)
|
||||||
{
|
{
|
||||||
return new float3(math.length(matrix.c0.xyz), math.length(matrix.c1.xyz), math.length(matrix.c2.xyz));
|
return new float3(math.length(matrix.c0.xyz), math.length(matrix.c1.xyz), math.length(matrix.c2.xyz));
|
||||||
|
|||||||
@@ -12,14 +12,62 @@ namespace Misaki.ArtTool
|
|||||||
var zIndex = remain / size.x;
|
var zIndex = remain / size.x;
|
||||||
var xIndex = remain % size.x;
|
var xIndex = remain % size.x;
|
||||||
|
|
||||||
localPosition = new float3(xIndex, yIndex, zIndex);
|
localPosition = new float3((int)xIndex, (int)yIndex, (int)zIndex);
|
||||||
localPosition -= (size - 1) * 0.5f;
|
localPosition -= (size - 1) * 0.5f;
|
||||||
return localPosition;
|
return localPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static bool GetMeshVertexPosition(int index, ref MeshData meshData, out float3 position)
|
internal static float4x4 GetRadialMatrix(int index, RadialDistributionSetting setting)
|
||||||
{
|
{
|
||||||
position = float3.zero;
|
var staringAngle = math.radians(setting.angleMinMax.x);
|
||||||
|
var totalAngle = math.TAU / (360.0f / setting.angleMinMax.y) - staringAngle;
|
||||||
|
var angleStep = totalAngle / setting.count;
|
||||||
|
|
||||||
|
var angle = index * angleStep + staringAngle;
|
||||||
|
var x = math.cos(-angle) * setting.radius;
|
||||||
|
var y = math.sin(-angle) * setting.radius;
|
||||||
|
|
||||||
|
var position = float3.zero;
|
||||||
|
switch (setting.plane)
|
||||||
|
{
|
||||||
|
case PlaneDirection.XY:
|
||||||
|
position = new float3(x, y, 0);
|
||||||
|
break;
|
||||||
|
case PlaneDirection.ZY:
|
||||||
|
position = new float3(0, x, y);
|
||||||
|
break;
|
||||||
|
case PlaneDirection.XZ:
|
||||||
|
position = new float3(x, 0, y);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var rotation = quaternion.identity;
|
||||||
|
if (setting.align)
|
||||||
|
{
|
||||||
|
switch (setting.plane)
|
||||||
|
{
|
||||||
|
case PlaneDirection.XY:
|
||||||
|
rotation = quaternion.EulerXYZ(0.0f, 0.0f, angle);
|
||||||
|
break;
|
||||||
|
case PlaneDirection.ZY:
|
||||||
|
rotation = quaternion.EulerXYZ(angle, 0.0f, 0.0f);
|
||||||
|
break;
|
||||||
|
case PlaneDirection.XZ:
|
||||||
|
rotation = quaternion.EulerXYZ(0.0f, angle, 0.0f);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return float4x4.TRS(position, rotation, new float3(1.0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static bool TryGetMeshVertexMatrix(int index, bool alignNormal, ref MeshData meshData, out float4x4 outMatrix)
|
||||||
|
{
|
||||||
|
outMatrix = float4x4.identity;
|
||||||
|
|
||||||
if (!meshData.vertices.IsCreated || meshData.vertices.Length <= index)
|
if (!meshData.vertices.IsCreated || meshData.vertices.Length <= index)
|
||||||
{
|
{
|
||||||
@@ -27,22 +75,32 @@ namespace Misaki.ArtTool
|
|||||||
}
|
}
|
||||||
|
|
||||||
var meshScale = meshData.worldMatrix.GetScale();
|
var meshScale = meshData.worldMatrix.GetScale();
|
||||||
var meshPosition = meshData.worldMatrix.c3.xyz;
|
var meshPosition = meshData.worldMatrix.GetPosition();
|
||||||
|
|
||||||
if (index >= meshData.vertices.Length)
|
if (index >= meshData.vertices.Length)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
position = meshData.vertices[index] * meshScale + meshPosition;
|
var position = meshData.vertices[index] * meshScale + meshPosition;
|
||||||
|
|
||||||
|
var rotation = quaternion.identity;
|
||||||
|
if (alignNormal)
|
||||||
|
{
|
||||||
|
var upDirection = meshData.normals[index];
|
||||||
|
var forwardDirection = math.normalize(math.cross(upDirection, new float3(-1.0f, 0.0f, 0.0f)));
|
||||||
|
|
||||||
|
rotation = quaternion.LookRotation(forwardDirection, upDirection);
|
||||||
|
}
|
||||||
|
|
||||||
|
outMatrix = float4x4.TRS(position, rotation, new float3(1.0f));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static bool GetMeshEdgePosition(int index, ref MeshData meshData, out float3 position, out float3 forwardDirection, out float3 upDirection)
|
internal static bool TryGetMeshEdgeMatrix(int index, bool alignNormal, ref MeshData meshData, out float4x4 outMatrix)
|
||||||
{
|
{
|
||||||
position = float3.zero;
|
outMatrix = float4x4.identity;
|
||||||
forwardDirection = new float3(0.0f, 0.0f, 1.0f);
|
|
||||||
upDirection = new float3(0.0f, 1.0f, 0.0f);
|
|
||||||
|
|
||||||
if (!meshData.edges.IsCreated || index >= meshData.edges.Length)
|
if (!meshData.edges.IsCreated || index >= meshData.edges.Length)
|
||||||
{
|
{
|
||||||
@@ -55,38 +113,38 @@ namespace Misaki.ArtTool
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var a = meshData.vertices[edge.x];
|
||||||
|
var b = meshData.vertices[edge.y];
|
||||||
|
|
||||||
|
var position = (a + b) / 2.0f;
|
||||||
|
var forwardDirection = math.normalize(a - b);
|
||||||
|
|
||||||
var meshScale = meshData.worldMatrix.GetScale();
|
var meshScale = meshData.worldMatrix.GetScale();
|
||||||
var meshPosition = meshData.worldMatrix.c3.xyz;
|
var meshPosition = meshData.worldMatrix.GetPosition();
|
||||||
|
position = position * meshScale + meshPosition;
|
||||||
|
|
||||||
var a = meshData.vertices[edge.x] * meshScale + meshPosition;
|
var rotation = quaternion.identity;
|
||||||
var b = meshData.vertices[edge.y] * meshScale + meshPosition;
|
if (alignNormal)
|
||||||
|
|
||||||
position = (a + b) / 2.0f;
|
|
||||||
forwardDirection = a - b;
|
|
||||||
|
|
||||||
var interpNormal = math.normalize(meshData.normals[edge.x] + meshData.normals[edge.y]);
|
|
||||||
upDirection = math.normalize(math.cross(interpNormal, new float3(1.0f, 0.0f, 0.0f)));
|
|
||||||
|
|
||||||
if (math.all(upDirection <= float3.zero))
|
|
||||||
{
|
{
|
||||||
upDirection = math.normalize(math.cross(interpNormal, new float3(0.0f, 0.0f, 1.0f)));
|
var upDirection = math.normalize(meshData.normals[edge.x] + meshData.normals[edge.y]);
|
||||||
|
rotation = quaternion.LookRotation(forwardDirection, upDirection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
outMatrix = float4x4.TRS(position, rotation, new float3(1.0f));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static bool GetMeshPolygonPosition(int index, ref MeshData meshData, out float3 position)
|
//TODO : interpolate normal based on distance
|
||||||
|
internal static bool TryGetMeshPolygonMatrix(int index, bool alignNormal, ref MeshData meshData, out float4x4 outMatrix)
|
||||||
{
|
{
|
||||||
position = float3.zero;
|
outMatrix = float4x4.identity;
|
||||||
|
|
||||||
if (!meshData.edges.IsCreated || meshData.edges.Length <= index)
|
if (!meshData.edges.IsCreated || meshData.edges.Length <= index)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var meshScale = meshData.worldMatrix.GetScale();
|
|
||||||
var meshPosition = meshData.worldMatrix.c3.xyz;
|
|
||||||
|
|
||||||
var triangleIndex = index * 3;
|
var triangleIndex = index * 3;
|
||||||
|
|
||||||
if (triangleIndex >= meshData.triangles.Length - 2)
|
if (triangleIndex >= meshData.triangles.Length - 2)
|
||||||
@@ -94,15 +152,110 @@ namespace Misaki.ArtTool
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var pointIndexA = meshData.triangles[triangleIndex];
|
var vertexIndexA = meshData.triangles[triangleIndex];
|
||||||
var pointIndexB = meshData.triangles[triangleIndex + 1];
|
var vertexIndexB = meshData.triangles[triangleIndex + 1];
|
||||||
var pointIndexC = meshData.triangles[triangleIndex + 2];
|
var vertexIndexC = meshData.triangles[triangleIndex + 2];
|
||||||
|
|
||||||
var a = meshData.vertices[pointIndexA] * meshScale + meshPosition;
|
var a = meshData.vertices[vertexIndexA];
|
||||||
var b = meshData.vertices[pointIndexB] * meshScale + meshPosition;
|
var b = meshData.vertices[vertexIndexB];
|
||||||
var c = meshData.vertices[pointIndexC] * meshScale + meshPosition;
|
var c = meshData.vertices[vertexIndexC];
|
||||||
|
|
||||||
position = (a + b + c) / 3.0f;
|
var position = (a + b + c) / 3.0f;
|
||||||
|
|
||||||
|
var meshScale = meshData.worldMatrix.GetScale();
|
||||||
|
var meshPosition = meshData.worldMatrix.GetPosition();
|
||||||
|
position = position * meshScale + meshPosition;
|
||||||
|
|
||||||
|
var rotation = quaternion.identity;
|
||||||
|
if (alignNormal)
|
||||||
|
{
|
||||||
|
var upDirection = math.normalize(meshData.normals[vertexIndexA] + meshData.normals[vertexIndexB] + meshData.normals[vertexIndexC]);
|
||||||
|
var forwardDirection = math.normalize(math.cross(upDirection, new float3(-1.0f, 0.0f, 0.0f)));
|
||||||
|
|
||||||
|
rotation = quaternion.LookRotation(forwardDirection, upDirection);
|
||||||
|
}
|
||||||
|
|
||||||
|
outMatrix = float4x4.TRS(position, rotation, new float3(1.0f));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO : interpolate normal based on distance
|
||||||
|
internal static bool TryGetMatrixOnMeshSurface(int index, uint seed, bool alignNormal, ref MeshData meshData, out float4x4 outMatrix)
|
||||||
|
{
|
||||||
|
outMatrix = float4x4.identity;
|
||||||
|
|
||||||
|
if (!meshData.areas.IsCreated || !meshData.vertices.IsCreated || !meshData.triangles.IsCreated)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var random = Random.CreateFromIndex(seed + (uint)index);
|
||||||
|
var randomValue = random.NextFloat(meshData.totalArea);
|
||||||
|
|
||||||
|
var triangleIndex = -1;
|
||||||
|
for (var j = 0; j < meshData.areas.Length; j++)
|
||||||
|
{
|
||||||
|
if (randomValue <= meshData.areas[j])
|
||||||
|
{
|
||||||
|
triangleIndex = j * 3;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
randomValue -= meshData.areas[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (triangleIndex >= meshData.triangles.Length - 2)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var vertexIndexA = meshData.triangles[triangleIndex];
|
||||||
|
var vertexIndexB = meshData.triangles[triangleIndex + 1];
|
||||||
|
var vertexIndexC = meshData.triangles[triangleIndex + 2];
|
||||||
|
|
||||||
|
var a = meshData.vertices[vertexIndexA];
|
||||||
|
var b = meshData.vertices[vertexIndexB];
|
||||||
|
var c = meshData.vertices[vertexIndexC];
|
||||||
|
|
||||||
|
var r1 = math.sqrt(random.NextFloat());
|
||||||
|
var r2 = random.NextFloat();
|
||||||
|
|
||||||
|
var position = (1 - r1) * a + (r1 * (1 - r2)) * b + (r1 * r2) * c;
|
||||||
|
|
||||||
|
var meshScale = meshData.worldMatrix.GetScale();
|
||||||
|
var meshPosition = meshData.worldMatrix.GetPosition();
|
||||||
|
position = position * meshScale + meshPosition;
|
||||||
|
|
||||||
|
var rotation = quaternion.identity;
|
||||||
|
if (alignNormal)
|
||||||
|
{
|
||||||
|
var upDirection = math.normalize(meshData.normals[vertexIndexA] + meshData.normals[vertexIndexB] + meshData.normals[vertexIndexC]);
|
||||||
|
var forwardDirection = math.normalize(math.cross(upDirection, new float3(-1.0f, 0.0f, 0.0f)));
|
||||||
|
|
||||||
|
rotation = quaternion.LookRotation(forwardDirection, upDirection);
|
||||||
|
}
|
||||||
|
|
||||||
|
outMatrix = float4x4.TRS(position, rotation, new float3(1.0f));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static bool TryGetPositionInMeshVolume(int index, uint seed, ref MeshData meshData, out float4x4 outMatrix)
|
||||||
|
{
|
||||||
|
var random = Random.CreateFromIndex(seed + (uint)index);
|
||||||
|
var meshScale = meshData.worldMatrix.GetScale();
|
||||||
|
var meshPosition = meshData.worldMatrix.GetPosition();
|
||||||
|
|
||||||
|
var volumePosition = random.NextFloat3(-meshData.bounds.extents * meshScale + meshPosition, meshData.bounds.extents * meshScale + meshPosition);
|
||||||
|
|
||||||
|
var isInsideMesh = IsPointInsideMesh(volumePosition, ref meshData);
|
||||||
|
while (!isInsideMesh)
|
||||||
|
{
|
||||||
|
volumePosition = random.NextFloat3(-meshData.bounds.extents * meshScale + meshPosition, meshData.bounds.extents * meshScale + meshPosition);
|
||||||
|
isInsideMesh = IsPointInsideMesh(volumePosition, ref meshData);
|
||||||
|
}
|
||||||
|
|
||||||
|
outMatrix = float4x4.TRS(volumePosition, quaternion.identity, new float3(1.0f));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ namespace Misaki.ArtTool
|
|||||||
{
|
{
|
||||||
var windingNumber = 0;
|
var windingNumber = 0;
|
||||||
var meshScale = meshData.worldMatrix.GetScale();
|
var meshScale = meshData.worldMatrix.GetScale();
|
||||||
var meshPosition = meshData.worldMatrix.c3.xyz;
|
var meshPosition = meshData.worldMatrix.GetPosition();
|
||||||
|
|
||||||
for (var i = 0; i < meshData.triangles.Length; i += 3)
|
for (var i = 0; i < meshData.triangles.Length; i += 3)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ namespace Misaki.ArtTool
|
|||||||
public SplineDistributionSetting splineDistributionSetting;
|
public SplineDistributionSetting splineDistributionSetting;
|
||||||
public LinearDistributionSetting linearDistributionSetting;
|
public LinearDistributionSetting linearDistributionSetting;
|
||||||
public GridDistributionSetting gridDistributionSetting;
|
public GridDistributionSetting gridDistributionSetting;
|
||||||
|
public RadialDistributionSetting radialDistributionSetting;
|
||||||
|
|
||||||
[WriteOnly]
|
[WriteOnly]
|
||||||
public NativeArray<PointData> points;
|
public NativeArray<PointData> points;
|
||||||
@@ -30,7 +31,7 @@ namespace Misaki.ArtTool
|
|||||||
switch (distributionMode)
|
switch (distributionMode)
|
||||||
{
|
{
|
||||||
case DistributionMode.Object:
|
case DistributionMode.Object:
|
||||||
Distribution.ObjectDistribution(i, objectDistributionSetting, out pointMatrix, out isValid);
|
Distribution.ObjectDistribution(i, ref objectDistributionSetting, out pointMatrix, out isValid);
|
||||||
break;
|
break;
|
||||||
case DistributionMode.Spline:
|
case DistributionMode.Spline:
|
||||||
Distribution.SplineDistribution(i, pointSize, splineDistributionSetting, out pointMatrix, out isValid);
|
Distribution.SplineDistribution(i, pointSize, splineDistributionSetting, out pointMatrix, out isValid);
|
||||||
@@ -42,6 +43,7 @@ namespace Misaki.ArtTool
|
|||||||
Distribution.GridDistribution(i, gridDistributionSetting, out pointMatrix, out isValid);
|
Distribution.GridDistribution(i, gridDistributionSetting, out pointMatrix, out isValid);
|
||||||
break;
|
break;
|
||||||
case DistributionMode.Radial:
|
case DistributionMode.Radial:
|
||||||
|
Distribution.RadialDistribution(i, radialDistributionSetting, out pointMatrix, out isValid);
|
||||||
break;
|
break;
|
||||||
case DistributionMode.Honeycomb:
|
case DistributionMode.Honeycomb:
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ namespace Misaki.ArtTool
|
|||||||
public ObjectDistributionMode mode;
|
public ObjectDistributionMode mode;
|
||||||
public uint count;
|
public uint count;
|
||||||
public uint seed;
|
public uint seed;
|
||||||
public bool alignNormal;
|
public bool isAlignNormal;
|
||||||
|
|
||||||
public int DistributionCount
|
public int DistributionCount
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
using System;
|
||||||
|
using Unity.Mathematics;
|
||||||
|
|
||||||
|
namespace Misaki.ArtTool
|
||||||
|
{
|
||||||
|
[Serializable]
|
||||||
|
public struct RadialDistributionSetting
|
||||||
|
{
|
||||||
|
public uint count;
|
||||||
|
public float radius;
|
||||||
|
public PlaneDirection plane;
|
||||||
|
public float2 angleMinMax;
|
||||||
|
public bool align;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 577cc0a461b273d42be5e22ecc600d8a
|
||||||
@@ -17,6 +17,10 @@ namespace Misaki.ArtTool
|
|||||||
public NativeArray<float3> vertices;
|
public NativeArray<float3> vertices;
|
||||||
[ReadOnly]
|
[ReadOnly]
|
||||||
public NativeList<int2> edges;
|
public NativeList<int2> edges;
|
||||||
|
[ReadOnly]
|
||||||
|
public NativeArray<float> areas;
|
||||||
|
|
||||||
|
public float totalArea;
|
||||||
|
|
||||||
public int vertexCount;
|
public int vertexCount;
|
||||||
|
|
||||||
@@ -31,6 +35,9 @@ namespace Misaki.ArtTool
|
|||||||
vertices = new(0, allocator);
|
vertices = new(0, allocator);
|
||||||
edges = new(0, allocator);
|
edges = new(0, allocator);
|
||||||
|
|
||||||
|
areas = new(0, allocator);
|
||||||
|
totalArea = 0.0f;
|
||||||
|
|
||||||
vertexCount = 0;
|
vertexCount = 0;
|
||||||
worldMatrix = float4x4.identity;
|
worldMatrix = float4x4.identity;
|
||||||
}
|
}
|
||||||
@@ -69,17 +76,37 @@ namespace Misaki.ArtTool
|
|||||||
AddEdge(edges, triangles[i + 2], triangles[i]);
|
AddEdge(edges, triangles[i + 2], triangles[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
areas = new(mesh.triangles.Length / 3, allocator);
|
||||||
|
totalArea = 0.0f;
|
||||||
|
for (var i = 0; i < triangles.Length; i += 3)
|
||||||
|
{
|
||||||
|
Vector3 v0 = vertices[triangles[i]];
|
||||||
|
Vector3 v1 = vertices[triangles[i + 1]];
|
||||||
|
Vector3 v2 = vertices[triangles[i + 2]];
|
||||||
|
var area = Vector3.Cross(v1 - v0, v2 - v0).magnitude * 0.5f;
|
||||||
|
areas[i / 3] = area;
|
||||||
|
totalArea += area;
|
||||||
|
}
|
||||||
|
|
||||||
worldMatrix = meshFilter.transform.localToWorldMatrix;
|
worldMatrix = meshFilter.transform.localToWorldMatrix;
|
||||||
|
|
||||||
static void AddEdge(NativeList<int2> edges, int a, int b)
|
static void AddEdge(NativeList<int2> edges, int a, int b)
|
||||||
{
|
{
|
||||||
if (a < b)
|
if (a < b)
|
||||||
{
|
{
|
||||||
edges.Add(new int2(a, b));
|
var edge = new int2(a, b);
|
||||||
|
if (!edges.Contains(edge))
|
||||||
|
{
|
||||||
|
edges.Add(edge);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
edges.Add(new int2(b, a));
|
var edge = new int2(b, a);
|
||||||
|
if (!edges.Contains(edge))
|
||||||
|
{
|
||||||
|
edges.Add(edge);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -90,6 +117,7 @@ namespace Misaki.ArtTool
|
|||||||
normals.Dispose();
|
normals.Dispose();
|
||||||
vertices.Dispose();
|
vertices.Dispose();
|
||||||
edges.Dispose();
|
edges.Dispose();
|
||||||
|
areas.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,38 +4,9 @@ using Unity.Mathematics;
|
|||||||
namespace Misaki.ArtTool
|
namespace Misaki.ArtTool
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public struct PointData : IEquatable<PointData>
|
public struct PointData
|
||||||
{
|
{
|
||||||
public bool isValid;
|
public bool isValid;
|
||||||
public float4x4 matrix;
|
public float4x4 matrix;
|
||||||
|
|
||||||
public bool Equals(PointData other)
|
|
||||||
{
|
|
||||||
return isValid == other.isValid && Equals(matrix, other.matrix);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
|
||||||
{
|
|
||||||
if (obj is PointData other)
|
|
||||||
{
|
|
||||||
return Equals(other);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode()
|
|
||||||
{
|
|
||||||
return HashCode.Combine(isValid, matrix);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool operator ==(PointData left, PointData right)
|
|
||||||
{
|
|
||||||
return left.Equals(right);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool operator !=(PointData left, PointData right)
|
|
||||||
{
|
|
||||||
return !(left == right);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user