Ejemplo n.º 1
0
        protected virtual void RenderInstances(CameraContext cameraContext, CommandBuffer renderQueue, Mesh mesh,
                                               List <Matrix4x4> transforms, List <Matrix4x4> parentTransforms,
                                               List <CreateMessage> shapes, Material material)
        {
            CategoriesState categories = this.CategoriesState;

            // Handle instancing block size limits.
            for (int i = 0; i < transforms.Count; i += _instanceTransforms.Length)
            {
                MaterialPropertyBlock materialProperties = new MaterialPropertyBlock();
                int itemCount = 0;
                _instanceColours.Clear();
                for (int j = 0; j < _instanceTransforms.Length && j + i < transforms.Count; ++j)
                {
                    if (categories == null || categories.IsActive(shapes[i + j].Category))
                    {
                        _instanceTransforms[itemCount] =
                            cameraContext.TesSceneToWorldTransform * parentTransforms[i + j] * transforms[i + j];
                        Maths.Colour colour = new Maths.Colour(shapes[i + j].Attributes.Colour);
                        _instanceColours.Add(Maths.ColourExt.ToUnityVector4(colour));
                        ++itemCount;
                    }
                }

                if (itemCount > 0)
                {
                    materialProperties.SetVectorArray("_Color", _instanceColours);
                    renderQueue.DrawMeshInstanced(mesh, 0, material, 0, _instanceTransforms, itemCount, materialProperties);
                }
            }
        }
        /// <summary>
        /// Clear all current objects.
        /// </summary>
        public override void Reset()
        {
            CategoriesState.Reset();
            _categories.Clear();
            if (OnClearCategories != null)
            {
                OnClearCategories();
            }

            // FIXME: localisation.
            AddCategory(0, 0, "Default", true);
        }
        /// <summary>
        /// Add a category to the list of known categories.
        /// </summary>
        /// <param name="id">The category ID</param>
        /// <param name="parentId">The parent ID. Zero is none (even though 0 is a valid category).</param>
        /// <param name="name">The category display name.</param>
        /// <param name="active">The default active state.</param>
        public void AddCategory(ushort id, ushort parentId, string name, bool active)
        {
            Category cat = new Category();

            cat.ID              = id;
            cat.ParentID        = parentId;
            cat.Name            = name;
            cat.Active          = active;
            _categories[cat.ID] = cat;
            bool parentActive = parentId == 0 || CategoriesState.IsActive(parentId);

            CategoriesState.SetActive(cat.ID, cat.Active && parentActive);
            NotifyNewCategory(cat);
        }
        /// <summary>
        /// Set the active state of all descendants of the category identified by <paramref name="id"/>.
        /// </summary>
        /// <param name="id">The parent category ID.</param>
        /// <param name="active">The new active state.</param>
        private void PropagateActiveToChildren(ushort id, bool active)
        {
            // Skip default category.
            if (id == 0)
            {
                return;
            }

            // Also affect all children.
            foreach (Category cat in ChildCategories(id))
            {
                if (CategoriesState.IsActive(cat.ID) != active)
                {
                    CategoriesState.SetActive(cat.ID, active);
                }
                PropagateActiveToChildren(cat.ID, active);
            }
        }
        /// <summary>
        /// Set the active state of a category.
        /// </summary>
        /// <param name="id">The category ID.</param>
        /// <param name="active">The desired active state.</param>
        /// <remarks>
        /// This invokes the <see cref="OnActivationChange"/> event when <paramref name="active"/>
        /// does not match the category state.
        ///
        /// Unknown <paramref name="id"/> values are ignored.
        /// </remarks>
        public void SetActive(ushort id, bool active)
        {
            Category cat;

            if (_categories.TryGetValue(id, out cat))
            {
                if (cat.Active != active)
                {
                    cat.Active = active;
                    // Update the dictionary.
                    _categories[cat.ID] = cat;
                    // Check hierarchy to determin final state.
                    bool mergedActive = active && CheckHierarchyActive(cat.ParentID);
                    CategoriesState.SetActive(cat.ID, mergedActive);
                    PropagateActiveToChildren(id, mergedActive);
                    if (OnActivationChange != null)
                    {
                        OnActivationChange(id, active);
                    }
                }
            }
        }
 /// <summary>
 /// Check if a category is active.
 /// </summary>
 /// <param name="id">The category ID.</param>
 /// <returns>True if active or unknown/</returns>
 public bool IsActive(ushort id)
 {
     return(CategoriesState.IsActive(id));
 }
