2323#include < pxr/usd/usdGeom/camera.h>
2424#include < pxr/usd/usdGeom/mesh.h>
2525#include < pxr/usd/usdGeom/metrics.h>
26+ #include < pxr/usd/usdGeom/pointInstancer.h>
2627#include < pxr/usd/usdGeom/primvarsAPI.h>
2728#include < pxr/usd/usdGeom/scope.h>
29+ #include < pxr/usd/usdGeom/sphere.h>
2830#include < pxr/usd/usdGeom/xform.h>
2931#include < pxr/base/gf/camera.h>
3032#include < pxr/usd/usdLux/shapingAPI.h>
@@ -787,6 +789,7 @@ namespace guc
787789 // TODO: proper material handling
788790 const cgltf_material* material = primitiveData->material ;
789791
792+ // TODO: how to actually handle indices in a point cloud?
790793 // Indices
791794 VtIntArray indices;
792795 {
@@ -801,14 +804,14 @@ namespace guc
801804 }
802805 }
803806
804- // Points
807+ // Points (& fallback indices)
805808 VtVec3fArray points;
806809 {
807810 const cgltf_accessor* accessor = cgltf_find_accessor (primitiveData, " POSITION" );
808811
809812 if (!detail::readVtArrayFromAccessor (accessor, points) || accessor->count == 0 )
810813 {
811- TF_RUNTIME_ERROR (" invalid POSITION accessor" );
814+ TF_RUNTIME_ERROR (" invalid %s accessor" , accessor-> name );
812815 return false ;
813816 }
814817
@@ -826,19 +829,19 @@ namespace guc
826829 VtVec3fArray colors;
827830 VtFloatArray opacities;
828831 {
829- const cgltf_accessor* accessor = cgltf_find_accessor (primitiveData, " COLOR0 " );
832+ const cgltf_accessor* accessor = cgltf_find_accessor (primitiveData, " COLOR_0 " );
830833
831- if (accessor-> type != cgltf_type_vec4)
832- {
833- // TODO: spec reads 'should' so missing alpha is valid
834- TF_RUNTIME_ERROR ( " gsplat primitive has invalid COLOR0 accessor " );
835- return false ;
836- }
834+ // TODO: the spec does not make it clear if we can expect a vec3 or vec4
835+ // TODO: for now this is debug code.
836+ # if 1
837+ assert (accessor-> type == cgltf_type_vec4 );
838+
839+ colors. resize (accessor-> count , GfVec3f ( 1 . 0f , 0 . 0f , 0 . 0f ));
837840
838841 VtVec4fArray rgbaColors;
839842 if (!detail::readVtArrayFromAccessor (accessor, rgbaColors))
840843 {
841- TF_RUNTIME_ERROR (" can't read gsplat COLOR0 attribute" );
844+ TF_RUNTIME_ERROR (" can't read %s attribute; ignoring " , accessor-> name );
842845 return false ;
843846 }
844847
@@ -850,34 +853,67 @@ namespace guc
850853 colors[k] = GfVec3f (rgbaColors[k].data ());
851854 }
852855
853- // Optimization: if material is opaque, we don't read the opacities anyway
854- if (material-> alpha_mode != cgltf_alpha_mode_opaque )
856+ opacities. resize (rgbaColorCount);
857+ for ( size_t k = 0 ; k < rgbaColorCount; k++ )
855858 {
856- opacities.resize (rgbaColorCount);
857- for (size_t k = 0 ; k < rgbaColorCount; k++)
858- {
859- opacities[k] = rgbaColors[k][3 ];
860- }
859+ opacities[k] = rgbaColors[k][3 ];
860+ }
861+ #else
862+ // TODO: I think we need to add our own validation function proxy
863+ assert(accessor->type == cgltf_type_vec3); // TODO: only for debugging, should be part of cgltf validation
864+
865+ if (!detail::readVtArrayFromAccessor(accessor, colors))
866+ {
867+ TF_RUNTIME_ERROR("can't read gsplat %s attribute", accessor->name);
868+ return false;
861869 }
870+ #endif
862871 }
863872
864- // Gsplat rotation, scale
865- VtVec4fArray rotations;
866- VtVec3fArray scales ;
873+ // Opacities
874+ # if 0
875+ VtFloatArray opacities ;
867876 {
868- const cgltf_accessor* rotationAccessor = cgltf_find_accessor (primitiveData, " KHR_gaussian_splatting:ROTATION " );
877+ const cgltf_accessor* accessor = cgltf_find_accessor(primitiveData, "KHR_gaussian_splatting:OPACITY ");
869878
870- if (!detail::readVtArrayFromAccessor (rotationAccessor, rotations ))
879+ if (!accessor || ! detail::readVtArrayFromAccessor(accessor, opacities ))
871880 {
872- TF_RUNTIME_ERROR (" can't read gsplat ROTATION accessor " );
881+ TF_RUNTIME_ERROR("can't read gsplat %s attribute", accessor->name );
873882 return false;
874883 }
884+ }
885+ #endif
875886
876- const cgltf_accessor* scaleAccessor = cgltf_find_accessor (primitiveData, " KHR_gaussian_splatting:SCALE" );
887+ // Rotations
888+ // TODO: try out if we just can keep the type vec4f
889+ VtQuatfArray rotations;
890+ {
891+ const cgltf_accessor* accessor = cgltf_find_accessor (primitiveData, " KHR_gaussian_splatting:ROTATION" );
877892
878- if (!detail::readVtArrayFromAccessor (scaleAccessor, scales))
893+ VtVec4fArray vec4Rots;
894+ if (!detail::readVtArrayFromAccessor (accessor, vec4Rots))
879895 {
880- TF_RUNTIME_ERROR (" can't read gsplat SCALE accessor" );
896+ TF_RUNTIME_ERROR (" can't read gsplat %s attribute" , accessor->name );
897+ return false ;
898+ }
899+
900+ size_t rotCount = vec4Rots.size ();
901+
902+ rotations.resize (rotCount);
903+ for (size_t i = 0 ; i < rotCount; i++)
904+ {
905+ rotations[i] = GfQuatf (vec4Rots[i][3 ], vec4Rots[i][0 ], vec4Rots[i][1 ], vec4Rots[i][2 ]);
906+ }
907+ }
908+
909+ // Scales
910+ VtVec3fArray scales;
911+ {
912+ const cgltf_accessor* accessor = cgltf_find_accessor (primitiveData, " KHR_gaussian_splatting:SCALE" );
913+
914+ if (!detail::readVtArrayFromAccessor (accessor, scales))
915+ {
916+ TF_RUNTIME_ERROR (" can't read gsplat %s attribute" , accessor->name );
881917 return false ;
882918 }
883919 }
@@ -916,15 +952,65 @@ namespace guc
916952 }
917953 }
918954
955+ // Create point instancer
956+ auto pointInstancer = UsdGeomPointInstancer::Define (m_stage, path);
919957
920- // TODO: now, we need to create a splat mesh (ellipsoid, triangle, quad)
921- // TODO: inside an instancer
958+ VtIntArray proto0Indices (indices.size (), 0 );
959+ pointInstancer.CreateProtoIndicesAttr (VtValue (proto0Indices));
960+ pointInstancer.CreatePositionsAttr (VtValue (points));
961+ pointInstancer.CreateOrientationsfAttr (VtValue (rotations));
962+ pointInstancer.CreateScalesAttr (VtValue (scales));
922963
964+ auto primvarsApi = UsdGeomPrimvarsAPI (pointInstancer);
965+ if (!colors.empty ())
966+ {
967+ primvarsApi.CreatePrimvar (TfToken (" displayColor" ), SdfValueTypeNames->Vector3fArray , UsdGeomTokens->varying ).Set (colors);
968+ primvarsApi.CreatePrimvar (TfToken (" color" ), SdfValueTypeNames->Vector3fArray , UsdGeomTokens->varying ).Set (colors);
969+ }
970+ if (!opacities.empty ())
971+ {
972+ primvarsApi.CreatePrimvar (TfToken (" displayOpacity" ), SdfValueTypeNames->FloatArray , UsdGeomTokens->varying ).Set (opacities);
973+ primvarsApi.CreatePrimvar (TfToken (" opacity" ), SdfValueTypeNames->FloatArray , UsdGeomTokens->varying ).Set (opacities);
974+ }
975+ size_t shCount = 0 ;
976+ for (auto & deg : shCoeffs)
977+ for (auto & values : deg)
978+ {
979+ auto name = TfToken (" sh_coeff" + std::to_string (shCount++));
980+ primvarsApi.CreatePrimvar (name, SdfValueTypeNames->FloatArray , UsdGeomTokens->varying ).Set (values);
981+ }
982+
983+ // Create prototype mesh
984+ auto protoPath = makeUniqueStageSubpath (m_stage, path, " ProtoGeom" );
985+ #if 1
986+ UsdGeomSphere protoGeom = UsdGeomSphere::Define (m_stage, protoPath);
987+ #else
988+ UsdGeomMesh protoGeom = UsdGeomMesh::Define(m_stage, protoPath);
989+
990+ VtVec3fArray trianglePoints = {
991+ GfVec3f(0.0f, 0.0f, 0.0f),
992+ GfVec3f(0.01f, 0.0f, 0.0f),
993+ GfVec3f(0.005f, 0.00866f, 0.0f)
994+ };
995+ protoGeom.CreatePointsAttr(VtValue(trianglePoints));
923996
997+ VtIntArray faceVertexCounts = { 3 };
998+ protoGeom.CreateFaceVertexCountsAttr(VtValue(faceVertexCounts));
924999
925- // TODO: we should also provide displayColors
1000+ VtIntArray faceVertexIndices = { 0, 1, 2 };
1001+ protoGeom.CreateFaceVertexIndicesAttr(VtValue(faceVertexIndices));
9261002
927- // TODO: return something
1003+ protoGeom.CreateSubdivisionSchemeAttr(VtValue(UsdGeomTokens->none));
1004+ #endif
1005+
1006+ auto instancerProtoRel = pointInstancer.CreatePrototypesRel ();
1007+ SdfPathVector protoPaths = { protoPath };
1008+ instancerProtoRel.SetTargets (protoPaths);
1009+
1010+ // TODO: assign GS material based on degree count
1011+
1012+ prim = pointInstancer.GetPrim ();
1013+ return true ;
9281014 }
9291015
9301016 bool Converter::createMeshPrimitive (const cgltf_primitive* primitiveData, SdfPath path, UsdPrim& prim)
0 commit comments