11using System . Collections . Generic ;
22using System . Globalization ;
33using System . IO ;
4+ using System . Linq ;
45using GaussianSplatting . Runtime ;
56using Unity . Burst ;
67using Unity . Collections ;
78using Unity . Collections . LowLevel . Unsafe ;
89using Unity . Jobs ;
910using Unity . Mathematics ;
1011using UnityEngine ;
12+ using UnityEngine . Assertions ;
1113
1214namespace GaussianSplatting . Editor . Utils
1315{
14- // input file splat data is expected to be in this format
16+ // input file splat data is read into this format
1517 public struct InputSplatData
1618 {
1719 public Vector3 pos ;
@@ -44,16 +46,14 @@ public static unsafe void ReadFile(string filePath, out NativeArray<InputSplatDa
4446 {
4547 if ( isPLY ( filePath ) )
4648 {
47- NativeArray < byte > verticesRawData ;
48- PLYFileReader . ReadFile ( filePath , out var splatCount , out var splatStride , out List < string > _ , out verticesRawData ) ;
49- if ( UnsafeUtility . SizeOf < InputSplatData > ( ) != splatStride )
50- throw new IOException ( $ "PLY vertex size mismatch, expected { UnsafeUtility . SizeOf < InputSplatData > ( ) } but file has { splatStride } ") ;
51-
52- // reorder SHs
53- NativeArray < float > floatData = verticesRawData . Reinterpret < float > ( 1 ) ;
54- ReorderSHs ( splatCount , ( float * ) floatData . GetUnsafePtr ( ) ) ;
55-
56- splats = verticesRawData . Reinterpret < InputSplatData > ( 1 ) ;
49+ NativeArray < byte > plyRawData ;
50+ List < ( string , PLYFileReader . ElementType ) > attributes ;
51+ PLYFileReader . ReadFile ( filePath , out var splatCount , out var vertexStride , out attributes , out plyRawData ) ;
52+ string attrError = CheckPLYAttributes ( attributes ) ;
53+ if ( ! string . IsNullOrEmpty ( attrError ) )
54+ throw new IOException ( $ "PLY file is probably not a Gaussian Splat file? Missing properties: { attrError } ") ;
55+ splats = PLYDataToSplats ( plyRawData , splatCount , vertexStride , attributes ) ;
56+ ReorderSHs ( splatCount , ( float * ) splats . GetUnsafePtr ( ) ) ;
5757 LinearizeData ( splats ) ;
5858 return ;
5959 }
@@ -68,6 +68,120 @@ public static unsafe void ReadFile(string filePath, out NativeArray<InputSplatDa
6868 static bool isPLY ( string filePath ) => filePath . EndsWith ( ".ply" , true , CultureInfo . InvariantCulture ) ;
6969 static bool isSPZ ( string filePath ) => filePath . EndsWith ( ".spz" , true , CultureInfo . InvariantCulture ) ;
7070
71+ static string CheckPLYAttributes ( List < ( string , PLYFileReader . ElementType ) > attributes )
72+ {
73+ string [ ] required = { "x" , "y" , "z" , "f_dc_0" , "f_dc_1" , "f_dc_2" , "opacity" , "scale_0" , "scale_1" , "scale_2" , "rot_0" , "rot_1" , "rot_2" , "rot_3" } ;
74+ List < string > missing = required . Where ( req => ! attributes . Contains ( ( req , PLYFileReader . ElementType . Float ) ) ) . ToList ( ) ;
75+ if ( missing . Count == 0 )
76+ return null ;
77+ return string . Join ( "," , missing ) ;
78+ }
79+
80+ static unsafe NativeArray < InputSplatData > PLYDataToSplats ( NativeArray < byte > input , int count , int stride , List < ( string , PLYFileReader . ElementType ) > attributes )
81+ {
82+ NativeArray < int > fileAttrOffsets = new NativeArray < int > ( attributes . Count , Allocator . Temp ) ;
83+ int offset = 0 ;
84+ for ( var ai = 0 ; ai < attributes . Count ; ai ++ )
85+ {
86+ var attr = attributes [ ai ] ;
87+ fileAttrOffsets [ ai ] = offset ;
88+ offset += PLYFileReader . TypeToSize ( attr . Item2 ) ;
89+ }
90+
91+ string [ ] splatAttributes =
92+ {
93+ "x" ,
94+ "y" ,
95+ "z" ,
96+ "nx" ,
97+ "ny" ,
98+ "nz" ,
99+ "f_dc_0" ,
100+ "f_dc_1" ,
101+ "f_dc_2" ,
102+ "f_rest_0" ,
103+ "f_rest_1" ,
104+ "f_rest_2" ,
105+ "f_rest_3" ,
106+ "f_rest_4" ,
107+ "f_rest_5" ,
108+ "f_rest_6" ,
109+ "f_rest_7" ,
110+ "f_rest_8" ,
111+ "f_rest_9" ,
112+ "f_rest_10" ,
113+ "f_rest_11" ,
114+ "f_rest_12" ,
115+ "f_rest_13" ,
116+ "f_rest_14" ,
117+ "f_rest_15" ,
118+ "f_rest_16" ,
119+ "f_rest_17" ,
120+ "f_rest_18" ,
121+ "f_rest_19" ,
122+ "f_rest_20" ,
123+ "f_rest_21" ,
124+ "f_rest_22" ,
125+ "f_rest_23" ,
126+ "f_rest_24" ,
127+ "f_rest_25" ,
128+ "f_rest_26" ,
129+ "f_rest_27" ,
130+ "f_rest_28" ,
131+ "f_rest_29" ,
132+ "f_rest_30" ,
133+ "f_rest_31" ,
134+ "f_rest_32" ,
135+ "f_rest_33" ,
136+ "f_rest_34" ,
137+ "f_rest_35" ,
138+ "f_rest_36" ,
139+ "f_rest_37" ,
140+ "f_rest_38" ,
141+ "f_rest_39" ,
142+ "f_rest_40" ,
143+ "f_rest_41" ,
144+ "f_rest_42" ,
145+ "f_rest_43" ,
146+ "f_rest_44" ,
147+ "opacity" ,
148+ "scale_0" ,
149+ "scale_1" ,
150+ "scale_2" ,
151+ "rot_0" ,
152+ "rot_1" ,
153+ "rot_2" ,
154+ "rot_3" ,
155+ } ;
156+ Assert . AreEqual ( UnsafeUtility . SizeOf < InputSplatData > ( ) / 4 , splatAttributes . Length ) ;
157+ NativeArray < int > srcOffsets = new NativeArray < int > ( splatAttributes . Length , Allocator . Temp ) ;
158+ for ( int ai = 0 ; ai < splatAttributes . Length ; ai ++ )
159+ {
160+ int attrIndex = attributes . IndexOf ( ( splatAttributes [ ai ] , PLYFileReader . ElementType . Float ) ) ;
161+ int attrOffset = attrIndex >= 0 ? fileAttrOffsets [ attrIndex ] : - 1 ;
162+ srcOffsets [ ai ] = attrOffset ;
163+ }
164+
165+ NativeArray < InputSplatData > dst = new NativeArray < InputSplatData > ( count , Allocator . Persistent ) ;
166+ ReorderPLYData ( count , ( byte * ) input . GetUnsafeReadOnlyPtr ( ) , stride , ( byte * ) dst . GetUnsafePtr ( ) , UnsafeUtility . SizeOf < InputSplatData > ( ) , ( int * ) srcOffsets . GetUnsafeReadOnlyPtr ( ) ) ;
167+ return dst ;
168+ }
169+
170+ [ BurstCompile ]
171+ static unsafe void ReorderPLYData ( int splatCount , byte * src , int srcStride , byte * dst , int dstStride , int * srcOffsets )
172+ {
173+ for ( int i = 0 ; i < splatCount ; i ++ )
174+ {
175+ for ( int attr = 0 ; attr < dstStride / 4 ; attr ++ )
176+ {
177+ if ( srcOffsets [ attr ] >= 0 )
178+ * ( int * ) ( dst + attr * 4 ) = * ( int * ) ( src + srcOffsets [ attr ] ) ;
179+ }
180+ src += srcStride ;
181+ dst += dstStride ;
182+ }
183+ }
184+
71185 [ BurstCompile ]
72186 static unsafe void ReorderSHs ( int splatCount , float * data )
73187 {
0 commit comments