Implement data structures and initial parser
This commit is contained in:
@@ -10,16 +10,22 @@ public sealed class SplatData : ScriptableObject
|
||||
|
||||
public int SplatCount => PositionArray.Length;
|
||||
public GraphicsBuffer PositionBuffer => GetCachedBuffers().position;
|
||||
public GraphicsBuffer AxisBuffer => GetCachedBuffers().axis;
|
||||
public GraphicsBuffer ScaleBuffer => GetCachedBuffers().scale;
|
||||
public GraphicsBuffer RotationBuffer => GetCachedBuffers().rotation;
|
||||
public GraphicsBuffer ColorBuffer => GetCachedBuffers().color;
|
||||
public GraphicsBuffer OpacityBuffer => GetCachedBuffers().opacity;
|
||||
public GraphicsBuffer SHBuffer => GetCachedBuffers().sh;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Serialized data
|
||||
|
||||
[field:SerializeField] public Vector3[] PositionArray { get; set; }
|
||||
[field:SerializeField] public Vector3[] AxisArray { get; set; }
|
||||
[field:SerializeField] public Vector3[] ScaleArray { get; set; }
|
||||
[field:SerializeField] public Quaternion[] RotationArray { get; set; }
|
||||
[field:SerializeField] public Color[] ColorArray { get; set; }
|
||||
[field:SerializeField] public float[] OpacityArray { get; set; }
|
||||
[field:SerializeField] public float[][] SHArray { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -28,32 +34,43 @@ public sealed class SplatData : ScriptableObject
|
||||
public void ReleaseGpuResources()
|
||||
{
|
||||
_cachedBuffers.position?.Release();
|
||||
_cachedBuffers.axis?.Release();
|
||||
_cachedBuffers.scale?.Release();
|
||||
_cachedBuffers.rotation?.Release();
|
||||
_cachedBuffers.color?.Release();
|
||||
_cachedBuffers = (null, null, null);
|
||||
_cachedBuffers.opacity?.Release();
|
||||
_cachedBuffers = (null, null, null, null, null, null);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GPU resource management
|
||||
|
||||
(GraphicsBuffer position, GraphicsBuffer axis, GraphicsBuffer color)
|
||||
(GraphicsBuffer position, GraphicsBuffer scale, GraphicsBuffer rotation,
|
||||
GraphicsBuffer color, GraphicsBuffer opacity, GraphicsBuffer sh)
|
||||
_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)
|
||||
(GraphicsBuffer position, GraphicsBuffer scale, GraphicsBuffer rotation,
|
||||
GraphicsBuffer color, GraphicsBuffer opacity, GraphicsBuffer sh)
|
||||
GetCachedBuffers()
|
||||
{
|
||||
if (_cachedBuffers.position == null)
|
||||
{
|
||||
_cachedBuffers.position = NewBuffer<Vector3>(SplatCount);
|
||||
_cachedBuffers.axis = NewBuffer<Vector3>(SplatCount * 3);
|
||||
_cachedBuffers.scale = NewBuffer<Vector3>(SplatCount);
|
||||
_cachedBuffers.rotation = NewBuffer<Quaternion>(SplatCount);
|
||||
_cachedBuffers.color = NewBuffer<Color>(SplatCount);
|
||||
_cachedBuffers.opacity = NewBuffer<float>(SplatCount);
|
||||
_cachedBuffers.sh = NewBuffer<float>(SplatCount * 45);
|
||||
|
||||
_cachedBuffers.position.SetData(PositionArray);
|
||||
_cachedBuffers.axis.SetData(AxisArray);
|
||||
_cachedBuffers.scale.SetData(ScaleArray);
|
||||
_cachedBuffers.rotation.SetData(RotationArray);
|
||||
_cachedBuffers.color.SetData(ColorArray);
|
||||
_cachedBuffers.opacity.SetData(OpacityArray);
|
||||
_cachedBuffers.sh.SetData(SHArray);
|
||||
}
|
||||
return _cachedBuffers;
|
||||
}
|
||||
@@ -67,4 +84,4 @@ public sealed class SplatData : ScriptableObject
|
||||
#endregion
|
||||
}
|
||||
|
||||
} // namespace SplatVfx
|
||||
}
|
||||
|
||||
@@ -9,112 +9,148 @@ using UnityEditor.Experimental;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using UnityEditor.Rendering.LookDev;
|
||||
using System.Linq;
|
||||
|
||||
namespace SplatVfx.Editor {
|
||||
|
||||
[ScriptedImporter(1, "splat"), BurstCompile]
|
||||
[ScriptedImporter(1, "ply"), 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);
|
||||
_ = ParsePLYFile(context.assetPath);
|
||||
// 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";
|
||||
// const string DefaultVfxPath = "Packages/jp.keijiro.splat-vfx/VFX/Splat.vfx";
|
||||
|
||||
GameObject CreatePrefab(SplatData data)
|
||||
{
|
||||
var go = new GameObject();
|
||||
// GameObject CreatePrefab(SplatData data)
|
||||
// {
|
||||
// var go = new GameObject();
|
||||
|
||||
var vfx = go.AddComponent<VisualEffect>();
|
||||
vfx.visualEffectAsset = EditorResources.Load<VisualEffectAsset>(DefaultVfxPath);
|
||||
// var vfx = go.AddComponent<VisualEffect>();
|
||||
// vfx.visualEffectAsset = EditorResources.Load<VisualEffectAsset>(DefaultVfxPath);
|
||||
|
||||
var binderBase = go.AddComponent<VFXPropertyBinder>();
|
||||
var binder = binderBase.AddPropertyBinder<VFXSplatDataBinder>();
|
||||
binder.SplatData = data;
|
||||
// var binderBase = go.AddComponent<VFXPropertyBinder>();
|
||||
// var binder = binderBase.AddPropertyBinder<VFXSplatDataBinder>();
|
||||
// binder.SplatData = data;
|
||||
|
||||
return go;
|
||||
}
|
||||
// return go;
|
||||
// }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Reader implementation
|
||||
|
||||
SplatData ImportAsSplatData(string path)
|
||||
(string header, byte[] binaryData) ParsePLYFile(string filePath)
|
||||
{
|
||||
var data = ScriptableObject.CreateInstance<SplatData>();
|
||||
data.name = Path.GetFileNameWithoutExtension(path);
|
||||
using (var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
|
||||
using (var reader = new StreamReader(fileStream))
|
||||
{
|
||||
StringBuilder headerBuilder = new StringBuilder();
|
||||
string line;
|
||||
|
||||
var arrays = LoadDataArrays(path);
|
||||
data.PositionArray = arrays.position;
|
||||
data.AxisArray = arrays.axis;
|
||||
data.ColorArray = arrays.color;
|
||||
data.ReleaseGpuResources();
|
||||
while ((line = reader.ReadLine()) != null)
|
||||
{
|
||||
headerBuilder.AppendLine(line);
|
||||
if (line.Trim() == "end_header")
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
long endHeaderPosition = headerBuilder.Length - headerBuilder.ToString().Split('\n').Length + 1;
|
||||
fileStream.Seek(endHeaderPosition, SeekOrigin.Begin);
|
||||
|
||||
byte[] binaryData = new byte[fileStream.Length - endHeaderPosition];
|
||||
|
||||
return (headerBuilder.ToString(), binaryData);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning disable CS0649
|
||||
/*
|
||||
get number of elements
|
||||
|
||||
struct ReadData
|
||||
{
|
||||
public float px, py, pz;
|
||||
public float sx, sy, sz;
|
||||
public byte r, g, b, a;
|
||||
public byte rw, rx, ry, rz;
|
||||
}
|
||||
run down header, building list of data mappings
|
||||
|
||||
#pragma warning restore CS0649
|
||||
for element
|
||||
for data mapping
|
||||
write data
|
||||
*/
|
||||
|
||||
(Vector3[] position, Vector3[] axis, Color[] color)
|
||||
LoadDataArrays(string path)
|
||||
{
|
||||
var bytes = (Span<byte>)File.ReadAllBytes(path);
|
||||
var count = bytes.Length / 32;
|
||||
// SplatData ImportAsSplatData(string path)
|
||||
// {
|
||||
// var data = ScriptableObject.CreateInstance<SplatData>();
|
||||
// data.name = Path.GetFileNameWithoutExtension(path);
|
||||
|
||||
var source = MemoryMarshal.Cast<byte, ReadData>(bytes);
|
||||
// var arrays = LoadDataArrays(path);
|
||||
// data.PositionArray = arrays.position;
|
||||
// data.AxisArray = arrays.axis;
|
||||
// data.ColorArray = arrays.color;
|
||||
// data.ReleaseGpuResources();
|
||||
|
||||
var position = new Vector3[count];
|
||||
var axis = new Vector3[count * 3];
|
||||
var color = new Color[count];
|
||||
// return data;
|
||||
// }
|
||||
|
||||
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]);
|
||||
// struct ReadData
|
||||
// {
|
||||
// public float px, py, pz;
|
||||
// public float sx, sy, sz;
|
||||
// public byte r, g, b, a;
|
||||
// public byte rw, rx, ry, rz;
|
||||
// }
|
||||
|
||||
return (position, axis, color);
|
||||
}
|
||||
// (Vector3[] position, Vector3[] axis, Color[] color)
|
||||
// LoadDataArrays(string path)
|
||||
// {
|
||||
// var bytes = (Span<byte>)File.ReadAllBytes(path);
|
||||
// var count = bytes.Length / 32;
|
||||
|
||||
[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;
|
||||
}
|
||||
// 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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user