Ejemplo n.º 7
0
        protected void Render(CameraContext cameraContext, ShapeCache shapeCache)
        {
            // TODO: (KS) verify material setup.
            // TODO: (KS) incorporate the 3es scene transform.
            // TODO: (KS) handle multiple cameras (code only tailored to one).
            Vector3         cameraPosition = (Vector3)cameraContext.CameraToWorldTransform.GetColumn(3);
            CategoriesState categories     = this.CategoriesState;

            // Walk the items in the shape cache.
            foreach (int shapeIndex in shapeCache.ShapeIndices)
            {
                // if (shapeCache.GetShapeDataByIndex<CreateMessage>(shapeIndex).Category)
                CreateMessage shape = shapeCache.GetShapeByIndex(shapeIndex);
                if (!categories.IsActive(shape.Category))
                {
                    // Category not enabled.
                    continue;
                }

                // Get transform and text data.
                Matrix4x4     transform = shapeCache.GetShapeTransformByIndex(shapeIndex);
                TextShapeData textData  = shapeCache.GetShapeDataByIndex <TextShapeData>(shapeIndex);

                if (textData.Mesh == null || textData.Material == null)
                {
                    // No mesh/material. Try instantiate via the delegate.
                    if (CreateTextMeshHandler != null)
                    {
                        CreateTextMeshHandler(textData.Text, textData.FontSize,
                                              Maths.ColourExt.ToUnity(new Maths.Colour(shape.Attributes.Colour)),
                                              ref textData.Mesh, ref textData.Material);
                    }

                    if (textData.Mesh == null || textData.Material == null)
                    {
                        continue;
                    }

                    // Newly creates mesh/material. Store the changes.
                    shapeCache.SetShapeDataByIndex <TextShapeData>(shapeIndex, textData);
                }

                if (textData.Mesh == null || textData.Material == null)
                {
                    continue;
                }

                if (textData.ScreenFacing)
                {
                    Vector3 textPosition = cameraContext.TesSceneToWorldTransform * (Vector3)transform.GetColumn(3);
                    Vector3 toCamera     = cameraPosition - textPosition;
                    // Remove any height component from the camera. Indexing using Unity's left handed, Y up system.
                    toCamera[1] = 0;

                    if (toCamera.sqrMagnitude > 1e-3f)
                    {
                        toCamera = toCamera.normalized;
                        Vector3 side = Vector3.Cross(toCamera, Vector3.up);
                        // Build new rotation axes using toCamera for forward and a new Up axis.
                        transform.SetColumn(0, new Vector4(side.x, side.y, side.z));
                        transform.SetColumn(1, new Vector4(Vector3.up.x, Vector3.up.y, Vector3.up.z));
                        transform.SetColumn(2, new Vector4(toCamera.x, toCamera.y, toCamera.z));
                        transform.SetColumn(3, new Vector4(textPosition.x, textPosition.y, textPosition.z, 1.0f));
                    }
                    // else too close to the camera to build a rotation.
                }
                else
                {
                    // transform = cameraContext.TesSceneToWorldTransform * transform;
                    // Just extract the text position.
                    // TODO: (KS) will have to look at allowing users to orient the text from the server.
                    Vector3 textPosition = cameraContext.TesSceneToWorldTransform * (Vector3)transform.GetColumn(3);
                    transform = Matrix4x4.identity;
                    transform.SetColumn(3, new Vector4(textPosition.x, textPosition.y, textPosition.z, 1.0f));
                }

                cameraContext.TransparentBuffer.DrawMesh(textData.Mesh, transform, textData.Material);

                // TODO: (KS) resolve procedural rendering without a game object. Consider TextMeshPro.
                // TODO: (KS) select opaque layer.
                // Graphics.DrawMesh(textData.Mesh, transform, material, 0);
            }
        }
