diff --git a/Runtime/ConfigureReinterop.cs b/Runtime/ConfigureReinterop.cs index f0b923ac..cc1e8c76 100644 --- a/Runtime/ConfigureReinterop.cs +++ b/Runtime/ConfigureReinterop.cs @@ -64,6 +64,12 @@ public void ExposeToCPP() Vector4 v = new Vector4(1.0f, 0.0f, 1.0f, 0.0f); + MaterialPropertyBlock propertyBlock = new MaterialPropertyBlock(); + propertyBlock.SetVectorArray(0, new Vector4[0]); + propertyBlock.SetVectorArray(0, new List()); + propertyBlock.SetVectorArray("name", new Vector4[0]); + propertyBlock.SetVectorArray("name", new List()); + t.position = new Vector3(); Vector3 p = t.position; float x = p.x; @@ -131,6 +137,9 @@ public void ExposeToCPP() Mesh mesh = new Mesh(); Mesh[] meshes = new[] { mesh }; + + Matrix4x4[] mats = new[] { m2 }; + mesh = meshes[0]; int meshesLength = meshes.Length; mesh.SetVertices(new NativeArray()); @@ -138,12 +147,16 @@ public void ExposeToCPP() mesh.SetUVs(0, new NativeArray()); mesh.SetIndices(new NativeArray(), MeshTopology.Triangles, 0, true, 0); mesh.RecalculateBounds(); + mesh.indexFormat = IndexFormat.UInt32; int vertexCount = mesh.vertexCount; int instanceID = mesh.GetInstanceID(); Vector3[] vertices = mesh.vertices; Vector3 vertex = vertices[0]; + int[] triangles = mesh.triangles; + int triangle = triangles[0]; + Bounds bounds = new Bounds(new Vector3(0, 0, 0), new Vector3(1, 2, 1)); MeshCollider meshCollider = go.AddComponent(); @@ -177,6 +190,7 @@ public void ExposeToCPP() meshRenderer.material.shaderKeywords = meshRenderer.material.shaderKeywords; meshRenderer.sharedMaterial = meshRenderer.sharedMaterial; meshRenderer.material.shader = meshRenderer.material.shader; + meshRenderer.material.enableInstancing = true; UnityEngine.Object.Destroy(meshGameObject); UnityEngine.Object.DestroyImmediate(meshGameObject, true); UnityEngine.Object.DestroyImmediate(meshGameObject); @@ -508,6 +522,16 @@ public void ExposeToCPP() stringList.Clear(); count = stringList.Count; + List matList = new List(); + matList.Add(m2); + matList.Clear(); + count = matList.Count; + + List double4x4List = new List(); + double4x4List.Add(ecefToLocal); + double4x4List.Clear(); + count = double4x4List.Count; + string test = string.Concat("string", "string2"); string[] stringArray = stringList.ToArray(); test = stringArray[0]; @@ -540,6 +564,14 @@ Cesium3DTilesetLoadFailureDetails tilesetDetails double3 cv4 = new double3(1.0, 2.0, 3.0); double3x3 matrix3x3 = double3x3.identity; + go.GetComponent(); + I3dmInstanceRenderer[] i3dmRenderers = go.GetComponentsInChildren(); + i3dmRenderers = go.GetComponentsInChildren(true); + I3dmInstanceRenderer i3dmRenderer = i3dmRenderers[i3dmRenderers.Length - 1]; + i3dmRenderer = go.AddComponent(); + + i3dmRenderer.AddInstanceGroup("groupId",mesh,meshRenderer.material,double4x4List); + go.GetComponent(); CesiumGlobeAnchor[] globeAnchors = go.GetComponentsInChildren(); globeAnchors = go.GetComponentsInChildren(true); diff --git a/Runtime/I3dmInstanceRenderer.cs b/Runtime/I3dmInstanceRenderer.cs new file mode 100644 index 00000000..14556f66 --- /dev/null +++ b/Runtime/I3dmInstanceRenderer.cs @@ -0,0 +1,131 @@ +using UnityEngine; +using System.Collections.Generic; +using Unity.Mathematics; + +namespace CesiumForUnity +{ +public static class MatrixUtils +{ + public static Matrix4x4 Double4x4ToMatrix4x4(double4x4 m) + { + return new Matrix4x4( + new Vector4((float)m.c0.x, (float)m.c0.y, (float)m.c0.z, (float)m.c0.w), + new Vector4((float)m.c1.x, (float)m.c1.y, (float)m.c1.z, (float)m.c1.w), + new Vector4((float)m.c2.x, (float)m.c2.y, (float)m.c2.z, (float)m.c2.w), + new Vector4((float)m.c3.x, (float)m.c3.y, (float)m.c3.z, (float)m.c3.w) + ); + } + + public static Matrix4x4[] Double4x4ArrayToMatrix4x4Array(double4x4[] arr) + { + if (arr == null) return null; + Matrix4x4[] result = new Matrix4x4[arr.Length]; + for (int i = 0; i < arr.Length; i++) + { + result[i] = Double4x4ToMatrix4x4(arr[i]); + } + return result; + } +} +[ExecuteInEditMode] +public class I3dmInstanceRenderer : MonoBehaviour +{ + // Instance groups prepared in the C++ cesium-unity dll + private Dictionary instanceGroups = new Dictionary(); + + //private MaterialPropertyBlock propertyBlock = new MaterialPropertyBlock(); + + [System.Serializable] + public class InstanceGroupData + { + public Mesh mesh; + public Material material; + public Matrix4x4[] matrices; + public int maxInstancesPerBatch = 1023; + } + + void Update() + { + // Perform rendering for all instance groups + foreach (var kvp in instanceGroups) + { + var groupData = kvp.Value; + RenderInstanceGroup(groupData); + } + } + + void RenderInstanceGroup(InstanceGroupData groupData) + { + if (groupData.mesh == null || groupData.material == null || groupData.matrices == null) + return; + + int totalInstances = groupData.matrices.Length; + int maxBatchSize = groupData.maxInstancesPerBatch; + + // Rendering divided by batch + for (int batchStart = 0; batchStart < totalInstances; batchStart += maxBatchSize) + { + int batchSize = Mathf.Min(maxBatchSize, totalInstances - batchStart); + + // Extract the matrices of the current batch + Matrix4x4[] batchMatrices = new Matrix4x4[batchSize]; + + for(int i = 0; i < batchSize; i++) + { + batchMatrices[i] = transform.GetChild(i).localToWorldMatrix; + } + //System.Array.Copy(groupData.matrices, batchStart, batchMatrices, 0, batchSize); + + // Rendering with GPU Instancing + Graphics.DrawMeshInstanced( + groupData.mesh, + 0, + groupData.material, + batchMatrices, + batchSize + ); + } + } + + // called from C++ cesium-unity dll + public void AddInstanceGroup(string groupId, Mesh mesh, Material material, List matrices) + { + // MaterialPropertyBlock setting (for each instance) + MaterialPropertyBlock propertyBlock = new MaterialPropertyBlock(); + + // TODO: color setting and shader property setting + /* + std::vector colorVector; + colorVector.reserve(batchSize); + + for (size_t i = 0; i < batchSize; ++i) { + size_t sourceIndex = batchStart + i; + const glm::dvec4& glmColor = instanceGroup->colors[sourceIndex]; + + std::vector colorValues = { + glmColor.x, glmColor.y, glmColor.z, glmColor.w + }; + + colorVector.push_back(gltfVectorToUnityVector(colorValues, 1.0f)); + } + + // Set the color array as a shader property + propertyBlock.SetVectorArray( + UnityEngine::Shader::PropertyToID(System::String("_InstanceColors")), + colorArray); + */ + + instanceGroups[groupId] = new InstanceGroupData + { + mesh = mesh, + material = material, + matrices = MatrixUtils.Double4x4ArrayToMatrix4x4Array(matrices.ToArray()) + }; + } + + public void RemoveInstanceGroup(string groupId) + { + instanceGroups.Remove(groupId); + } +} +} diff --git a/Runtime/I3dmInstanceRenderer.cs.meta b/Runtime/I3dmInstanceRenderer.cs.meta new file mode 100644 index 00000000..5df051b8 --- /dev/null +++ b/Runtime/I3dmInstanceRenderer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8638331f35e70e642aec9126ed96e716 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/native~/Runtime/src/UnityPrepareRendererResources.cpp b/native~/Runtime/src/UnityPrepareRendererResources.cpp index dbeff78c..d3b6d3db 100644 --- a/native~/Runtime/src/UnityPrepareRendererResources.cpp +++ b/native~/Runtime/src/UnityPrepareRendererResources.cpp @@ -1,4 +1,4 @@ -#include "UnityPrepareRendererResources.h" +#include "UnityPrepareRendererResources.h" #include "CesiumFeaturesMetadataUtility.h" #include "TextureLoader.h" @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -26,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -137,6 +139,24 @@ struct MeshDataResult { std::vector primitiveInfos; }; +/** + * @brief Instance data structure for GPU Instancing + */ +struct InstanceData { + /** + * @brief transform matrix + */ + glm::dmat4 transform; // transform matrix + /** + * @brief for color of each instance (optional) + */ + glm::dvec4 color; + /** + * @brief batchId + */ + uint32_t batchId; +}; + template struct CopyVertexColors { uint8_t* pWritePos; size_t stride; @@ -1123,7 +1143,10 @@ void setGltfMaterialParameterValues( materialProperties.getMetallicRoughnessFactorID(), {(float)pbr.metallicFactor, (float)pbr.roughnessFactor, 0, 0}); + // Process baseColorTexture with fallback for legacy materials const std::optional& baseColorTexture = pbr.baseColorTexture; + bool textureSet = false; + if (baseColorTexture) { auto texCoordIndexIt = primitiveInfo.uvIndexMap.find(baseColorTexture->texCoord); @@ -1138,10 +1161,36 @@ void setGltfMaterialParameterValues( unityMaterial.SetFloat( materialProperties.getBaseColorTextureCoordinateIndexID(), static_cast(texCoordIndexIt->second)); + textureSet = true; } } } + // Fallback: If no standard PBR baseColorTexture, try to use first available + // texture Only apply fallback if this primitive actually has UV coordinates + if (!textureSet && !model.textures.empty() && + !primitiveInfo.uvIndexMap.empty()) { + + // Find first available UV channel + int32_t fallbackUvIndex = primitiveInfo.uvIndexMap.begin()->second; + + // Try to load first texture + UnityEngine::Texture fallbackTexture = + TextureLoader::loadTexture(model, 0, true); + if (fallbackTexture != nullptr) { + fallbackTexture.hideFlags( + DotNet::UnityEngine::HideFlags::HideAndDontSave); + unityMaterial.SetTexture( + materialProperties.getBaseColorTextureID(), + fallbackTexture); + unityMaterial.SetFloat( + materialProperties.getBaseColorTextureCoordinateIndexID(), + static_cast(fallbackUvIndex)); + textureSet = true; + + } + } + const std::optional& metallicRoughness = pbr.metallicRoughnessTexture; if (metallicRoughness) { @@ -1377,6 +1426,170 @@ void setGltfMaterialParameterValues( } } } +void ExtractInstanceDataFromExtMeshGpuInstancing( + const CesiumGltf::Model& gltf, + const CesiumGltf::Node& node, + const CesiumGltf::ExtensionExtMeshGpuInstancing& gpuExt, + const glm::dmat4& nodeTransform, + std::vector& outInstanceData) { + + // Get TRANSLATION property + auto translationIt = gpuExt.attributes.find("TRANSLATION"); + const CesiumGltf::Accessor* pTranslationAccessor = nullptr; + if (translationIt != gpuExt.attributes.end()) { + pTranslationAccessor = + CesiumGltf::Model::getSafe(&gltf.accessors, translationIt->second); + } + + // Get ROTATION property + auto rotationIt = gpuExt.attributes.find("ROTATION"); + const CesiumGltf::Accessor* pRotationAccessor = nullptr; + if (rotationIt != gpuExt.attributes.end()) { + pRotationAccessor = + CesiumGltf::Model::getSafe(&gltf.accessors, rotationIt->second); + } + + // Get SCALE property + auto scaleIt = gpuExt.attributes.find("SCALE"); + const CesiumGltf::Accessor* pScaleAccessor = nullptr; + if (scaleIt != gpuExt.attributes.end()) { + pScaleAccessor = + CesiumGltf::Model::getSafe(&gltf.accessors, scaleIt->second); + } + + // Determine the number of instances + int64_t instanceCount = 0; + if (pTranslationAccessor) { + instanceCount = pTranslationAccessor->count; + } else if (pRotationAccessor) { + instanceCount = pRotationAccessor->count; + } else if (pScaleAccessor) { + instanceCount = pScaleAccessor->count; + } + + if (instanceCount == 0) { + return; + } + + // Create AccessorView + CesiumGltf::AccessorView> + translationView; + if (pTranslationAccessor) { + translationView = + CesiumGltf::AccessorView>( + gltf, + *pTranslationAccessor); + } + + CesiumGltf::AccessorView> rotationView; + if (pRotationAccessor) { + rotationView = + CesiumGltf::AccessorView>( + gltf, + *pRotationAccessor); + } + + CesiumGltf::AccessorView> scaleView; + if (pScaleAccessor) { + scaleView = + CesiumGltf::AccessorView>( + gltf, + *pScaleAccessor); + } + + // Create InstanceData for each instance + for (int64_t i = 0; i < instanceCount; ++i) { + InstanceData instanceData; + + // Location settings + glm::dvec3 position(0.0); + if (translationView.status() == CesiumGltf::AccessorViewStatus::Valid && + i < translationView.size()) { + auto translation = translationView[i]; + position = glm::dvec3( + translation.value[0], + translation.value[1], + translation.value[2]); + } + + // Rotation settings (quaternion) + glm::dquat rotation(1.0, 0.0, 0.0, 0.0); // Unit quaternion + if (rotationView.status() == CesiumGltf::AccessorViewStatus::Valid && + i < rotationView.size()) { + auto rot = rotationView[i]; + rotation = glm::dquat( + rot.value[3], + rot.value[0], + rot.value[1], + rot.value[2]); // w, x, y, z + } + + // Set scale + glm::dvec3 scale(1.0); + if (scaleView.status() == CesiumGltf::AccessorViewStatus::Valid && + i < scaleView.size()) { + auto scaleVec = scaleView[i]; + scale = + glm::dvec3(-scaleVec.value[0], -scaleVec.value[1], -scaleVec.value[2]); + } + + // Construct the transformation matrix + glm::dmat4 instanceTransform = glm::dmat4(1.0); + instanceTransform = glm::translate(instanceTransform, position); + instanceTransform *= glm::mat4_cast(rotation); + + //upside down. + instanceTransform *= CesiumGeometry::Transforms::Y_UP_TO_Z_UP; + instanceTransform *= CesiumGeometry::Transforms::Y_UP_TO_Z_UP; + + instanceTransform = glm::scale(instanceTransform, scale); + + // Apply node transformation + instanceData.transform = nodeTransform * instanceTransform; + + // Set other properties + instanceData.color = glm::dvec4(1.0, 1.0, 1.0, 1.0); // white color + instanceData.batchId = static_cast(i); // batch ID + + outInstanceData.push_back(instanceData); + } +} + +bool CheckForExtMeshGpuInstancing( + const CesiumGltf::Model& gltf, + const CesiumGltf::Node& node) { + // Check if the EXT_mesh_gpu_instancing extension is present + return node.getExtension() != + nullptr; +} + +void ExtractInstanceDataFromGltfModel( + const CesiumGltf::Model& gltf, + const glm::dmat4& tileTransform, + std::vector& outInstanceData) { + + // Extracting EXT_mesh_gpu_instancing data from a model converted by I3dmToGltfConverter + gltf.forEachPrimitiveInScene( + -1, + [&](const Model& model, + const Node& node, + const Mesh& mesh, + const MeshPrimitive& primitive, + const glm::dmat4& nodeTransform) { + // Check the EXT_mesh_gpu_instancing extension + const auto* pGpuInstancing = + node.getExtension(); + + if (pGpuInstancing && !pGpuInstancing->attributes.empty()) { + ExtractInstanceDataFromExtMeshGpuInstancing( + model, + node, + *pGpuInstancing, + tileTransform * nodeTransform, + outInstanceData); + } + }); +} } // namespace void* UnityPrepareRendererResources::prepareInMainThread( @@ -1453,6 +1666,9 @@ void* UnityPrepareRendererResources::prepareInMainThread( int32_t meshIndex = 0; + // i3dm index tracking variable + int i3dmGlobalIndex = 0; + // For backwards compatibility. CesiumForUnity::CesiumMetadata metadataComponent = pModelGameObject @@ -1478,6 +1694,7 @@ void* UnityPrepareRendererResources::prepareInMainThread( &pModelGameObject, &tileTransform, &meshIndex, + &i3dmGlobalIndex, &tilesetComponent, pCoordinateSystem, createPhysicsMeshes, @@ -1528,110 +1745,275 @@ void* UnityPrepareRendererResources::prepareInMainThread( primitiveGameObject.transform().parent(pModelGameObject->transform()); primitiveGameObject.layer(tilesetLayer); - glm::dmat4 modelToEcef = tileTransform * transform; + + //check i3dm + bool isI3dmType = CheckForExtMeshGpuInstancing(gltf,node); - CesiumForUnity::CesiumGlobeAnchor anchor = - primitiveGameObject - .AddComponent(); - anchor.detectTransformChanges(false); - anchor.adjustOrientationForGlobeWhenMoving(false); - anchor.localToGlobeFixedMatrix( - UnityTransforms::toUnityMathematics(modelToEcef)); + std::vector instanceData; + std::vector intanceObjects; - UnityEngine::MeshFilter meshFilter = - primitiveGameObject.AddComponent(); - meshFilter.sharedMesh(unityMesh); + if (isI3dmType) { + // Extract instance data from models already processed by existing + // converters - UnityEngine::MeshRenderer meshRenderer = - primitiveGameObject.AddComponent(); + ::DotNet::UnityEngine::Object::DestroyImmediate(primitiveGameObject); - const Material* pMaterial = - Model::getSafe(&gltf.materials, primitive.material); + // Extract only instances of the current node (i3dm) (to prevent duplication) + const auto* pGpuInstancing = + node.getExtension(); + + if (pGpuInstancing && !pGpuInstancing->attributes.empty()) { + ExtractInstanceDataFromExtMeshGpuInstancing( + gltf, + node, + *pGpuInstancing, + tileTransform * transform, + instanceData); + } - UnityEngine::Material opaqueMaterial = - tilesetComponent.opaqueMaterial(); + for (size_t instanceDataIndex = 0; + instanceDataIndex < instanceData.size(); + ++instanceDataIndex) { + + UnityEngine::GameObject intanceGameObject(System::String( + "I3dm " + std::to_string(i3dmGlobalIndex) + + " Mesh " + std::to_string(instanceDataIndex) + + " Primitive " + + std::to_string(primitiveIndex))); + if (showTilesInHierarchy) { + intanceGameObject.hideFlags(UnityEngine::HideFlags::DontSave); + } else { + intanceGameObject.hideFlags( + UnityEngine::HideFlags::DontSave | + UnityEngine::HideFlags::HideInHierarchy); + } - if (opaqueMaterial == nullptr) { - if (primitiveInfo.isUnlit) { - opaqueMaterial = - UnityEngine::Resources::Load( - System::String("CesiumUnlitTilesetMaterial")); - } else { - opaqueMaterial = - UnityEngine::Resources::Load( - System::String("CesiumDefaultTilesetMaterial")); + intanceGameObject.transform().parent( + pModelGameObject->transform()); + intanceGameObject.layer(tilesetLayer); + intanceObjects.push_back(intanceGameObject); } + + // Increment the index with the next i3dm + i3dmGlobalIndex++; } - UnityEngine::Material material = - UnityEngine::Object::Instantiate(opaqueMaterial); - material.hideFlags(UnityEngine::HideFlags::HideAndDontSave); - meshRenderer.material(material); - if (pMaterial) { - setGltfMaterialParameterValues( - gltf, - primitiveInfo, - *pMaterial, - material, - materialProperties); - } + glm::dmat4 modelToEcef = tileTransform * transform; - if (primitiveInfo.containsPoints) { - CesiumForUnity::CesiumPointCloudRenderer pointCloudRenderer = - primitiveGameObject - .AddComponent(); - - CesiumForUnity::Cesium3DTileInfo tileInfo; - tileInfo.usesAdditiveRefinement = - tile.getRefine() == Cesium3DTilesSelection::TileRefine::Add; - tileInfo.geometricError = - static_cast(tile.getGeometricError()); - - // TODO: can we make AccessorView retrieve the min/max for us? - const Accessor* pPositionAccessor = - Model::getSafe(&gltf.accessors, positionAccessorID); - glm::vec3 min( - pPositionAccessor->min[0], - pPositionAccessor->min[1], - pPositionAccessor->min[2]); - glm::vec3 max( - pPositionAccessor->max[0], - pPositionAccessor->max[1], - pPositionAccessor->max[2]); - glm::vec3 dimensions(transform * glm::dvec4(max - min, 0)); - - tileInfo.dimensions = - UnityEngine::Vector3{dimensions.x, dimensions.y, dimensions.z}; - tileInfo.isTranslucent = primitiveInfo.isTranslucent; - pointCloudRenderer.tileInfo(tileInfo); - } + if (isI3dmType) { + + if (!instanceData.empty() && meshes.Length() != 0) { + // Using the first mesh (i3dm is an instance of the same model) + UnityEngine::Mesh baseMesh = meshes[primitiveIndex]; - if (createPhysicsMeshes) { - if (!primitiveInfo.containsPoints && - !isDegenerateTriangleMesh(unityMesh)) { - // This should not trigger mesh baking for physics, because the - // meshes were already baked in the worker thread. - UnityEngine::MeshCollider meshCollider = - primitiveGameObject.AddComponent(); - meshCollider.sharedMesh(unityMesh); - } - } + UnityEngine::Material opaqueMaterial = + tilesetComponent.opaqueMaterial(); + + if (opaqueMaterial == nullptr) { + if (primitiveInfo.isUnlit) { + opaqueMaterial = + UnityEngine::Resources::Load( + System::String("CesiumUnlitTilesetMaterial")); + } else { + opaqueMaterial = + UnityEngine::Resources::Load( + System::String("CesiumDefaultTilesetMaterial")); + } + } + + UnityEngine::Material material = + UnityEngine::Object::Instantiate(opaqueMaterial); - // For backwards compatibility. - if (metadataComponent != nullptr) { - metadataComponent.NativeImplementation().addMetadata( - primitiveGameObject.transform().GetInstanceID(), - &gltf, - &primitive); + const Material* pMaterial = + Model::getSafe(&gltf.materials, primitive.material); + + if (pMaterial) { + setGltfMaterialParameterValues( + gltf, + primitiveInfo, + *pMaterial, + material, + materialProperties); + } + + // set shader for GPU Instancing + material.enableInstancing(true); + + const std::string* url = + std::get_if(&tile.getTileID()); + + std::string groupId = *url; + + for (size_t i = 0; i < intanceObjects.size(); ++i) { + + const InstanceData& instance = instanceData[i]; + + modelToEcef = instance.transform; + + UnityEngine::GameObject& instanceGameObject = + intanceObjects[i]; + + CesiumForUnity::CesiumGlobeAnchor instanceAnchor = + instanceGameObject.AddComponent(); + instanceAnchor.detectTransformChanges(false); + instanceAnchor.adjustOrientationForGlobeWhenMoving(false); + instanceAnchor.localToGlobeFixedMatrix( + UnityTransforms::toUnityMathematics(modelToEcef)); + + if (createPhysicsMeshes) { + // This should not trigger mesh baking for physics, because + // the meshes were already baked in the worker thread. + UnityEngine::MeshCollider meshCollider = + instanceGameObject + .AddComponent(); + meshCollider.sharedMesh(baseMesh); + } + } + + + + CesiumForUnity::I3dmInstanceRenderer i3dmInstanceRenderer = + pModelGameObject + ->AddComponent(); + + DotNet::System::Collections::Generic::List1< + DotNet::Unity::Mathematics::double4x4> + matList = DotNet::System::Collections::Generic::List1< + DotNet::Unity::Mathematics::double4x4>(); + + for (size_t i = 0; i < instanceData.size(); ++i) { + const InstanceData& instance = instanceData[i]; + matList.Add( + UnityTransforms::toUnityMathematics(instance.transform)); + } + + i3dmInstanceRenderer.AddInstanceGroup( + System::String(groupId), + baseMesh, + material, + matList); + + // For backwards compatibility. + if (metadataComponent != nullptr) { + metadataComponent.NativeImplementation().addMetadata( + primitiveGameObject.transform().GetInstanceID(), + &gltf, + &primitive); + } else { + const ExtensionExtMeshFeatures* pFeatures = + primitive.getExtension(); + if (pFeatures) { + CesiumFeaturesMetadataUtility::addPrimitiveFeatures( + primitiveGameObject, + gltf, + primitive, + *pFeatures); + } + } + } } else { - const ExtensionExtMeshFeatures* pFeatures = - primitive.getExtension(); - if (pFeatures) { - CesiumFeaturesMetadataUtility::addPrimitiveFeatures( - primitiveGameObject, + CesiumForUnity::CesiumGlobeAnchor anchor = + primitiveGameObject + .AddComponent(); + anchor.detectTransformChanges(false); + anchor.adjustOrientationForGlobeWhenMoving(false); + anchor.localToGlobeFixedMatrix( + UnityTransforms::toUnityMathematics(modelToEcef)); + + UnityEngine::MeshFilter meshFilter = + primitiveGameObject.AddComponent(); + meshFilter.sharedMesh(unityMesh); + + UnityEngine::MeshRenderer meshRenderer = + primitiveGameObject.AddComponent(); + + const Material* pMaterial = + Model::getSafe(&gltf.materials, primitive.material); + + UnityEngine::Material opaqueMaterial = + tilesetComponent.opaqueMaterial(); + + if (opaqueMaterial == nullptr) { + if (primitiveInfo.isUnlit) { + opaqueMaterial = + UnityEngine::Resources::Load( + System::String("CesiumUnlitTilesetMaterial")); + } else { + opaqueMaterial = + UnityEngine::Resources::Load( + System::String("CesiumDefaultTilesetMaterial")); + } + } + UnityEngine::Material material = + UnityEngine::Object::Instantiate(opaqueMaterial); + material.hideFlags(UnityEngine::HideFlags::HideAndDontSave); + meshRenderer.material(material); + if (pMaterial) { + setGltfMaterialParameterValues( gltf, - primitive, - *pFeatures); + primitiveInfo, + *pMaterial, + material, + materialProperties); + } + + if (primitiveInfo.containsPoints) { + CesiumForUnity::CesiumPointCloudRenderer pointCloudRenderer = + primitiveGameObject + .AddComponent(); + + CesiumForUnity::Cesium3DTileInfo tileInfo; + tileInfo.usesAdditiveRefinement = + tile.getRefine() == Cesium3DTilesSelection::TileRefine::Add; + tileInfo.geometricError = + static_cast(tile.getGeometricError()); + + // TODO: can we make AccessorView retrieve the min/max for us? + const Accessor* pPositionAccessor = + Model::getSafe(&gltf.accessors, positionAccessorID); + glm::vec3 min( + pPositionAccessor->min[0], + pPositionAccessor->min[1], + pPositionAccessor->min[2]); + glm::vec3 max( + pPositionAccessor->max[0], + pPositionAccessor->max[1], + pPositionAccessor->max[2]); + glm::vec3 dimensions(transform * glm::dvec4(max - min, 0)); + + tileInfo.dimensions = + UnityEngine::Vector3{dimensions.x, dimensions.y, dimensions.z}; + tileInfo.isTranslucent = primitiveInfo.isTranslucent; + pointCloudRenderer.tileInfo(tileInfo); + } + + if (createPhysicsMeshes) { + if (!primitiveInfo.containsPoints && + !isDegenerateTriangleMesh(unityMesh)) { + // This should not trigger mesh baking for physics, because the + // meshes were already baked in the worker thread. + UnityEngine::MeshCollider meshCollider = + primitiveGameObject.AddComponent(); + meshCollider.sharedMesh(unityMesh); + } + } + + // For backwards compatibility. + if (metadataComponent != nullptr) { + metadataComponent.NativeImplementation().addMetadata( + primitiveGameObject.transform().GetInstanceID(), + &gltf, + &primitive); + } else { + const ExtensionExtMeshFeatures* pFeatures = + primitive.getExtension(); + if (pFeatures) { + CesiumFeaturesMetadataUtility::addPrimitiveFeatures( + primitiveGameObject, + gltf, + primitive, + *pFeatures); + } } } }); diff --git a/native~/Runtime/src/UnityPrepareRendererResources.h b/native~/Runtime/src/UnityPrepareRendererResources.h index 51f2528d..df65e8b4 100644 --- a/native~/Runtime/src/UnityPrepareRendererResources.h +++ b/native~/Runtime/src/UnityPrepareRendererResources.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "TilesetMaterialProperties.h"