Stride Forums Archive

[Solved] Script-generated model invisible

5 posts, 1972 views, 2016-08-05 to 2016-08-06

Nicogo (Goosse Nicolas) 2016-08-05 #1

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:

xen2 (Virgile) 2016-08-06 #2

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!

Nicogo (Goosse Nicolas) 2016-08-06 #3 in reply to #2

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”.

Kryptos (Nicolas Musset) 2016-08-06 #4

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)
Nicogo (Goosse Nicolas) 2016-08-06 #5 in reply to #4

Thanks it work fine :slight_smile: