[Solved] Script-generated model invisible

Hi :slight_smile: ,

I have made a script that generate a sphere and should draw it but when I debug, Nothing…
I can’t find where is the problem, some help would be really apreciated.
I have written it by following the Terrain Sample.

using System;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using SiliconStudio.Core.Mathematics;
using SiliconStudio.Xenko.Engine;
using SiliconStudio.Xenko.Rendering;
using SiliconStudio.Xenko.Graphics;

namespace VoxelTerrain
{

    public class Planet : StartupScript
    {

        public float radius { get; set; } = 5f;
        public int slices { get; set; } = 10;
        public int stacks { get; set; } = 10;

        public override void Start()
        {
            // Calcul BufferSizes
            var vertexDeclaration = VertexNormalTexture.VertexDeclaration;

            int PlanetVerticesPerRow = slices + 1;
            int PlanetVerticesPerColumn = stacks + 1;
            int PlanetVerticesCount = PlanetVerticesPerRow * PlanetVerticesPerColumn;

            int PlanetIndicesCount = slices * stacks * 6;

            var PlanetVertexBufferSize = PlanetVerticesCount * vertexDeclaration.CalculateSize();
            var PlanetIndexBufferSize = PlanetIndicesCount * sizeof(short);

            var PlanetVertexBuffer = SiliconStudio.Xenko.Graphics.Buffer.Vertex.New(GraphicsDevice, PlanetVertexBufferSize, GraphicsResourceUsage.Dynamic);
            var PlanetIndexBuffer = SiliconStudio.Xenko.Graphics.Buffer.New(GraphicsDevice, PlanetIndexBufferSize, BufferFlags.IndexBuffer, GraphicsResourceUsage.Dynamic);

            var commandList = Game.GraphicsContext.CommandList;

            // Set data in VertexBuffer
            var mappedSubResource = commandList.MapSubresource(PlanetVertexBuffer, 0, MapMode.WriteDiscard);
            SetVertexData(radius, stacks, slices, PlanetVerticesPerColumn, PlanetVerticesPerRow, mappedSubResource.DataBox.DataPointer);
            commandList.UnmapSubresource(mappedSubResource);

            // Set data in IndexBuffer
            mappedSubResource = commandList.MapSubresource(PlanetIndexBuffer, 0, MapMode.WriteDiscard);
            var elementCount = SetIndexData(stacks, slices, PlanetVerticesPerRow, mappedSubResource.DataBox.DataPointer);
            commandList.UnmapSubresource(mappedSubResource);

            //Creating Mesh
            var meshDraw = new MeshDraw
            {
                PrimitiveType = PrimitiveType.TriangleList,
                VertexBuffers = new[] { new VertexBufferBinding(PlanetVertexBuffer, vertexDeclaration, PlanetVerticesCount) },
                IndexBuffer = new IndexBufferBinding(PlanetIndexBuffer, false, PlanetIndicesCount),
                DrawCount = elementCount,
            };

            var Planet = new Mesh();
            Planet.Draw = meshDraw;

            Entity.GetOrCreate<ModelComponent>().Model = new Model { Planet };
        }

        private static unsafe void SetVertexData(float radius, int stacks, int slices, int PlanetVerticesPerColumn, int PlanetVectricesPerRow, IntPtr vertexBuffer)
        {
            var vb = (VertexNormalTexture*)vertexBuffer;
            var currentIndex = 0;

            float theta = 0.0f;
            float phi = 0.0f;

            float verticalAngularStride = (float)Math.PI / (float)stacks;
            float horizontalAngularStride = ((float)Math.PI * 2) / (float)slices;

            for (int verticalIt = 0; verticalIt < PlanetVerticesPerColumn; verticalIt++)
            {
                // beginning on top of the sphere:
                theta = ((float)Math.PI / 2.0f) - verticalAngularStride * verticalIt;

                for (int horizontalIt = 0; horizontalIt < PlanetVectricesPerRow; horizontalIt++)
                {
                    phi = horizontalAngularStride * horizontalIt;

                    // position
                    float x = radius * (float)Math.Cos(theta) * (float)Math.Cos(phi);
                    float y = radius * (float)Math.Cos(theta) * (float)Math.Sin(phi);
                    float z = radius * (float)Math.Sin(theta);

                    VertexNormalTexture position = new VertexNormalTexture { Position = new Vector4(x, z, y, 0) };
                    vb[currentIndex++] = position;
                }
            }
        }

