/// <summary>
        /// Overridden to read optional point cloud indices.
        /// </summary>
        /// <param name="msg">Message header.</param>
        /// <param name="packet">Data packet.</param>
        /// <param name="reader">Data packet reader.</param>
        /// <returns></returns>
        protected override Error HandleMessage(DataMessage msg, PacketBuffer packet, BinaryReader reader)
        {
            ShapeCache cache      = (msg.ObjectID == 0) ? _transientCache : _shapeCache;
            int        shapeIndex = (msg.ObjectID == 0) ? _lastTransientIndex : cache.GetShapeIndex(msg.ObjectID);

            if (shapeIndex < 0)
            {
                return(new Error(ErrorCode.InvalidObjectID, msg.ObjectID));
            }

            PointsComponent pointsComp = cache.GetShapeDataByIndex <PointsComponent>(shapeIndex);

            // Read index offset and count.
            uint offset = reader.ReadUInt32();
            uint count  = reader.ReadUInt32();

            int[] indices = pointsComp.Indices;
            for (uint i = 0; i < count; ++i)
            {
                indices[i + offset] = reader.ReadInt32();
            }

            pointsComp.IndicesDirty = true;

            if (pointsComp.IndexCount != 0 && offset + count >= pointsComp.IndexCount)
            {
                // Done. Register for the mesh.
                RegisterForMesh(pointsComp);
            }

            return(new Error());
        }
        /// <summary>
        /// Overridden to read information about mesh parts.
        /// </summary>
        /// <param name="msg"></param>
        /// <param name="packet"></param>
        /// <param name="reader"></param>
        /// <returns></returns>
        protected override Error PostHandleMessage(CreateMessage msg, PacketBuffer packet, BinaryReader reader,
                                                   ShapeCache cache, int shapeIndex)
        {
            // Read additional attributes.
            PointsComponent pointsComp = new PointsComponent();

            // Read the mesh ID to render points from.
            pointsComp.MeshID = reader.ReadUInt32();
            // Read the number of indices (zero implies show entire mesh).
            pointsComp.IndexCount = reader.ReadUInt32();

            if (packet.Header.VersionMajor == 0 && packet.Header.VersionMinor == 1)
            {
                // Legacy support.
                pointsComp.PointScale = (float)reader.ReadByte();
            }
            else
            {
                pointsComp.PointScale = reader.ReadSingle();
            }

            cache.SetShapeDataByIndex(shapeIndex, pointsComp);

            if (pointsComp.IndexCount == 0)
            {
                pointsComp.IndicesDirty = false;
                // Not expecting any index data messages.
                // Register the mesh now.
                RegisterForMesh(pointsComp);
            }

            return(new Error());
        }
Пример #3
0
        /// <summary>
        /// Overridden to read information about mesh parts.
        /// </summary>
        /// <param name="msg"></param>
        /// <param name="packet"></param>
        /// <param name="reader"></param>
        /// <returns></returns>
        protected override Error HandleMessage(CreateMessage msg, PacketBuffer packet, BinaryReader reader)
        {
            GameObject obj = null;

            if (msg.ObjectID == 0)
            {
                // Cannot support transient objects: we need to get point data through additional
                // messages which requires a valid object id.
                return(new Error(ErrorCode.InvalidObjectID, 0));
            }
            else
            {
                obj = CreateObject(msg.ObjectID);
                if (!obj)
                {
                    // Object already exists.
                    return(new Error(ErrorCode.DuplicateShape, msg.ObjectID));
                }
            }

            ShapeComponent shapeComp = obj.GetComponent <ShapeComponent>();

            if (shapeComp)
            {
                shapeComp.Category    = msg.Category;
                shapeComp.ObjectFlags = msg.Flags;
                shapeComp.Colour      = ShapeComponent.ConvertColour(msg.Attributes.Colour);
            }

            obj.transform.SetParent(Root.transform, false);
            DecodeTransform(msg.Attributes, obj.transform);

            // Read additional attributes.
            PointsComponent pointsComp = obj.AddComponent <PointsComponent>();

            // Read the mesh ID to render points from.
            pointsComp.MeshID = reader.ReadUInt32();
            // Read the number of indices (zero implies show entire mesh).
            pointsComp.IndexCount = reader.ReadUInt32();
            pointsComp.PointSize  = reader.ReadByte();

            if (pointsComp.IndexCount == 0)
            {
                // Not expecting any index data messages.
                // Register the mesh now.
                RegisterForMesh(pointsComp);
            }

            return(new Error());
        }
        /// <summary>
        /// Creates a point cloud shape for serialising <paramref name="shapeComponent"/> and its point data.
        /// </summary>
        /// <param name="shapeComponent">The component to create a shape for.</param>
        /// <returns>A shape instance suitable for configuring to generate serialisation messages.</returns>
        protected override Shapes.Shape CreateSerialisationShape(ShapeCache cache, int shapeIndex, CreateMessage shapeData)
        {
            PointsComponent pointsComp = cache.GetShapeDataByIndex <PointsComponent>(shapeIndex);

            Shapes.PointCloudShape points = new Shapes.PointCloudShape(new MeshResourcePlaceholder(pointsComp.MeshID),
                                                                       shapeData.ObjectID,
                                                                       shapeData.Category,
                                                                       pointsComp.PointScale);
            points.SetAttributes(shapeData.Attributes);
            if (pointsComp.IndexCount > 0)
            {
                points.SetIndices(pointsComp.Indices);
            }
            return(points);
        }