Ejemplo n.º 8
0
        private void RenderMeshes(CameraContext cameraContext, ShapeCache cache, int shapeIndex)
        {
            CreateMessage shape = cache.GetShapeByIndex(shapeIndex);

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

            Matrix4x4 shapeWorldTransform = cameraContext.TesSceneToWorldTransform * cache.GetShapeTransformByIndex(shapeIndex);
            PartSet   parts = cache.GetShapeDataByIndex <PartSet>(shapeIndex);

            for (int i = 0; i < parts.Meshes.Length; ++i)
            {
                RenderMesh mesh = (parts.Meshes[i] != null) ? parts.Meshes[i].Mesh : null;

                if (mesh == null)
                {
                    continue;
                }

                if (mesh.MaterialDirty)
                {
                    mesh.UpdateMaterial();
                }

                Material material =
                    (parts.MaterialOverrides != null && parts.MaterialOverrides.Length > 0 && parts.MaterialOverrides[i]) ?
                    parts.MaterialOverrides[i] : mesh.Material;

                if (material == null)
                {
                    continue;
                }

                // TODO: (KS) use transparent queue for parts with transparency.
                CommandBuffer renderQueue = cameraContext.OpaqueBuffer;

                // Push the part transform.
                Matrix4x4 partWorldTransform = shapeWorldTransform * parts.Transforms[i] * mesh.LocalTransform;

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

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

                // if (mesh.HasUVs)
                // {
                //   material.SetBuffer("uvs", mesh.UvsBuffer);
                // }

                if (material.HasProperty("_Color"))
                {
                    material.SetColor("_Color", new Maths.Colour(shape.Attributes.Colour).ToUnity32());
                }

                if (material.HasProperty("_Tint"))
                {
                    material.SetColor("_Tint", mesh.Tint.ToUnity32());
                }

                if (material.HasProperty("_BackColour"))
                {
                    material.SetColor("_BackColour", new Maths.Colour(shape.Attributes.Colour).ToUnity32());
                }

                // Bind vertices and draw.
                material.SetBuffer("_Vertices", mesh.VertexBuffer);

                if (mesh.IndexBuffer != null)
                {
                    renderQueue.DrawProcedural(mesh.IndexBuffer, partWorldTransform, material, 0, mesh.Topology, mesh.IndexCount);
                }
                else
                {
                    renderQueue.DrawProcedural(partWorldTransform, material, 0, mesh.Topology, mesh.VertexCount);
                }
            }
        }
Ejemplo n.º 9
0
        protected override void RenderInstances(CameraContext cameraContext, CommandBuffer renderQueue, Mesh mesh,
                                                List <Matrix4x4> transforms, List <Matrix4x4> parentTransforms,
                                                List <CreateMessage> shapes, Material material)
        {
            // Work out which mesh set we are rendering from the parent call: solid or wireframe. We could also look at
            // the first CreateMessage flags.
            Mesh[] meshes =
                (shapes.Count > 0 && (shapes[0].Flags & (ushort)ObjectFlag.Wireframe) != 0)  ? _wireframeMeshes : _solidMeshes;
            CategoriesState categories = this.CategoriesState;

            // Handle instancing block size limits.
            for (int i = 0; i < transforms.Count; i += _instanceTransforms.Length)
            {
                MaterialPropertyBlock materialProperties = new MaterialPropertyBlock();
                int itemCount = 0;
                _instanceColours.Clear();
                for (int j = 0; j < _instanceTransforms.Length && j + i < transforms.Count; ++j)
                {
                    if (categories != null && !categories.IsActive(shapes[i + j].Category))
                    {
                        continue;
                    }

                    // Build the end cap transforms.
                    Matrix4x4 modelToSceneTransform = cameraContext.TesSceneToWorldTransform * parentTransforms[i + j];
                    Matrix4x4 transform             = transforms[i + j];

                    // Work out the scaling. We only want to lengthen each line.
                    Vector3 scale = Vector3.zero;
                    scale.x = transform.GetColumn(0).magnitude;
                    scale.y = transform.GetColumn(1).magnitude;
                    scale.z = transform.GetColumn(2).magnitude;

                    // Remove scaling.
                    transform.SetColumn(0, transform.GetColumn(0) / scale.x);
                    transform.SetColumn(1, transform.GetColumn(1) / scale.y);
                    transform.SetColumn(2, transform.GetColumn(2) / scale.z);

                    // Scale each mesh.
                    Matrix4x4 transform2 = transform;
                    transform2.SetColumn(0, transform2.GetColumn(0) * scale.x);
                    _instanceTransforms[itemCount] = modelToSceneTransform * transform2;

                    transform2 = transform;
                    transform2.SetColumn(1, transform2.GetColumn(1) * scale.y);
                    _axis1Transforms[itemCount] = modelToSceneTransform * transform2;

                    transform2 = transform;
                    transform2.SetColumn(2, transform2.GetColumn(2) * scale.z);
                    _axis2Transforms[itemCount] = modelToSceneTransform * transform2;

                    Maths.Colour colour = new Maths.Colour(shapes[i + j].Attributes.Colour);
                    _instanceColours.Add(Maths.ColourExt.ToUnityVector4(colour));
                    ++itemCount;
                }

                if (itemCount > 0)
                {
                    materialProperties.SetVectorArray("_Color", _instanceColours);
                    // Render body.
                    renderQueue.DrawMeshInstanced(meshes[0], 0, material, 0, _instanceTransforms, itemCount, materialProperties);
                    // Render end caps.
                    renderQueue.DrawMeshInstanced(meshes[1], 0, material, 0, _axis1Transforms, itemCount, materialProperties);
                    renderQueue.DrawMeshInstanced(meshes[2], 0, material, 0, _axis2Transforms, itemCount, materialProperties);
                }
            }
        }