        private static unsafe int SetIndexData(int stacks, int slices, int PlanetVerticesPerRow, IntPtr indexBuffer)
        {
            var ib = (short*)indexBuffer;
            var currentIndex = 0;
            for (int verticalIt = 0; verticalIt < stacks; verticalIt++)
            {
                for (int horizontalIt = 0; horizontalIt < slices; horizontalIt++)
                {
                    short lt = (short)(horizontalIt + verticalIt * (PlanetVerticesPerRow));
                    short rt = (short)((horizontalIt + 1) + verticalIt * (PlanetVerticesPerRow));

                    short lb = (short)(horizontalIt + (verticalIt + 1) * (PlanetVerticesPerRow));
                    short rb = (short)((horizontalIt + 1) + (verticalIt + 1) * (PlanetVerticesPerRow));

                    ib[currentIndex++] = (lt);
                    ib[currentIndex++] = (rt);
                    ib[currentIndex++] = (lb);

                    ib[currentIndex++] = (rt);
                    ib[currentIndex++] = (rb);
                    ib[currentIndex++] = (lb);
                }
            }
            return currentIndex - 1;
        }

    }

    struct VertexNormalTexture
    {
        /// <summary>
        /// Gets a declaration of Vertex attribute which consists of Position::Vector4, Normal::Vector4, TextureCoordinate::Vector2
        /// </summary>
        public static readonly VertexDeclaration VertexDeclaration = new VertexDeclaration(VertexElement.Position<Vector4>(),
            VertexElement.Normal<Vector4>(), VertexElement.TextureCoordinate<Vector2>());

        /// <summary>
        /// Gets or sets a Position of a vertex
        /// </summary>
        public Vector4 Position;

        /// <summary>
        /// Gets or sets a Normal vector of a vertex 
        /// </summary>
        public Vector4 Normal;

        /// <summary>
        /// Gets or sets a texture coordinate of a vertex
        /// </summary>
        public Vector2 TextureCoordinate;
    }

}

Thanks. Sorry for my English :frowning:

You should create and add at least one material to Model.Materials (if material is null, it won’t draw anything)

Let us know if that fixes your problem!

1 Like

Thanks, it work :slight_smile:

using System;
using SiliconStudio.Core.Mathematics;
using SiliconStudio.Xenko.Engine;
using SiliconStudio.Xenko.Rendering;
using SiliconStudio.Xenko.Graphics;

namespace VoxelTerrain
{

    public class Planet : StartupScript
    {

        public float radius { get; set; } = 5f;
        public int slices { get; set; } = 10;
        public int stacks { get; set; } = 10;

        public Material PlanetMaterial;
        private Mesh PlanetMesh;

        public override void Start()
        {
            // Calcul BufferSizes
            var vertexDeclaration = VertexNormalTexture.VertexDeclaration;

            int PlanetVerticesPerRow = slices + 1;
            int PlanetVerticesPerColumn = stacks + 1;
            int PlanetVerticesCount = PlanetVerticesPerRow * PlanetVerticesPerColumn;

            int PlanetIndicesCount = slices * stacks * 6;

            var PlanetVertexBufferSize = PlanetVerticesCount * vertexDeclaration.CalculateSize();
            var PlanetIndexBufferSize = PlanetIndicesCount * sizeof(short);

            var PlanetVertexBuffer = SiliconStudio.Xenko.Graphics.Buffer.Vertex.New(GraphicsDevice, PlanetVertexBufferSize, GraphicsResourceUsage.Dynamic);
            var PlanetIndexBuffer = SiliconStudio.Xenko.Graphics.Buffer.New(GraphicsDevice, PlanetIndexBufferSize, BufferFlags.IndexBuffer, GraphicsResourceUsage.Dynamic);

            //Creating MeshDraw
            var meshDraw = new MeshDraw
            {
                PrimitiveType = PrimitiveType.TriangleList,
                VertexBuffers = new[] { new VertexBufferBinding(PlanetVertexBuffer, vertexDeclaration, PlanetVerticesCount) },
                IndexBuffer = new IndexBufferBinding(PlanetIndexBuffer, false, PlanetIndicesCount),
            };

            //Set MaterialParameters if needed



            //Create Mesh

            PlanetMesh = new Mesh { Draw = meshDraw, MaterialIndex = 0 };
            Entity.GetOrCreate<ModelComponent>().Model = new Model { PlanetMesh, PlanetMaterial };

            var commandList = Game.GraphicsContext.CommandList;

            // Set data in VertexBuffer
            var mappedSubResource = commandList.MapSubresource(PlanetVertexBuffer, 0, MapMode.WriteDiscard);
            SetVertexData(PlanetVerticesPerColumn, PlanetVerticesPerRow, mappedSubResource.DataBox.DataPointer);
            commandList.UnmapSubresource(mappedSubResource);

            // Set data in IndexBuffer
            mappedSubResource = commandList.MapSubresource(PlanetIndexBuffer, 0, MapMode.WriteDiscard);
            var elementCount = SetIndexData(PlanetVerticesPerRow, mappedSubResource.DataBox.DataPointer);
            commandList.UnmapSubresource(mappedSubResource);


            PlanetMesh.Draw.DrawCount = elementCount;
        }