Пример #5
0
        /// <summary>
        /// Post destroy message: destroy sub-objects.
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="msg"></param>
        /// <param name="packet"></param>
        /// <param name="reader"></param>
        /// <returns></returns>
        protected override Error PostHandleMessage(GameObject obj, DestroyMessage msg, PacketBuffer packet, BinaryReader reader)
        {
            PointsComponent points = obj.GetComponent <PointsComponent>();

            if (points != null)
            {
                // Remove the registered parts.
                List <PointsComponent> parts = null;
                if (_registeredParts.TryGetValue(points.MeshID, out parts))
                {
                    // Remove from parts.
                    parts.Remove(points);
                    _awaitingFinalisation.RemoveAll((PointsComponent cmp) => { return(cmp == points); });
                    //parts.RemoveAll((PointsComponent cmp) => { return cmp == part; }));
                }
            }
            return(new Error());
        }
        /// <summary>
        /// Post destroy message: destroy sub-objects.
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="msg"></param>
        /// <param name="packet"></param>
        /// <param name="reader"></param>
        /// <returns></returns>
        protected override Error PostHandleMessage(DestroyMessage msg, ShapeCache cache, int shapeIndex)
        {
            PointsComponent pointsComp = cache.GetShapeDataByIndex <PointsComponent>(shapeIndex);

            if (pointsComp != null)
            {
                // Remove from the registered mesh list.
                List <PointsComponent> parts;
                if (_registeredParts.TryGetValue(pointsComp.MeshID, out parts))
                {
                    // Remove from the list.
                    parts.RemoveAll((PointsComponent cmp) => { return(cmp == pointsComp); });
                }

                pointsComp.Release();
            }
            return(new Error());
        }
Пример #7
0
        /// <summary>
        /// Creates a point cloud shape for serialising <paramref name="shapeComponent"/> and its point data.
        /// </summary>
        /// <param name="shapeComponent">The component to create a shape for.</param>
        /// <returns>A shape instance suitable for configuring to generate serialisation messages.</returns>
        protected override Shapes.Shape CreateSerialisationShape(ShapeComponent shapeComponent)
        {
            PointsComponent pointsComp = shapeComponent.GetComponent <PointsComponent>();

            if (pointsComp != null)
            {
                ObjectAttributes attr = new ObjectAttributes();
                EncodeAttributes(ref attr, shapeComponent.gameObject, shapeComponent);

                Shapes.PointCloudShape points = new Shapes.PointCloudShape(new MeshResourcePlaceholder(pointsComp.MeshID),
                                                                           shapeComponent.ObjectID,
                                                                           shapeComponent.Category,
                                                                           (byte)pointsComp.PointSize);
                points.SetAttributes(attr);

                return(points);
            }
            return(null);
        }
Пример #8
0
        /// <summary>
        /// Overridden to read optional point cloud indices.
        /// </summary>
        /// <param name="msg">Message header.</param>
        /// <param name="packet">Data packet.</param>
        /// <param name="reader">Data packet reader.</param>
        /// <returns></returns>
        protected override Error HandleMessage(DataMessage msg, PacketBuffer packet, BinaryReader reader)
        {
            GameObject obj = null;

            if (msg.ObjectID != 0)
            {
                obj = FindObject(msg.ObjectID);
            }
            else
            {
                obj = _transientCache.LastObject;
            }

            if (obj == null)
            {
                return(new Error(ErrorCode.InvalidObjectID, msg.ObjectID));
            }

            // Read index offset and count.
            uint offset = reader.ReadUInt32();
            uint count  = reader.ReadUInt32();

            PointsComponent pointsComp = obj.GetComponent <PointsComponent>();

            int[] indices = pointsComp.Indices;
            for (uint i = 0; i < count; ++i)
            {
                indices[i + offset] = reader.ReadInt32();
            }

            if (pointsComp.IndexCount != 0 && offset + count >= pointsComp.IndexCount)
            {
                // Done. Register for the mesh.
                RegisterForMesh(pointsComp);
            }

            return(new Error());
        }
        protected virtual void BindMaterial(PointsComponent points)
        {
            // Select the material by topology.
            Material material = new Material(_pointsMaterial);

            if (points.Mesh.Mesh.HasColours)
            {
                material.EnableKeyword("WITH_COLOURS_UINT");
            }

            if (points.Mesh.Mesh.HasNormals)
            {
                material.EnableKeyword("WITH_NORMALS");
            }

            if (material.HasProperty("_LeftHanded"))
            {
                material.SetInt("_LeftHanded", ServerInfo.IsLeftHanded ? 1 : 0);
            }

            if (material.HasProperty("_PointSize"))
            {
                float pointScale = (points.PointScale > 0) ? points.PointScale : 1.0f;
                material.SetFloat("_PointSize", GlobalSettings.PointSize * pointScale);
            }

            if (material.HasProperty("_Color"))
            {
                material.SetColor("_Color", points.Colour);
            }

            if (material.HasProperty("_Tint"))
            {
                material.SetColor("_Tint", points.Mesh.Tint);
            }

            points.Material = material;
        }