Ejemplo n.º 10
0
        protected void RenderObject(CameraContext cameraContext, ShapeCache cache, int shapeIndex)
        {
            CreateMessage shape = cache.GetShapeByIndex(shapeIndex);

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

            MeshEntry meshEntry = cache.GetShapeDataByIndex <MeshEntry>(shapeIndex);
            Matrix4x4 transform = cache.GetShapeTransformByIndex(shapeIndex);

            // TODO: (KS) select command buffer for transparent rendering.
            CommandBuffer renderQueue = cameraContext.OpaqueBuffer;
            Material      material    = meshEntry.Material;
            RenderMesh    mesh        = meshEntry.Mesh;

            if (material == null || mesh == null)
            {
                return;
            }

            Matrix4x4 modelWorld = cameraContext.TesSceneToWorldTransform * transform;

            // Transform and cull bounds
            // FIXME: (KS) this really isn't how culling should be performed.
            Bounds bounds = GeometryUtility.CalculateBounds(new Vector3[] { mesh.MinBounds, mesh.MaxBounds }, modelWorld);

            if (!GeometryUtility.TestPlanesAABB(cameraContext.CameraFrustumPlanes, bounds))
            {
                return;
            }

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

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

            // if (mesh.HasUVs)
            // {
            //   material.SetBuffer("uvs", mesh.UvsBuffer);
            // }

            if (material.HasProperty("_Color"))
            {
                material.SetColor("_Color", Maths.ColourExt.ToUnity(new Maths.Colour(shape.Attributes.Colour)));
            }

            if (material.HasProperty("_Tint"))
            {
                material.SetColor("_Tint", Maths.ColourExt.ToUnity(mesh.Tint));
            }

            if (material.HasProperty("_BackColour"))
            {
                material.SetColor("_BackColour", Maths.ColourExt.ToUnity(new Maths.Colour(shape.Attributes.Colour)));
            }

            // TODO: (KS) Need to derive this from the shape properties.
            if (mesh.Topology == MeshTopology.Points)
            {
                // Set min/max shader values.
                if (material.HasProperty("_BoundsMin"))
                {
                    material.SetVector("_BoundsMin", mesh.MinBounds);
                }
                if (material.HasProperty("_BoundsMax"))
                {
                    material.SetVector("_BoundsMax", mesh.MaxBounds);
                }

                float pointScale = (meshEntry.DrawScale > 0) ? meshEntry.DrawScale : 1.0f;
                material.SetFloat("_PointSize", GlobalSettings.PointSize * pointScale);

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

                    case 1:
                        material.EnableKeyword("WITH_COLOURS_RANGE_Y");
                        break;

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

            // Bind vertices and draw.
            material.SetBuffer("_Vertices", mesh.VertexBuffer);

            if (mesh.IndexBuffer != null)
            {
                renderQueue.DrawProcedural(mesh.IndexBuffer, modelWorld, material, 0, mesh.Topology, mesh.IndexCount);
            }
            else
            {
                renderQueue.DrawProcedural(modelWorld, material, 0, mesh.Topology, mesh.VertexCount);
            }
        }
Ejemplo n.º 11
0
        protected override void RenderInstances(CameraContext cameraContext, CommandBuffer renderQueue, Mesh mesh,
                                                List <Matrix4x4> transforms, List <Matrix4x4> parentTransforms,
                                                List <CreateMessage> shapes, Material material)
        {
            // Work out which mesh set we are rendering from the parent call: solid or wireframe. We could also look at
            // the first CreateMessage flags.
            Mesh[] meshes =
                (shapes.Count > 0 && (shapes[0].Flags & (ushort)ObjectFlag.Wireframe) != 0)  ? _wireframeMeshes : _solidMeshes;
            CategoriesState categories = this.CategoriesState;

            // Handle instancing block size limits.
            for (int i = 0; i < transforms.Count; i += _instanceTransforms.Length)
            {
                MaterialPropertyBlock materialProperties = new MaterialPropertyBlock();
                int itemCount = 0;
                _instanceColours.Clear();
                for (int j = 0; j < _instanceTransforms.Length && j + i < transforms.Count; ++j)
                {
                    if (categories != null && !categories.IsActive(shapes[i + j].Category))
                    {
                        continue;
                    }

                    // Build the end cap transforms.
                    Matrix4x4 modelToSceneTransform = cameraContext.TesSceneToWorldTransform * parentTransforms[i + j];
                    Matrix4x4 transform             = transforms[i + j];
                    _instanceTransforms[itemCount] = modelToSceneTransform * transform;

                    // Extract radius and length to position the end caps.
                    float   radius = transform.GetColumn(0).magnitude;
                    Vector4 zAxis  = transform.GetColumn(2);
                    float   length = zAxis.magnitude;
                    zAxis *= 1.0f / (length != 0 ? length : 1.0f);
                    // Scale the length axis to match the other two as the end caps are spheres.
                    transform.SetColumn(2, zAxis * radius);

                    // Adjust position for the first end cap.
                    Vector4 tAxis = transform.GetColumn(3);
                    tAxis += -0.5f * length * zAxis;
                    transform.SetColumn(3, tAxis);
                    _cap1Transforms[j] = modelToSceneTransform * transform;

                    // Adjust position for the second end cap.
                    tAxis += length * zAxis;
                    transform.SetColumn(3, tAxis);
                    _cap2Transforms[j] = modelToSceneTransform * transform;

                    Maths.Colour colour = new Maths.Colour(shapes[i + j].Attributes.Colour);
                    _instanceColours.Add(Maths.ColourExt.ToUnityVector4(colour));
                    ++itemCount;
                }

                if (itemCount > 0)
                {
                    materialProperties.SetVectorArray("_Color", _instanceColours);
                    // Render body.
                    renderQueue.DrawMeshInstanced(meshes[0], 0, material, 0, _instanceTransforms, itemCount, materialProperties);
                    // Render end caps.
                    renderQueue.DrawMeshInstanced(meshes[1], 0, material, 0, _cap1Transforms, itemCount, materialProperties);
                    renderQueue.DrawMeshInstanced(meshes[2], 0, material, 0, _cap2Transforms, itemCount, materialProperties);
                }
            }
        }
Ejemplo n.º 12
0
        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);
            }
        }