        private unsafe void SetVertexData(int PlanetVerticesPerColumn, int PlanetVectricesPerRow, IntPtr vertexBuffer)
        {
            var vb = (VertexNormalTexture*)vertexBuffer;
            var currentIndex = 0;

            float theta = 0.0f;
            float phi = 0.0f;

            float verticalAngularStride = (float)Math.PI / (float)stacks;
            float horizontalAngularStride = ((float)Math.PI * 2) / (float)slices;

            for (int verticalIt = 0; verticalIt < PlanetVerticesPerColumn; verticalIt++)
            {
                // beginning on top of the sphere:
                theta = ((float)Math.PI / 2.0f) - verticalAngularStride * verticalIt;

                for (int horizontalIt = 0; horizontalIt < PlanetVectricesPerRow; horizontalIt++)
                {
                    phi = horizontalAngularStride * horizontalIt;

                    // position
                    float x = radius * (float)Math.Cos(theta) * (float)Math.Cos(phi);
                    float y = radius * (float)Math.Cos(theta) * (float)Math.Sin(phi);
                    float z = radius * (float)Math.Sin(theta);

                    // normal

                    //What is the Normal ? And why when I remove it from "VertextNormalTexture" the screen is black ?

                    //TextureCoordinate

                    //Why my texturescoordinate seems to not work ? (the first pixel of the texture is painted everywhere)

                    vb[currentIndex++] = new VertexNormalTexture
                    {
                        Position = new Vector4(x, y, z, 1),
                        Normal = new Vector4(0, 0, 0, 0),
                        TextureCoordinate = new Vector2(horizontalIt / PlanetVectricesPerRow, verticalIt / PlanetVerticesPerColumn)
                    };
                }
            }
        }

        private unsafe int SetIndexData(int PlanetVerticesPerRow, IntPtr indexBuffer)
        {
            var ib = (short*)indexBuffer;
            var currentIndex = 0;
            for (int verticalIt = 0; verticalIt < stacks; verticalIt++)
            {
                for (int horizontalIt = 0; horizontalIt < slices; horizontalIt++)
                {
                    short lt = (short)(horizontalIt + verticalIt * (PlanetVerticesPerRow));
                    short rt = (short)((horizontalIt + 1) + verticalIt * (PlanetVerticesPerRow));

                    short lb = (short)(horizontalIt + (verticalIt + 1) * (PlanetVerticesPerRow));
                    short rb = (short)((horizontalIt + 1) + (verticalIt + 1) * (PlanetVerticesPerRow));

                    ib[currentIndex++] = (lt);
                    ib[currentIndex++] = (rt);
                    ib[currentIndex++] = (lb);

                    ib[currentIndex++] = (rt);
                    ib[currentIndex++] = (rb);
                    ib[currentIndex++] = (lb);
                }
            }
            return currentIndex - 1;
        }

    }

    struct VertexNormalTexture
    {
        /// <summary>
        /// Gets a declaration of Vertex attribute which consists of Position::Vector4, Normal::Vector4, TextureCoordinate::Vector2
        /// </summary>
        public static readonly VertexDeclaration VertexDeclaration = new VertexDeclaration(VertexElement.Position<Vector4>(),
            VertexElement.Normal<Vector4>(), VertexElement.TextureCoordinate<Vector2>());

        /// <summary>
        /// Gets or sets a Position of a vertex
        /// </summary>
        public Vector4 Position;

        /// <summary>
        /// Gets or sets a Normal vector of a vertex 
        /// </summary>
        public Vector4 Normal;

        /// <summary>
        /// Gets or sets a texture coordinate of a vertex
        /// </summary>
        public Vector2 TextureCoordinate;
    }

}

But, because i’m new to 3D programming, i have 2 questions :

-What is the Normal (of a point ?) ? And why when I remove it from “VertextNormalTexture” the screen is black ?
-Why my “TexturesCoordinate” seems to not work ? (the first pixel of the texture is painted everywhere)

The material has a Shading diffuse “Texture” and Diffuse model “Lambert”.

You are using int values for horizontalIt and ``PlanetVectricesPerRow so this line

TextureCoordinate = new Vector2(horizontalIt / PlanetVectricesPerRow, verticalIt / PlanetVerticesPerColumn)

will always result in a new Vector2(0, 0). You need to cast at least one value to float:

TextureCoordinate = new Vector2(horizontalIt / (float)PlanetVectricesPerRow, verticalIt / (float)PlanetVerticesPerColumn)
1 Like

Thanks it work fine :slight_smile: