Table of Contents


Hey, all. I know I’m certainly not the first to accomplish this (David Winter’s been doing it a while with his player uniforms), but I figured I’d go ahead and post a code sample that will paint texture layers one on top of the other on a render surface, then bake them out to a texture, ready to be applied to your friendly neighborhood uniform, character model, vehicle, or what have you.

The code will allow you to add each texture layer with:

  • An overall opacity (excellent for gradual changes like bruises, facial hair growth, or molding bread!)
  • Each texture’s alpha information, as well as an optional alpha mask
  • A color tint (great for adding color to greyscale textures, good for team uniform colors, skin tones, or the color of your facial hair)

The system works just as well for baking out multi-layered normal maps, too: very useful for adding dents to vehicles, or wrinkles to faces! Just remember to normalize your normal map after baking it all down! And although I haven’t really done anything with it, I’m perfectly sure that this would work fine for changing specular maps (adding sweat/blood), bump maps, and alpha maps.


Public Class texBaker
    'Dimensions used to store the width and height of the render surface we'll be painting to
    Private bakeWidth As Integer
    Private bakeHeight As Integer
    'Each texture we want to bake on will be stored in a layer, and will be painted in the order it's added
    Private Structure bakeLayers
        Dim texID As Integer
        Dim texAlpha As Single
        Dim texColor As MTV3D65.TV_3DVECTOR
        Dim hasMask As Boolean
        Dim maskID As Integer
    End Structure
    Private bakeLayer() As bakeLayers
    Private iLayers As Integer

    'Before we start baking, we initialize our values and clear our layers
    Public Sub begin(ByVal width As Integer, ByVal height As Integer)
        bakeWidth = width
        bakeHeight = height
        iLayers = -1
        ReDim bakeLayer(0)
    End Sub

    'As the user adds each layer, we create a new layer and fill it with the appropriate information
    Public Sub addLayer(ByVal textureID As Integer, ByVal textureAlpha As Single, ByVal texturecolor As MTV3D65.TV_3DVECTOR, Optional ByVal maskID As Integer = -1)
        iLayers += 1
        ReDim Preserve bakeLayer(iLayers)
        bakeLayer(iLayers).texID = textureID
        bakeLayer(iLayers).texAlpha = textureAlpha
        bakeLayer(iLayers).texColor = texturecolor
        bakeLayer(iLayers).maskID = maskID
    End Sub

    Public Function bake(Optional ByVal bakedTextureName As String = "") As Integer
        'When the user is ready to bake out a texture, we make sure there are layers ready to be baked, then...
        If iLayers > -1 Then
            'We create our render surface and begin painting on each layer
            Dim bakeSurface As New MTV3D65.TVRenderSurface
            bakeSurface = tvSCENE.CreateRenderSurface(bakeWidth, bakeHeight)
            Dim i
            For i = 0 To iLayers
                'If a layer has a mask assigned to it, we take the diffuse texture and add an alpha channel to it
                If bakeLayer(i).maskID <> -1 Then
                    bakeLayer(i).texID = tvTEXTURES.AddAlphaChannel(bakeLayer(i).texID, bakeLayer(i).maskID, "Fex's texBaker's temporary alpha'd texture")
                End If
                'We paint on each layer with the appropriate color and opacity
                tvSCREEN.Draw_Texture(bakeLayer(i).texID, 0, 0, bakeWidth - 1, bakeHeight - 1, tvGLOBALS.RGBA(bakeLayer(i).texColor.x, bakeLayer(i).texColor.y, bakeLayer(i).texColor.z, bakeLayer(i).texAlpha), tvGLOBALS.RGBA(bakeLayer(i).texColor.x, bakeLayer(i).texColor.y, bakeLayer(i).texColor.z, bakeLayer(i).texAlpha), tvGLOBALS.RGBA(bakeLayer(i).texColor.x, bakeLayer(i).texColor.y, bakeLayer(i).texColor.z, bakeLayer(i).texAlpha), tvGLOBALS.RGBA(bakeLayer(i).texColor.x, bakeLayer(i).texColor.y, bakeLayer(i).texColor.z, bakeLayer(i).texAlpha))
                'If we created a new texture with an alpha channel just a second ago, we clean it up here
                If bakeLayer(i).maskID <> -1 Then
                    tvTEXTURES.DeleteTexture(tvGLOBALS.GetTex("texBaker's temporary alpha'd texture"))
                End If
            'Once we're done baking down all of our layers, we save out our baked render surface as a texture
            If tvTEXTURES.TextureExists(bakedTextureName) Then tvTEXTURES.DeleteTexture(tvGLOBALS.GetTex(bakedTextureName))
            bake = bakeSurface.CreateStaticTextureFromRenderSurface(bakeWidth, bakeHeight, MTV3D65.CONST_TV_COLORKEY.TV_COLORKEY_USE_ALPHA_CHANNEL, bakedTextureName)
            'Cleanup time!
        End If
    End Function

End Class

Sample Useage Code

    Public tvBAKER As New texBaker

    'When I change the diffuse map progress bar values:
            tvBAKER.begin(256, 256)
            tvBAKER.addLayer(tvGLOBALS.GetTex("headBase"), 1, vector(1, 1, 1))
            tvBAKER.addLayer(tvGLOBALS.GetTex("facialHair"), ProgressBar1.Value / 100, vector(60 / 256, 40 / 256, 35 / 256), tvGLOBALS.GetTex("facialHairMask"))
            testHead.SetTexture(tvBAKER.bake("bakedDiffuseTexture"), 0)

    'When I change the normal map progress bar values:
            tvBAKER.begin(256, 256)
            tvBAKER.addLayer(tvGLOBALS.GetTex("headNormal"), 1, vector(1, 1, 1))
            tvBAKER.addLayer(tvGLOBALS.GetTex("wrinkleNormal"), ProgressBar2.Value / 100, vector(1, 1, 1))
            testHead.SetTextureEx(MTV3D65.CONST_TV_LAYER.TV_LAYER_NORMALMAP, tvBAKER.bake("bakedNormalTexture"), 0)
sta_source/texbaker.txt · Last modified: 2013/11/22 13:32