Cailean Finn
9 months ago
38 changed files with 31850 additions and 2 deletions
@ -0,0 +1,8 @@ |
|||
fileFormatVersion: 2 |
|||
guid: 0742a7add6bdfb84f81e897f7a4aa627 |
|||
folderAsset: yes |
|||
DefaultImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
@ -0,0 +1,16 @@ |
|||
using UnityEngine; |
|||
using UnityEditor; |
|||
|
|||
namespace SplatVfx.Editor { |
|||
|
|||
[CustomEditor(typeof(SplatData))] |
|||
public sealed class SplatDataInspector : UnityEditor.Editor |
|||
{ |
|||
public override void OnInspectorGUI() |
|||
{ |
|||
var count = ((SplatData)target).SplatCount; |
|||
EditorGUILayout.LabelField("Splat Count", $"{count:N0}"); |
|||
} |
|||
} |
|||
|
|||
} // namespace SplatVfx.Editor
|
@ -0,0 +1,11 @@ |
|||
fileFormatVersion: 2 |
|||
guid: 90300afbf61b2ac46906aa1e19eedddc |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
@ -0,0 +1,122 @@ |
|||
using Unity.Burst; |
|||
using Unity.Mathematics; |
|||
using UnityEngine; |
|||
using UnityEngine.VFX; |
|||
using UnityEngine.VFX.Utility; |
|||
using UnityEditor; |
|||
using UnityEditor.AssetImporters; |
|||
using UnityEditor.Experimental; |
|||
using System; |
|||
using System.IO; |
|||
using System.Runtime.InteropServices; |
|||
|
|||
namespace SplatVfx.Editor { |
|||
|
|||
[ScriptedImporter(1, "splat"), BurstCompile] |
|||
public sealed class SplatImporter : ScriptedImporter |
|||
{ |
|||
#region ScriptedImporter implementation
|
|||
|
|||
public override void OnImportAsset(AssetImportContext context) |
|||
{ |
|||
var data = ImportAsSplatData(context.assetPath); |
|||
var prefab = CreatePrefab(data); |
|||
context.AddObjectToAsset("prefab", prefab); |
|||
context.AddObjectToAsset("data", data); |
|||
context.SetMainObject(prefab); |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region Prefab construction
|
|||
|
|||
const string DefaultVfxPath = "Packages/jp.keijiro.splat-vfx/VFX/Splat.vfx"; |
|||
|
|||
GameObject CreatePrefab(SplatData data) |
|||
{ |
|||
var go = new GameObject(); |
|||
|
|||
var vfx = go.AddComponent<VisualEffect>(); |
|||
vfx.visualEffectAsset = EditorResources.Load<VisualEffectAsset>(DefaultVfxPath); |
|||
|
|||
var binderBase = go.AddComponent<VFXPropertyBinder>(); |
|||
var binder = binderBase.AddPropertyBinder<VFXSplatDataBinder>(); |
|||
binder.SplatData = data; |
|||
|
|||
return go; |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region Reader implementation
|
|||
|
|||
SplatData ImportAsSplatData(string path) |
|||
{ |
|||
var data = ScriptableObject.CreateInstance<SplatData>(); |
|||
data.name = Path.GetFileNameWithoutExtension(path); |
|||
|
|||
var arrays = LoadDataArrays(path); |
|||
data.PositionArray = arrays.position; |
|||
data.AxisArray = arrays.axis; |
|||
data.ColorArray = arrays.color; |
|||
data.ReleaseGpuResources(); |
|||
|
|||
return data; |
|||
} |
|||
|
|||
#pragma warning disable CS0649
|
|||
|
|||
struct ReadData |
|||
{ |
|||
public float px, py, pz; |
|||
public float sx, sy, sz; |
|||
public byte r, g, b, a; |
|||
public byte rw, rx, ry, rz; |
|||
} |
|||
|
|||
#pragma warning restore CS0649
|
|||
|
|||
(Vector3[] position, Vector3[] axis, Color[] color) |
|||
LoadDataArrays(string path) |
|||
{ |
|||
var bytes = (Span<byte>)File.ReadAllBytes(path); |
|||
var count = bytes.Length / 32; |
|||
|
|||
var source = MemoryMarshal.Cast<byte, ReadData>(bytes); |
|||
|
|||
var position = new Vector3[count]; |
|||
var axis = new Vector3[count * 3]; |
|||
var color = new Color[count]; |
|||
|
|||
for (var i = 0; i < count; i++) |
|||
ParseReadData(source[i], |
|||
out position[i], |
|||
out axis[i * 3], |
|||
out axis[i * 3 + 1], |
|||
out axis[i * 3 + 2], |
|||
out color[i]); |
|||
|
|||
return (position, axis, color); |
|||
} |
|||
|
|||
[BurstCompile] |
|||
void ParseReadData(in ReadData src, |
|||
out Vector3 position, |
|||
out Vector3 axis1, |
|||
out Vector3 axis2, |
|||
out Vector3 axis3, |
|||
out Color color) |
|||
{ |
|||
var rv = (math.float4(src.rx, src.ry, src.rz, src.rw) - 128) / 128; |
|||
var q = math.quaternion(-rv.x, -rv.y, rv.z, rv.w); |
|||
position = math.float3(src.px, src.py, -src.pz); |
|||
axis1 = math.mul(q, math.float3(src.sx, 0, 0)); |
|||
axis2 = math.mul(q, math.float3(0, src.sy, 0)); |
|||
axis3 = math.mul(q, math.float3(0, 0, src.sz)); |
|||
color = (Vector4)math.float4(src.r, src.g, src.b, src.a) / 255; |
|||
} |
|||
|
|||
#endregion
|
|||
} |
|||
|
|||
} // namespace SplatVfx.Editor
|
@ -0,0 +1,11 @@ |
|||
fileFormatVersion: 2 |
|||
guid: 7a7f5d2fd17129a42904e57ffbcf8a67 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
@ -0,0 +1,21 @@ |
|||
{ |
|||
"name": "SplatVfx.Editor", |
|||
"rootNamespace": "", |
|||
"references": [ |
|||
"GUID:57d6a1ae39d606347b1307f1eadefe70", |
|||
"GUID:d8b63aba1907145bea998dd612889d6b", |
|||
"GUID:2665a8d13d1b3f18800f46e256720795", |
|||
"GUID:d04eb9c554ad44ceab303cecf0c0cf82" |
|||
], |
|||
"includePlatforms": [ |
|||
"Editor" |
|||
], |
|||
"excludePlatforms": [], |
|||
"allowUnsafeCode": false, |
|||
"overrideReferences": false, |
|||
"precompiledReferences": [], |
|||
"autoReferenced": true, |
|||
"defineConstraints": [], |
|||
"versionDefines": [], |
|||
"noEngineReferences": false |
|||
} |
@ -0,0 +1,7 @@ |
|||
fileFormatVersion: 2 |
|||
guid: f9e984872a36ed840845202c3d099efc |
|||
AssemblyDefinitionImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
@ -0,0 +1,8 @@ |
|||
fileFormatVersion: 2 |
|||
guid: 1fed89f6395c66f45869fa300c022eae |
|||
folderAsset: yes |
|||
DefaultImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
@ -0,0 +1,70 @@ |
|||
using UnityEngine; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
|
|||
namespace SplatVfx { |
|||
|
|||
public sealed class SplatData : ScriptableObject |
|||
{ |
|||
#region Public properties
|
|||
|
|||
public int SplatCount => PositionArray.Length; |
|||
public GraphicsBuffer PositionBuffer => GetCachedBuffers().position; |
|||
public GraphicsBuffer AxisBuffer => GetCachedBuffers().axis; |
|||
public GraphicsBuffer ColorBuffer => GetCachedBuffers().color; |
|||
|
|||
#endregion
|
|||
|
|||
#region Serialized data
|
|||
|
|||
[field:SerializeField] public Vector3[] PositionArray { get; set; } |
|||
[field:SerializeField] public Vector3[] AxisArray { get; set; } |
|||
[field:SerializeField] public Color[] ColorArray { get; set; } |
|||
|
|||
#endregion
|
|||
|
|||
#region Public methods
|
|||
|
|||
public void ReleaseGpuResources() |
|||
{ |
|||
_cachedBuffers.position?.Release(); |
|||
_cachedBuffers.axis?.Release(); |
|||
_cachedBuffers.color?.Release(); |
|||
_cachedBuffers = (null, null, null); |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region GPU resource management
|
|||
|
|||
(GraphicsBuffer position, GraphicsBuffer axis, GraphicsBuffer color) |
|||
_cachedBuffers; |
|||
|
|||
static unsafe GraphicsBuffer NewBuffer<T>(int count) where T : unmanaged |
|||
=> new GraphicsBuffer(GraphicsBuffer.Target.Structured, count, sizeof(T)); |
|||
|
|||
(GraphicsBuffer position, GraphicsBuffer axis, GraphicsBuffer color) |
|||
GetCachedBuffers() |
|||
{ |
|||
if (_cachedBuffers.position == null) |
|||
{ |
|||
_cachedBuffers.position = NewBuffer<Vector3>(SplatCount); |
|||
_cachedBuffers.axis = NewBuffer<Vector3>(SplatCount * 3); |
|||
_cachedBuffers.color = NewBuffer<Color>(SplatCount); |
|||
_cachedBuffers.position.SetData(PositionArray); |
|||
_cachedBuffers.axis.SetData(AxisArray); |
|||
_cachedBuffers.color.SetData(ColorArray); |
|||
} |
|||
return _cachedBuffers; |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region ScriptableObject implementation
|
|||
|
|||
void OnDisable() => ReleaseGpuResources(); |
|||
|
|||
#endregion
|
|||
} |
|||
|
|||
} // namespace SplatVfx
|
@ -0,0 +1,11 @@ |
|||
fileFormatVersion: 2 |
|||
guid: 99e8102f25e54bf4d89eb4309bb9901a |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
@ -0,0 +1,61 @@ |
|||
using UnityEngine; |
|||
using UnityEngine.VFX; |
|||
using UnityEngine.VFX.Utility; |
|||
|
|||
namespace SplatVfx { |
|||
|
|||
[AddComponentMenu("VFX/Property Binders/Splat Data Binder")] |
|||
[VFXBinder("Splat Data")] |
|||
public sealed class VFXSplatDataBinder : VFXBinderBase |
|||
{ |
|||
public SplatData SplatData = null; |
|||
|
|||
public string SplatCountProperty |
|||
{ get => (string)_splatCountProperty; |
|||
set => _splatCountProperty = value; } |
|||
|
|||
public string PositionBufferProperty |
|||
{ get => (string)_positionBufferProperty; |
|||
set => _positionBufferProperty = value; } |
|||
|
|||
public string AxisBufferProperty |
|||
{ get => (string)_axisBufferProperty; |
|||
set => _axisBufferProperty = value; } |
|||
|
|||
public string ColorBufferProperty |
|||
{ get => (string)_colorBufferProperty; |
|||
set => _colorBufferProperty = value; } |
|||
|
|||
[VFXPropertyBinding("System.UInt32"), SerializeField] |
|||
ExposedProperty _splatCountProperty = "SplatCount"; |
|||
|
|||
[VFXPropertyBinding("UnityEngine.GraphicsBuffer"), SerializeField] |
|||
ExposedProperty _positionBufferProperty = "PositionBuffer"; |
|||
|
|||
[VFXPropertyBinding("UnityEngine.GraphicsBuffer"), SerializeField] |
|||
ExposedProperty _axisBufferProperty = "AxisBuffer"; |
|||
|
|||
[VFXPropertyBinding("UnityEngine.GraphicsBuffer"), SerializeField] |
|||
ExposedProperty _colorBufferProperty = "ColorBuffer"; |
|||
|
|||
public override bool IsValid(VisualEffect component) |
|||
=> SplatData != null && |
|||
component.HasUInt(_splatCountProperty) && |
|||
component.HasGraphicsBuffer(_positionBufferProperty) && |
|||
component.HasGraphicsBuffer(_axisBufferProperty) && |
|||
component.HasGraphicsBuffer(_colorBufferProperty); |
|||
|
|||
public override void UpdateBinding(VisualEffect component) |
|||
{ |
|||
component.SetUInt(_splatCountProperty, (uint)SplatData.SplatCount); |
|||
component.SetGraphicsBuffer(_positionBufferProperty, SplatData.PositionBuffer); |
|||
component.SetGraphicsBuffer(_axisBufferProperty, SplatData.AxisBuffer); |
|||
component.SetGraphicsBuffer(_colorBufferProperty, SplatData.ColorBuffer); |
|||
} |
|||
|
|||
public override string ToString() |
|||
=> $"Splat Data : {_splatCountProperty}, {_positionBufferProperty}, " |
|||
+ $"{_axisBufferProperty}, {_colorBufferProperty}"; |
|||
} |
|||
|
|||
} // namespace SplatVfx
|
@ -0,0 +1,11 @@ |
|||
fileFormatVersion: 2 |
|||
guid: 6b23e4c8461b80e458b0acda332b8a17 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
@ -0,0 +1,16 @@ |
|||
{ |
|||
"name": "SplatVfx.Runtime", |
|||
"rootNamespace": "", |
|||
"references": [ |
|||
"GUID:d04eb9c554ad44ceab303cecf0c0cf82" |
|||
], |
|||
"includePlatforms": [], |
|||
"excludePlatforms": [], |
|||
"allowUnsafeCode": true, |
|||
"overrideReferences": false, |
|||
"precompiledReferences": [], |
|||
"autoReferenced": true, |
|||
"defineConstraints": [], |
|||
"versionDefines": [], |
|||
"noEngineReferences": false |
|||
} |
@ -0,0 +1,7 @@ |
|||
fileFormatVersion: 2 |
|||
guid: 57d6a1ae39d606347b1307f1eadefe70 |
|||
AssemblyDefinitionImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
@ -0,0 +1,8 @@ |
|||
fileFormatVersion: 2 |
|||
guid: 2d7f462a7494efc41a164e16799dd783 |
|||
folderAsset: yes |
|||
DefaultImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
File diff suppressed because it is too large
@ -0,0 +1,10 @@ |
|||
fileFormatVersion: 2 |
|||
guid: ba6fab3c458b65948b6b54b560dc6ad8 |
|||
ScriptedImporter: |
|||
internalIDToNameTable: [] |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|||
script: {fileID: 11500000, guid: 625f186215c104763be7675aa2d941aa, type: 3} |
@ -0,0 +1,8 @@ |
|||
fileFormatVersion: 2 |
|||
guid: 71a7613a0b9d0914fa79a1406446691c |
|||
folderAsset: yes |
|||
DefaultImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
File diff suppressed because it is too large
@ -0,0 +1,7 @@ |
|||
fileFormatVersion: 2 |
|||
guid: 6ec2bd8fee604ee489e49fadaef11fe2 |
|||
VisualEffectImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
File diff suppressed because it is too large
@ -0,0 +1,7 @@ |
|||
fileFormatVersion: 2 |
|||
guid: 4ce91597b36c2104481cf644dd8f0cd0 |
|||
VisualEffectImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
File diff suppressed because it is too large
@ -0,0 +1,7 @@ |
|||
fileFormatVersion: 2 |
|||
guid: 98ff151d5676464419f3e5d8ec5ecb8b |
|||
VisualEffectImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
File diff suppressed because it is too large
@ -0,0 +1,7 @@ |
|||
fileFormatVersion: 2 |
|||
guid: fd4bd13ed1bfa804c90718dfbc02d3e8 |
|||
VisualEffectImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
File diff suppressed because it is too large
@ -0,0 +1,7 @@ |
|||
fileFormatVersion: 2 |
|||
guid: fd065fccc077e0e4aa25fcd2a1a8bf29 |
|||
VisualEffectImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
File diff suppressed because it is too large
@ -0,0 +1,7 @@ |
|||
fileFormatVersion: 2 |
|||
guid: 8ada6dcd9d799a5448dee04183f48fd2 |
|||
VisualEffectImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
File diff suppressed because it is too large
@ -0,0 +1,7 @@ |
|||
fileFormatVersion: 2 |
|||
guid: 687c12d75f307d746ba048bc8df6c99a |
|||
VisualEffectImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
File diff suppressed because it is too large
@ -0,0 +1,7 @@ |
|||
fileFormatVersion: 2 |
|||
guid: c2390383b28322c469644e7f7e01ebb0 |
|||
VisualEffectImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
@ -0,0 +1,13 @@ |
|||
{ |
|||
"author": "Keijiro Takahashi", |
|||
"dependencies": {}, |
|||
"description": "3D Gaussian Splatting support for VFX Graph", |
|||
"displayName": "Splat VFX", |
|||
"keywords": [ "unity" ], |
|||
"license": "Unlicense", |
|||
"name": "jp.keijiro.splat-vfx", |
|||
"repository": "github:keijiro/SplatVFX", |
|||
"unity": "2023.1", |
|||
"unityRelease": "0f1", |
|||
"version": "0.0.1" |
|||
} |
@ -0,0 +1,7 @@ |
|||
fileFormatVersion: 2 |
|||
guid: f7fb3e96e44041f41a351d435ccb5d50 |
|||
PackageManifestImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
Loading…
Reference in new issue