1
\$\begingroup\$

It's difficult to ask this, but I'll try. The thing is: I asked before somethings about creating ramps and blocks with vertexes. [I'm using C#/XNA.]


Explanation: now I got a chunk that has blocks wherever I want, that automatically change "stairs" into ramps. And I love it and I thank all the people that helped me out! But I don't know how to texture it appropriately.

I could add a Texture Atlas and set the coordinates of each texture (I found the example at a project called "TechCraft Engine"), but I'd like to create separate PNG files for each texture, 'cause I'll use transparency later and I'd like that textures can be loaded during game runtime.

I'm newbie in programming, but I'm searching for solutions. All that I got for now is that I have a custom effect (FX file) created that changes colors for each time of the day. But it only has a slot for one texture file loaded. And I still can't implement it because of that.

I can't add more texture samplers to the effect 'cause it can't be done at game runtime (or can it?)

I'm using the VertexBuffers and IndexBuffers, with TriangleList primitive. For now, I can only draw with colors, without textures.

Later in my game I would like that custom textures could be added and placed on some of the block's faces. A example for this can be found in The Sims 3. There you can add textures to the game and paint the walls and objects with it. It's something like that I'd like to create, but with a loader while playing.


My question is: should I create a VertexBuffer and a IndexBuffer for each texture and separate the vertexes with each texture between them, creating a List of VertexBuffer and IndexBuffer for placing each?... Then I could draw all the vertexes of one texture at a time, change the effect's texture parameter with a different one (call the pass technique again), and set the graphics device again with the next VertexBuffer and IndexBuffer of the list, for drawing it with the TriangleList primitive.

I'd repeat it for each texture loaded. Does it work or is there any other way to do it?

Should I forget about runtime loading for now, for finding a easier solution?

I'm pretty messed with this, do you have any suggestions? Any information will help. Thank you!

\$\endgroup\$
  • 1
    \$\begingroup\$ A full cube side is made of two triangles, and ramp cube side is made of one triangle. Isn't that one triangle textured appropriately already? \$\endgroup\$ – MichaelHouse Sep 20 '14 at 4:50
  • \$\begingroup\$ I'm using VertexPositionColor. So I can't add textures yet. Im changing to a new IVertex type. But can I use more than one VertexBuffer and IndexBuffer? I'm going to create one for each texture. \$\endgroup\$ – Arthur 'Gibraltar' Condino Sep 20 '14 at 19:32
  • \$\begingroup\$ I'm testing somethings. I'm trying now to use ConcurrentDictionary<string, List<IVertexType>> and ConcurrentDictionary<string, VertexBuffer> with ConcurrentDictionary<string, IndexBuffer>. Then for each key I'll set the effect with a new Texture2D and set the graphics device for drawing. Let's see what happens... It takes time to convert a function to a new one... \$\endgroup\$ – Arthur 'Gibraltar' Condino Sep 20 '14 at 20:40
  • \$\begingroup\$ I tested and that does work, but I need to optimize... And I have a problem with the chunks, I always get System.OutOfMemory with the block list... Messy. If I can get it to work smoothly, I'll post some code parts as answer. If not, then I don't have an answer. [EDIT: I dream one day I'll be able to paint walls, like I could do in The Sims.. <3] \$\endgroup\$ – Arthur 'Gibraltar' Condino Sep 21 '14 at 19:34
  • \$\begingroup\$ you can use more than one vertex buffer but not index buffer \$\endgroup\$ – RadioSpace Sep 23 '14 at 18:20
0
\$\begingroup\$

Ok, I found a solution to my problem: ConcurrentDictionary of string, VertexBuffer, ConcurrentDictionary of string, IndexBuffer and ConcurrentDictionary of string, Texture2D.

With them, I can create each VertexBuffer and IndexBuffer for a texture name stored in a string.

Then I can easily access all data I need: loading a Texture 2D, setting a name for it and setting a block to use it.

First I create each VertexBuffer and IndexBuffer for each block type in the map, storing in the ConcurrentDictionary the block's texture name as the string parameter and the data created.

When the drawing function comes, I check every VertexBuffer in the ConcurrentDictionary and decide which texture to use using its name, then get the IndexBuffer and Texture2D for it from each ConcurrentDictionary.

I'll provide more details later, if I can edit the post.

Edit: here are my codes:

First, in my content loader, I make the texture be detected and added to a ConcurrentDictionary in another class:

                dynamic XNAobject = Game.Content.Load<dynamic>(path);
                // [...]

                else if (XNAobject is Texture2D && path.Contains("Terrain") && path.EndsWith("Atlas")) {
                    Console.WriteLine(this + " adicionando textura de terreno");
                    TextureManager.AddTerrainTexture((Texture2D)XNAobject, path);
                }

Here's the class that contains the ConcurrentDictionary.

    #region Texturas do Terreno
    /// <summary>
    ///  Todas as texturas carregadas, classificadas pelo caminho do arquivo (Tag).
    /// </summary>
    internal static ConcurrentDictionary<string, Texture2D> TerrainTextures = new ConcurrentDictionary<string, Texture2D>();
    #endregion
    #endregion

    #region Adicionar Textura
    internal static void AddTerrainTexture(Texture2D texture2DAtlas, object tag) {
        texture2DAtlas.Tag = tag;
        if (!(tag is string)) { return; }
        string stringTag = (string)tag;
        string texture2DName = stringTag.Substring(stringTag.LastIndexOf("\\") + 1, (stringTag.LastIndexOf("Atlas")) - (stringTag.LastIndexOf("\\") + 1));
        //Debug.WriteLine("textura 2D adicionada: " + texture2DName);

        Texture2D oldValue;
        texture2DAtlas.Name = texture2DName;
        if (!TerrainTextures.TryGetValue(texture2DName, out oldValue)) { TerrainTextures.TryAdd(texture2DName, texture2DAtlas); }
    }
    #endregion

Here's the process of creating and saving the buffers for each texture. But I didn't show here the vertex creation still.

        //  Criar buffers.
        #region Buffers
        lock (chunk) {

            chunk.IndexBuffers.Clear(); chunk.VertexBuffers.Clear(); 

            //  Adquirir dados finais do chunk.
            foreach (var list in chunk.Vertexes) { string textureName = list.Key;
                IVertexType[] vertexes = list.Value.ToArray();

                short[] indexes = chunk.Indexes[textureName].ToArray();

                if (vertexes.Length > 0) {
                    ////  Buffer de vértices.
                    chunk.VertexBuffers.TryAdd(textureName,
                        new VertexBuffer(GraphicsDevice, typeof(VertexPositionNormalTextureLight), vertexes.Length, BufferUsage.WriteOnly));

                    //  Converter para o tipo.
                    VertexPositionNormalTextureLight[] vertexesConverted = new VertexPositionNormalTextureLight[vertexes.Length];
                    for (int i = 0; i < vertexes.Length; i ++) {
                        vertexesConverted[i] = (VertexPositionNormalTextureLight)vertexes[i];
                    }

                    chunk.VertexBuffers[textureName].SetData(vertexesConverted);

                    //  Buffer de índices.
                    chunk.IndexBuffers.TryAdd(textureName, 
                        new IndexBuffer(GraphicsDevice, IndexElementSize.SixteenBits, indexes.Length, BufferUsage.WriteOnly));

                    chunk.IndexBuffers[textureName].SetData(indexes);
                }
            }

            chunk.NeedsBuild = false;
        }
        #endregion

And some of the chunk data needed for the buffers:

    #region Vértices
    /// <summary>
    ///  Listas de todos os vértices do chunk, para serem desenhados.
    /// </summary>
    public ConcurrentDictionary<string, List<IVertexType>> Vertexes = 
        new ConcurrentDictionary<string, List<IVertexType>>();

    public ConcurrentDictionary<string, short> VertexCounts = new ConcurrentDictionary<string, short>();

    /// <summary>
    ///  Listas de todos os índices para a ordem de vértices neste chunk.
    /// </summary>
    public ConcurrentDictionary<string, List<short>> Indexes = 
        new ConcurrentDictionary<string, List<short>>();
    #endregion

    #region Buffers
    /// <summary>
    ///  Lista de Buffers de vértices dos blocos do chunk.
    ///  Cada buffer pode ser usado para aplicar determinado efeito.
    /// </summary>
    public ConcurrentDictionary<string, VertexBuffer> VertexBuffers = new ConcurrentDictionary<string, VertexBuffer>();

    /// <summary>
    ///  Lista de Buffers de índices do chunk.
    /// </summary>
    public ConcurrentDictionary<string, IndexBuffer> IndexBuffers = new ConcurrentDictionary<string, IndexBuffer>();
    #endregion

Then, after building a VertexBuffer and a IndexBuffer for each texture, and saving in a ConcurrentDictionary with the texture's name, I can access it by the texture's name and draw it:

                    lock (chunk) { 
                        //  Desenhar vértices dos blocos, com as texturas para eles.
                        foreach (var list in chunk.VertexBuffers) { string textureName = list.Key;
                            Texture2D texture; 
                            if (TextureManager.TerrainTextures.TryGetValue(textureName, out texture)) {
                                //  Colocar a textura selecionada da lista.
                                TextureManager.DynamicTexturingEffect.Parameters["Texture1"].SetValue(texture);
                                //Debug.WriteLine(texture.Name);

                                //  Ativar as opções de efeito para o dispositivo gráfico e desenhar com elas.
                                foreach (EffectPass pass in TextureManager.DynamicTexturingEffect.CurrentTechnique.Passes) {
                                    pass.Apply();

                                    VertexBuffer vertexBuffer; IndexBuffer indexBuffer;
                                    if (chunk.IndexBuffers.TryGetValue(textureName, out indexBuffer) && chunk.VertexBuffers.TryGetValue(textureName, out vertexBuffer)) {
                                        if (indexBuffer.IndexCount > 0) { 
                                            lock (GraphicsDevice) { 
                                                GraphicsDevice.SetVertexBuffer(vertexBuffer);
                                                GraphicsDevice.Indices = indexBuffer;
                                                GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, vertexBuffer.VertexCount, 0, indexBuffer.IndexCount / 3);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.