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 int SplatCount => PositionArray.Length;
|
||||||
public GraphicsBuffer PositionBuffer => GetCachedBuffers().position;
|
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 ColorBuffer => GetCachedBuffers().color;
|
||||||
|
public GraphicsBuffer OpacityBuffer => GetCachedBuffers().opacity;
|
||||||
|
public GraphicsBuffer SHBuffer => GetCachedBuffers().sh;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Serialized data
|
#region Serialized data
|
||||||
|
|
||||||
[field:SerializeField] public Vector3[] PositionArray { get; set; }
|
[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 Color[] ColorArray { get; set; }
|
||||||
|
[field:SerializeField] public float[] OpacityArray { get; set; }
|
||||||
|
[field:SerializeField] public float[][] SHArray { get; set; }
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@@ -28,32 +34,43 @@ public sealed class SplatData : ScriptableObject
|
|||||||
public void ReleaseGpuResources()
|
public void ReleaseGpuResources()
|
||||||
{
|
{
|
||||||
_cachedBuffers.position?.Release();
|
_cachedBuffers.position?.Release();
|
||||||
_cachedBuffers.axis?.Release();
|
_cachedBuffers.scale?.Release();
|
||||||
|
_cachedBuffers.rotation?.Release();
|
||||||
_cachedBuffers.color?.Release();
|
_cachedBuffers.color?.Release();
|
||||||
_cachedBuffers = (null, null, null);
|
_cachedBuffers.opacity?.Release();
|
||||||
|
_cachedBuffers = (null, null, null, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region GPU resource management
|
#region GPU resource management
|
||||||
|
|
||||||
(GraphicsBuffer position, GraphicsBuffer axis, GraphicsBuffer color)
|
(GraphicsBuffer position, GraphicsBuffer scale, GraphicsBuffer rotation,
|
||||||
|
GraphicsBuffer color, GraphicsBuffer opacity, GraphicsBuffer sh)
|
||||||
_cachedBuffers;
|
_cachedBuffers;
|
||||||
|
|
||||||
static unsafe GraphicsBuffer NewBuffer<T>(int count) where T : unmanaged
|
static unsafe GraphicsBuffer NewBuffer<T>(int count) where T : unmanaged
|
||||||
=> new GraphicsBuffer(GraphicsBuffer.Target.Structured, count, sizeof(T));
|
=> 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()
|
GetCachedBuffers()
|
||||||
{
|
{
|
||||||
if (_cachedBuffers.position == null)
|
if (_cachedBuffers.position == null)
|
||||||
{
|
{
|
||||||
_cachedBuffers.position = NewBuffer<Vector3>(SplatCount);
|
_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.color = NewBuffer<Color>(SplatCount);
|
||||||
|
_cachedBuffers.opacity = NewBuffer<float>(SplatCount);
|
||||||
|
_cachedBuffers.sh = NewBuffer<float>(SplatCount * 45);
|
||||||
|
|
||||||
_cachedBuffers.position.SetData(PositionArray);
|
_cachedBuffers.position.SetData(PositionArray);
|
||||||
_cachedBuffers.axis.SetData(AxisArray);
|
_cachedBuffers.scale.SetData(ScaleArray);
|
||||||
|
_cachedBuffers.rotation.SetData(RotationArray);
|
||||||
_cachedBuffers.color.SetData(ColorArray);
|
_cachedBuffers.color.SetData(ColorArray);
|
||||||
|
_cachedBuffers.opacity.SetData(OpacityArray);
|
||||||
|
_cachedBuffers.sh.SetData(SHArray);
|
||||||
}
|
}
|
||||||
return _cachedBuffers;
|
return _cachedBuffers;
|
||||||
}
|
}
|
||||||
@@ -67,4 +84,4 @@ public sealed class SplatData : ScriptableObject
|
|||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace SplatVfx
|
}
|
||||||
|
|||||||
@@ -9,112 +9,148 @@ using UnityEditor.Experimental;
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
using UnityEditor.Rendering.LookDev;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace SplatVfx.Editor {
|
namespace SplatVfx.Editor {
|
||||||
|
|
||||||
[ScriptedImporter(1, "splat"), BurstCompile]
|
[ScriptedImporter(1, "ply"), BurstCompile]
|
||||||
public sealed class SplatImporter : ScriptedImporter
|
public sealed class SplatImporter : ScriptedImporter
|
||||||
{
|
{
|
||||||
#region ScriptedImporter implementation
|
#region ScriptedImporter implementation
|
||||||
|
|
||||||
public override void OnImportAsset(AssetImportContext context)
|
public override void OnImportAsset(AssetImportContext context)
|
||||||
{
|
{
|
||||||
var data = ImportAsSplatData(context.assetPath);
|
_ = ParsePLYFile(context.assetPath);
|
||||||
var prefab = CreatePrefab(data);
|
// var data = ImportAsSplatData(context.assetPath);
|
||||||
context.AddObjectToAsset("prefab", prefab);
|
// var prefab = CreatePrefab(data);
|
||||||
context.AddObjectToAsset("data", data);
|
// context.AddObjectToAsset("prefab", prefab);
|
||||||
context.SetMainObject(prefab);
|
// context.AddObjectToAsset("data", data);
|
||||||
|
// context.SetMainObject(prefab);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Prefab construction
|
#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)
|
// GameObject CreatePrefab(SplatData data)
|
||||||
{
|
// {
|
||||||
var go = new GameObject();
|
// var go = new GameObject();
|
||||||
|
|
||||||
var vfx = go.AddComponent<VisualEffect>();
|
// var vfx = go.AddComponent<VisualEffect>();
|
||||||
vfx.visualEffectAsset = EditorResources.Load<VisualEffectAsset>(DefaultVfxPath);
|
// vfx.visualEffectAsset = EditorResources.Load<VisualEffectAsset>(DefaultVfxPath);
|
||||||
|
|
||||||
var binderBase = go.AddComponent<VFXPropertyBinder>();
|
// var binderBase = go.AddComponent<VFXPropertyBinder>();
|
||||||
var binder = binderBase.AddPropertyBinder<VFXSplatDataBinder>();
|
// var binder = binderBase.AddPropertyBinder<VFXSplatDataBinder>();
|
||||||
binder.SplatData = data;
|
// binder.SplatData = data;
|
||||||
|
|
||||||
return go;
|
// return go;
|
||||||
}
|
// }
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Reader implementation
|
#region Reader implementation
|
||||||
|
|
||||||
SplatData ImportAsSplatData(string path)
|
(string header, byte[] binaryData) ParsePLYFile(string filePath)
|
||||||
{
|
{
|
||||||
var data = ScriptableObject.CreateInstance<SplatData>();
|
using (var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
|
||||||
data.name = Path.GetFileNameWithoutExtension(path);
|
using (var reader = new StreamReader(fileStream))
|
||||||
|
{
|
||||||
|
StringBuilder headerBuilder = new StringBuilder();
|
||||||
|
string line;
|
||||||
|
|
||||||
var arrays = LoadDataArrays(path);
|
while ((line = reader.ReadLine()) != null)
|
||||||
data.PositionArray = arrays.position;
|
{
|
||||||
data.AxisArray = arrays.axis;
|
headerBuilder.AppendLine(line);
|
||||||
data.ColorArray = arrays.color;
|
if (line.Trim() == "end_header")
|
||||||
data.ReleaseGpuResources();
|
{
|
||||||
|
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
|
run down header, building list of data mappings
|
||||||
{
|
|
||||||
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
|
for element
|
||||||
|
for data mapping
|
||||||
|
write data
|
||||||
|
*/
|
||||||
|
|
||||||
(Vector3[] position, Vector3[] axis, Color[] color)
|
// SplatData ImportAsSplatData(string path)
|
||||||
LoadDataArrays(string path)
|
// {
|
||||||
{
|
// var data = ScriptableObject.CreateInstance<SplatData>();
|
||||||
var bytes = (Span<byte>)File.ReadAllBytes(path);
|
// data.name = Path.GetFileNameWithoutExtension(path);
|
||||||
var count = bytes.Length / 32;
|
|
||||||
|
|
||||||
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];
|
// return data;
|
||||||
var axis = new Vector3[count * 3];
|
// }
|
||||||
var color = new Color[count];
|
|
||||||
|
|
||||||
for (var i = 0; i < count; i++)
|
// struct ReadData
|
||||||
ParseReadData(source[i],
|
// {
|
||||||
out position[i],
|
// public float px, py, pz;
|
||||||
out axis[i * 3],
|
// public float sx, sy, sz;
|
||||||
out axis[i * 3 + 1],
|
// public byte r, g, b, a;
|
||||||
out axis[i * 3 + 2],
|
// public byte rw, rx, ry, rz;
|
||||||
out color[i]);
|
// }
|
||||||
|
|
||||||
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]
|
// var source = MemoryMarshal.Cast<byte, ReadData>(bytes);
|
||||||
void ParseReadData(in ReadData src,
|
|
||||||
out Vector3 position,
|
// var position = new Vector3[count];
|
||||||
out Vector3 axis1,
|
// var axis = new Vector3[count * 3];
|
||||||
out Vector3 axis2,
|
// var color = new Color[count];
|
||||||
out Vector3 axis3,
|
|
||||||
out Color color)
|
// for (var i = 0; i < count; i++)
|
||||||
{
|
// ParseReadData(source[i],
|
||||||
var rv = (math.float4(src.rx, src.ry, src.rz, src.rw) - 128) / 128;
|
// out position[i],
|
||||||
var q = math.quaternion(-rv.x, -rv.y, rv.z, rv.w);
|
// out axis[i * 3],
|
||||||
position = math.float3(src.px, src.py, -src.pz);
|
// out axis[i * 3 + 1],
|
||||||
axis1 = math.mul(q, math.float3(src.sx, 0, 0));
|
// out axis[i * 3 + 2],
|
||||||
axis2 = math.mul(q, math.float3(0, src.sy, 0));
|
// out color[i]);
|
||||||
axis3 = math.mul(q, math.float3(0, 0, src.sz));
|
|
||||||
color = (Vector4)math.float4(src.r, src.g, src.b, src.a) / 255;
|
// 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
|
#endregion
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user