7

I have been banging my head against this problem for hours now. What I want to do is draw a cube, with different textures on each side; or more specifically, I want to be able to specify whatever texture I want per side. I used the example here to start with, and then attempted to develop it further, so I could have more than one texture. However, no matter what I do, it still only uses the last texture that is applied to the effect, and pays no heed to any previous assignments. Here is my shape class:

public class BasicShape {

 public Vector3 shapeSize;
 public Vector3 shapePosition;
 private VertexPositionNormalTexture[][] shapeVertices;
 private int shapeTriangles;
 private VertexBuffer shapeBuffer;
 public Texture2D topTexture;
 public Texture2D frontTexture;
 public Texture2D backTexture;
 public Texture2D leftTexture;
 public Texture2D rightTexture;
 public Texture2D bottomTexture;

 public BasicShape(Vector3 size, Vector3 position) {
    shapeSize = size;
    shapePosition = position;
 }

 private void BuildShape() {
    shapeTriangles = 12;

    shapeVertices = new VertexPositionNormalTexture[6][];
    for(int i = 0; i < 6; i++) {
        shapeVertices[i] = new VertexPositionNormalTexture[6];
    }

    Vector3 topLeftFront = shapePosition +
     new Vector3(0.0f, 1.0f, 0.0f) * shapeSize;
    Vector3 bottomLeftFront = shapePosition +
     new Vector3(0.0f, 0.0f, 0.0f) * shapeSize;
    Vector3 topRightFront = shapePosition +
     new Vector3(1.0f, 1.0f, 0.0f) * shapeSize;
    Vector3 bottomRightFront = shapePosition +
     new Vector3(1.0f, 0.0f, 0.0f) * shapeSize;
    Vector3 topLeftBack = shapePosition +
     new Vector3(0.0f, 1.0f, 1.0f) * shapeSize;
    Vector3 topRightBack = shapePosition +
     new Vector3(1.0f, 1.0f, 1.0f) * shapeSize;
    Vector3 bottomLeftBack = shapePosition +
     new Vector3(0.0f, 0.0f, 1.0f) * shapeSize;
    Vector3 bottomRightBack = shapePosition +
     new Vector3(1.0f, 0.0f, 1.0f) * shapeSize;

    Vector3 topLeftFront2 = shapePosition +
     new Vector3(0.0f, 1.0f, 0.0f) * shapeSize;
    Vector3 bottomLeftFront2 = shapePosition +
     new Vector3(0.0f, 0.0f, 0.0f) * shapeSize;
    Vector3 topRightFront2 = shapePosition +
     new Vector3(1.0f, 1.0f, 0.0f) * shapeSize;
    Vector3 bottomRightFront2 = shapePosition +
     new Vector3(1.0f, 0.0f, 0.0f) * shapeSize;
    Vector3 topLeftBack2 = shapePosition +
     new Vector3(0.0f, 1.0f, 1.0f) * shapeSize;
    Vector3 topRightBack2 = shapePosition +
     new Vector3(1.0f, 1.0f, 1.0f) * shapeSize;
    Vector3 bottomLeftBack2 = shapePosition +
     new Vector3(0.0f, 0.0f, 1.0f) * shapeSize;
    Vector3 bottomRightBack2 = shapePosition +
     new Vector3(1.0f, 0.0f, 1.0f) * shapeSize;

    Vector3 topLeftFront3 = shapePosition +
     new Vector3(0.0f, 1.0f, 0.0f) * shapeSize;
    Vector3 bottomLeftFront3 = shapePosition +
     new Vector3(0.0f, 0.0f, 0.0f) * shapeSize;
    Vector3 topRightFront3 = shapePosition +
     new Vector3(1.0f, 1.0f, 0.0f) * shapeSize;
    Vector3 bottomRightFront3 = shapePosition +
     new Vector3(1.0f, 0.0f, 0.0f) * shapeSize;
    Vector3 topLeftBack3 = shapePosition +
     new Vector3(0.0f, 1.0f, 1.0f) * shapeSize;
    Vector3 topRightBack3 = shapePosition +
     new Vector3(1.0f, 1.0f, 1.0f) * shapeSize;
    Vector3 bottomLeftBack3 = shapePosition +
     new Vector3(0.0f, 0.0f, 1.0f) * shapeSize;
    Vector3 bottomRightBack3 = shapePosition +
     new Vector3(1.0f, 0.0f, 1.0f) * shapeSize;

    Vector3 frontNormal = new Vector3(0.0f, 0.0f, 1.0f) * shapeSize;
    Vector3 backNormal = new Vector3(0.0f, 0.0f, -1.0f) * shapeSize;
    Vector3 topNormal = new Vector3(0.0f, 1.0f, 0.0f) * shapeSize;
    Vector3 bottomNormal = new Vector3(0.0f, -1.0f, 0.0f) * shapeSize;
    Vector3 leftNormal = new Vector3(-1.0f, 0.0f, 0.0f) * shapeSize;
    Vector3 rightNormal = new Vector3(1.0f, 0.0f, 0.0f) * shapeSize;

    Vector2 textureTopLeft = new Vector2(1f * shapeSize.X, 0.0f * shapeSize.Y);
    Vector2 textureTopRight = new Vector2(0.0f * shapeSize.X, 0.0f * shapeSize.Y);
    Vector2 textureBottomLeft = new Vector2(1f * shapeSize.X, 1f * shapeSize.Y);
    Vector2 textureBottomRight = new Vector2(0.0f * shapeSize.X, 1f * shapeSize.Y);

    // Front face.
    shapeVertices[0][0] = new VertexPositionNormalTexture(
     topLeftFront, frontNormal, textureTopLeft);
    shapeVertices[0][1] = new VertexPositionNormalTexture(
     bottomLeftFront, frontNormal, textureBottomLeft);
    shapeVertices[0][2] = new VertexPositionNormalTexture(
     topRightFront, frontNormal, textureTopRight);
    shapeVertices[0][3] = new VertexPositionNormalTexture(
     bottomLeftFront, frontNormal, textureBottomLeft);
    shapeVertices[0][4] = new VertexPositionNormalTexture(
     bottomRightFront, frontNormal, textureBottomRight);
    shapeVertices[0][5] = new VertexPositionNormalTexture(
     topRightFront, frontNormal, textureTopRight);

    // Back face.
    shapeVertices[1][0] = new VertexPositionNormalTexture(
     topLeftBack, backNormal, textureTopRight);
    shapeVertices[1][1] = new VertexPositionNormalTexture(
     topRightBack, backNormal, textureTopLeft);
    shapeVertices[1][2] = new VertexPositionNormalTexture(
     bottomLeftBack, backNormal, textureBottomRight);
    shapeVertices[1][3] = new VertexPositionNormalTexture(
     bottomLeftBack, backNormal, textureBottomRight);
    shapeVertices[1][4] = new VertexPositionNormalTexture(
     topRightBack, backNormal, textureTopLeft);
    shapeVertices[1][5] = new VertexPositionNormalTexture(
     bottomRightBack, backNormal, textureBottomLeft);

    // Top face.
    shapeVertices[2][0] = new VertexPositionNormalTexture(
     topLeftFront2, topNormal, textureBottomLeft);
    shapeVertices[2][1] = new VertexPositionNormalTexture(
     topRightBack2, topNormal, textureTopRight);
    shapeVertices[2][2] = new VertexPositionNormalTexture(
     topLeftBack2, topNormal, textureTopLeft);
    shapeVertices[2][3] = new VertexPositionNormalTexture(
     topLeftFront2, topNormal, textureBottomLeft);
    shapeVertices[2][4] = new VertexPositionNormalTexture(
     topRightFront2, topNormal, textureBottomRight);
    shapeVertices[2][5] = new VertexPositionNormalTexture(
     topRightBack2, topNormal, textureTopRight);

    // Bottom face.
    shapeVertices[3][0] = new VertexPositionNormalTexture(
     bottomLeftFront2, bottomNormal, textureTopLeft);
    shapeVertices[3][1] = new VertexPositionNormalTexture(
     bottomLeftBack2, bottomNormal, textureBottomLeft);
    shapeVertices[3][2] = new VertexPositionNormalTexture(
     bottomRightBack2, bottomNormal, textureBottomRight);
    shapeVertices[3][3] = new VertexPositionNormalTexture(
     bottomLeftFront2, bottomNormal, textureTopLeft);
    shapeVertices[3][4] = new VertexPositionNormalTexture(
     bottomRightBack2, bottomNormal, textureBottomRight);
    shapeVertices[3][5] = new VertexPositionNormalTexture(
     bottomRightFront2, bottomNormal, textureTopRight);

    // Left face.
    shapeVertices[4][0] = new VertexPositionNormalTexture(
     topLeftFront3, leftNormal, textureTopRight);
    shapeVertices[4][1] = new VertexPositionNormalTexture(
     bottomLeftBack3, leftNormal, textureBottomLeft);
    shapeVertices[4][2] = new VertexPositionNormalTexture(
     bottomLeftFront3, leftNormal, textureBottomRight);
    shapeVertices[4][3] = new VertexPositionNormalTexture(
     topLeftBack3, leftNormal, textureTopLeft);
    shapeVertices[4][4] = new VertexPositionNormalTexture(
     bottomLeftBack3, leftNormal, textureBottomLeft);
    shapeVertices[4][5] = new VertexPositionNormalTexture(
     topLeftFront3, leftNormal, textureTopRight);

    // Right face.
    shapeVertices[5][0] = new VertexPositionNormalTexture(
     topRightFront3, rightNormal, textureTopLeft);
    shapeVertices[5][1] = new VertexPositionNormalTexture(
     bottomRightFront3, rightNormal, textureBottomLeft);
    shapeVertices[5][2] = new VertexPositionNormalTexture(
     bottomRightBack3, rightNormal, textureBottomRight);
    shapeVertices[5][3] = new VertexPositionNormalTexture(
     topRightBack3, rightNormal, textureTopRight);
    shapeVertices[5][4] = new VertexPositionNormalTexture(
     topRightFront3, rightNormal, textureTopLeft);
    shapeVertices[5][5] = new VertexPositionNormalTexture(
     bottomRightBack3, rightNormal, textureBottomRight);
 }

 public void SetTopTexture(Texture2D tex) {
    topTexture = tex;
 }
 public void SetSideTexture(Texture2D tex) {
    frontTexture = tex;
    backTexture = tex;
    leftTexture = tex;
    rightTexture = tex;
 }
 public void SetBottomTexture(Texture2D tex) {
    bottomTexture = tex;
 }

 public void RenderShape(GraphicsDevice device, Effect effect) {
    BuildShape();


    effect.Parameters["xTexture"].SetValue(topTexture);
    device.DrawUserPrimitives(PrimitiveType.TriangleList, shapeVertices[2], 0, 2);
    effect.Parameters["xTexture"].SetValue(bottomTexture);
    device.DrawUserPrimitives(PrimitiveType.TriangleList, shapeVertices[3], 0, 2);
    effect.Parameters["xTexture"].SetValue(frontTexture);
    device.DrawUserPrimitives(PrimitiveType.TriangleList, shapeVertices[0], 0, 2);
    effect.Parameters["xTexture"].SetValue(backTexture);
    device.DrawUserPrimitives(PrimitiveType.TriangleList, shapeVertices[1], 0, 2);
    effect.Parameters["xTexture"].SetValue(leftTexture);
    device.DrawUserPrimitives(PrimitiveType.TriangleList, shapeVertices[4], 0, 2);
    effect.Parameters["xTexture"].SetValue(rightTexture);
    device.DrawUserPrimitives(PrimitiveType.TriangleList, shapeVertices[5], 0, 2);

 }

}