Пример #10
0
        /// <summary>
        /// Register <paramref name="points"/> for mesh resolving.
        /// </summary>
        /// <remarks>
        /// The mesh is either resolved now, or on mesh finalisation.
        /// Note that any limited indexing must be completed before calling
        /// this function. That is <see cref="PointsComponent.Indices"/>
        /// must have been resolved.
        /// </remarks>
        /// <param name="points">The points component.</param>
        protected void RegisterForMesh(PointsComponent points)
        {
            List <PointsComponent> parts = null;

            if (!_registeredParts.TryGetValue(points.MeshID, out parts))
            {
                // Add new list.
                parts = new List <PointsComponent>();
                _registeredParts.Add(points.MeshID, parts);
            }

            parts.Add(points);

            // Try resolve the mesh from the cache now.
            if (_meshCache != null)
            {
                MeshCache.MeshDetails meshDetails = _meshCache.GetEntry(points.MeshID);
                if (meshDetails != null && meshDetails.Finalised)
                {
                    points.MeshDirty = true;
                    _awaitingFinalisation.Add(points);
                }
            }
        }
Пример #11
0
        /// <summary>
        /// Set the visuals of <pararef name="points"/> to use <paramref name="meshDetails"/>.
        /// </summary>
        /// <param name="points">The points object</param>
        /// <param name="meshDetails">The mesh details.</param>
        /// <remarks>
        /// Adds multiple children to <paramref name="points"/> when <paramref name="meshDetails"/>
        /// contains multiple mesh objects.
        /// </remarks>
        protected virtual void SetMesh(PointsComponent points, MeshCache.MeshDetails meshDetails)
        {
            ShapeComponent shape = points.GetComponent <ShapeComponent>();

            // Clear all children as a hard reset.
            foreach (Transform child in points.GetComponentsInChildren <Transform>())
            {
                if (child.gameObject != points.gameObject)
                {
                    child.parent = null;
                    GameObject.Destroy(child.gameObject);
                }
            }

            // Use shared resources if we have no limited indexing.
            if (points.IndexCount == 0)
            {
                // Add children for each mesh sub-sub-part.
                int partNumber = 0;
                foreach (Mesh mesh in meshDetails.FinalMeshes)
                {
                    GameObject partMesh = new GameObject(string.Format("cloud{0}", partNumber));
                    partMesh.transform.localPosition = meshDetails.LocalPosition;
                    partMesh.transform.localRotation = meshDetails.LocalRotation;
                    partMesh.transform.localScale    = meshDetails.LocalScale;
                    partMesh.AddComponent <MeshFilter>().sharedMesh = mesh;

                    MeshRenderer renderer = partMesh.AddComponent <MeshRenderer>();
                    if (meshDetails.Topology == MeshTopology.Points)
                    {
                        // Use mesh material as is.
                        renderer.material = meshDetails.Material;
                    }
                    else
                    {
                        // Rendering a mesh with non-point topology. Set tha points based material.
                        renderer.material = mesh.normals.Length > 0 ? _litMaterial : _unlitMaterial;
                    }
                    int pointSize = points.PointSize;
                    if (pointSize == 0 && Materials != null)
                    {
                        pointSize = Materials.DefaultPointSize;
                    }
                    renderer.material.SetInt("_PointSize", pointSize);
                    renderer.material.SetInt("_LeftHanded", ServerInfo.IsLeftHanded ? 1 : 0);
                    renderer.material.color = (shape != null) ? shape.Colour : new Color32(255, 255, 255, 255);
                    partMesh.transform.SetParent(points.transform, false);
                    ++partNumber;
                }
            }
            else
            {
                // We are going to need to remap the indexing. For this we'll
                // copy the required vertices from the MeshDetails and create new
                // meshes with new indices. We could potentially share vertex data,
                // but this is difficult with the Unity vertex count limit.
                Mesh[] meshes = meshDetails.Builder.GetReindexedMeshes(points.Indices, MeshTopology.Points);
                for (int i = 0; i < meshes.Length; ++i)
                {
                    // Create this mesh piece.
                    bool     defaultMaterial = meshDetails.Topology == MeshTopology.Points;
                    Material material        = (defaultMaterial) ? meshDetails.Material : _unlitMaterial;
                    if (!defaultMaterial && meshDetails.Builder.Normals.Length != 0)
                    {
                        material = _litMaterial;
                    }

                    GameObject child = new GameObject();
                    child.AddComponent <MeshFilter>().mesh = meshes[i];
                    material.SetInt("_PointSize", points.PointSize);
                    material.SetInt("_LeftHanded", ServerInfo.IsLeftHanded ? 1 : 0);
                    child.AddComponent <MeshRenderer>().material = material;
                    child.transform.SetParent(points.transform, false);
                }
            }
        }
        void RenderPoints(CameraContext cameraContext, ShapeCache cache, int shapeIndex)
        {
            CreateMessage shape = cache.GetShapeByIndex(shapeIndex);

            if (CategoriesState != null && !CategoriesState.IsActive(shape.Category))
            {
                return;
            }

            Matrix4x4       modelWorld  = cameraContext.TesSceneToWorldTransform * cache.GetShapeTransformByIndex(shapeIndex);
            PointsComponent points      = cache.GetShapeDataByIndex <PointsComponent>(shapeIndex);
            CommandBuffer   renderQueue = cameraContext.OpaqueBuffer;
            RenderMesh      mesh        = points.Mesh != null ? points.Mesh.Mesh : null;

            if (mesh == null)
            {
                // No mesh.
                Debug.LogWarning($"Point cloud shape {shape.ObjectID} missing mesh with ID {points.MeshID}");
                return;
            }

            if (points.Material == null)
            {
                // No mesh.
                Debug.LogWarning($"Point cloud shape {shape.ObjectID} missing material");
                return;
            }

            // Check rendering with index buffer?
            GraphicsBuffer indexBuffer = null;
            int            indexCount  = 0;

            if (mesh.IndexCount > 0 || points.IndexCount > 0)
            {
                if ((int)points.IndexCount > 0)
                {
                    indexBuffer = points.IndexBuffer;
                    indexCount  = (int)points.IndexCount;
                }
                // We only use the mesh index buffer if the mesh has points topology.
                // Otherwise we convert to points using vertices as is.
                else if (mesh.Topology == MeshTopology.Points)
                {
                    indexBuffer = mesh.IndexBuffer;
                    indexCount  = mesh.IndexCount;
                }
            }

            if (mesh.HasColours)
            {
                points.Material.SetBuffer("_Colours", mesh.ColoursBuffer);
            }

            if (mesh.HasNormals)
            {
                points.Material.SetBuffer("_Normals", mesh.NormalsBuffer);
            }

            points.Material.SetBuffer("_Vertices", mesh.VertexBuffer);


            // Set min/max shader values.
            if (points.Material.HasProperty("_BoundsMin"))
            {
                points.Material.SetVector("_BoundsMin", points.Mesh.Mesh.MinBounds);
            }
            if (points.Material.HasProperty("_BoundsMax"))
            {
                points.Material.SetVector("_BoundsMax", points.Mesh.Mesh.MaxBounds);
            }

            float pointScale = (points.PointScale > 0) ? points.PointScale : 1.0f;

            points.Material.SetFloat("_PointSize", GlobalSettings.PointSize * pointScale);

            // Colour by height if we have a zero colour value.
            if (shape.Attributes.Colour == 0)
            {
                points.Material.SetColor("_Color", Color.white);
                points.Material.SetColor("_BackColour", Color.white);
                switch (CoordinateFrameUtil.AxisIndex(ServerInfo.CoordinateFrame, 2))
                {
                case 0:
                    points.Material.EnableKeyword("WITH_COLOURS_RANGE_X");
                    break;

                case 1:
                    points.Material.EnableKeyword("WITH_COLOURS_RANGE_Y");
                    break;

                default:
                case 2:
                    points.Material.EnableKeyword("WITH_COLOURS_RANGE_Z");
                    break;
                }
            }

            if (mesh.IndexBuffer != null)
            {
                renderQueue.DrawProcedural(mesh.IndexBuffer, modelWorld, points.Material, 0, mesh.Topology, mesh.IndexCount);
            }
            else
            {
                renderQueue.DrawProcedural(modelWorld, points.Material, 0, mesh.Topology, mesh.VertexCount);
            }
        }