And in the Draw method for my game:

cubeEffect.CurrentTechnique = cubeEffect.Techniques["Textured"];
   foreach(EffectPass pass in cubeEffect.CurrentTechnique.Passes) {
      pass.Apply();
      BasicShape s = new BasicShape(new Vector3(1, 1, 1), new Vector3(0, 0, 3));
      s.SetTopTexture(TextureLoader.GetTexture(4));
      s.SetSideTexture(TextureLoader.GetTexture(35));
      s.SetBottomTexture(TextureLoader.GetTexture(4));
      s.RenderShape(GraphicsDevice, cubeEffect);   

  }

As you can see, I am loading different textures, yet the result is this:

my cube http://www.tinyimg.org/images/769MinecraftClassic_2011_.bmp

I am sure that the textures are different, yet the same texture gets drawn on all sides. Do I need a separate effect for each side? That definitely seems like overkill.

3
  • Have you verified that TextureLoader.GetTexture(35) is returning what you expect it to return? Commented Jan 12, 2011 at 22:44
  • @ChrisF - Well, texture 35 is the only texture showing, so I assume that it is. Also, if I take the first two rows of the draw code in RenderShape and put it at the end, it renders texture 4. So it is only rendering the last applied texture. Commented Jan 12, 2011 at 22:48
  • That seems like useful information that you should include in your question. I can't help with the answer though - I'm not that familiar with xna. Commented Jan 12, 2011 at 22:51

1 Answer 1

6

Any parameters set on the effect aren't applied until you call EffectPass.Apply(). This is because applying changes to an effect is expensive and you might want to perform multiple changes in one go.

Your RenderShape function should look something like:

public void RenderShape(GraphicsDevice device, Effect effect)
{
    BuildShape();

    foreach (EffectPass pass in effect.CurrentTechnique.Passes)
    {
        effect.Parameters["xTexture"].SetValue(topTexture);
        pass.Apply();
        device.DrawUserPrimitives(PrimitiveType.TriangleList, shapeVertices[2], 0, 2);

        effect.Parameters["xTexture"].SetValue(bottomTexture);
        pass.Apply();
        device.DrawUserPrimitives(PrimitiveType.TriangleList, shapeVertices[3], 0, 2);

        effect.Parameters["xTexture"].SetValue(frontTexture);
        pass.Apply();
        device.DrawUserPrimitives(PrimitiveType.TriangleList, shapeVertices[0], 0, 2);

        effect.Parameters["xTexture"].SetValue(backTexture);
        pass.Apply();
        device.DrawUserPrimitives(PrimitiveType.TriangleList, shapeVertices[1], 0, 2);

        effect.Parameters["xTexture"].SetValue(leftTexture);
        pass.Apply();
        device.DrawUserPrimitives(PrimitiveType.TriangleList, shapeVertices[4], 0, 2);

        effect.Parameters["xTexture"].SetValue(rightTexture);
        pass.Apply();
        device.DrawUserPrimitives(PrimitiveType.TriangleList, shapeVertices[5], 0, 2);
    }
}
Sign up to request clarification or add additional context in comments.

8 Comments

@Empyrean - So, are you saying that this is not the recommended way of doing it? What would be a faster way? I'm going to have to draw a lot of these cubes, so I need to optimize it as much as possible.
You can usually only make a few hundred state changes (called batches) before you run into performance problems. In your code, the rendering of each cube consists of 6 batches. That means you'll probably be able to render less than 100 cubes before your framerate starts to get unacceptable. You want as few draw calls as possible so draw all cube faces with the same texture in one draw call. Better yet combine your six texture into a single texture (texture atlasing). Also vertex buffers are much faster on PC than DrawUserPrimitive calls.
The fastest way would be to use texture atlasing and render all cubes in one call using either at static or dynamic vertex buffer depending on whether or not your cubes move or not. If some of them don't move, use a static vertex buffer for those and a dynamic vertex buffer for the ones that do. You should also use indexes to avoid using duplicate vertices. Duplicate vertices have to both be transformed and they may transform slightly differently giving seams in your meshes.
Additionally, duplicate vertices have to be transformed, sent through buses and will take up space in the cache, all which will reduce your performance.
@Empyrean - How would I go about with the atlasing? Do I use the texture coordinates for the vertices for that? So I need to find the coordinates for each texture on a large texture map?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.