Jump to content

Convert glTF textures to DDS


Josh
 Share

Recommended Posts

This code treats the glTF file as JSON data, finds material textures, and converts them to the correct DDS format, and resaves the JSON data. This is very cool because it does not actually load a model, so glTF textures can be converted to DDS with no other changes. 

function CompressTexture(path, format)
    local k
    local pixmap = LoadPixmap(path)
    if pixmap == nil then return end
    local out = StripExt(path)..".dds"
    local chain2 = {}
    local mipchain = pixmap:BuildMipchain()
    if format == TEXTURE_BC7 or format == TEXTURE_BC6H or format == TEXTURE_BC5 or format == TEXTURE_BC4 then
        for k = 1, #mipchain do
            if mipchain[k].size.x < 4 or mipchain[k].size.y < 4 then break end
            if mipchain[k].format ~= format then
                mipchain[k] = mipchain[k]:Convert(format)
            end
            table.insert(chain2, mipchain[k])
        end
    else
        chain2 = mipchain-- this might not work yet
    end
    return SaveTexture(out, TEXTURE_2D, chain2)
end

function glTFCompressTextures(path)
    local n, k
    local dir = ExtractDir(path)
    if dir ~= "" then dir = dir.."/" end

    --Load glTF as JSON data
    local t = LoadTable(path)
    if type(t) ~= "table" then return false end

    --Check for DDS extension
    if type(t["extensionsUsed"]) == "table" then
        for n = 1, #t["extensionsUsed"] do
            if type(t["extensionsUsed"][n]) == "string" then
                if t["extensionsUsed"][n] == "MSFT_texture_dds" then
                    return false-- DDS textures already exist so return
                end
            end
        end        
    else
        t["extensionsUsed"] = {}
    end
    table.insert(t["extensionsUsed"], "MSFT_texture_dds")
    
    if type(t["materials"]) ~= "table" then
        return false-- glTF file contains no materials
    end
    
    for n = 1, #t["materials"] do

        --Convert normal maps to BC5 DDS
        if type(t["materials"][n]["normalTexture"]) == "table" then            
            if type(t["materials"][n]["normalTexture"]["index"]) == "number" then
                local textureindex = t["materials"][n]["normalTexture"]["index"]
                local imageindex = t["textures"][textureindex + 1]["source"]
                local imagefile = t["images"][imageindex + 1]["uri"]
                CompressTexture(dir..imagefile, TEXTURE_BC5)
            end
        end

        --Convert emissive texture to BC7
        if type(t["materials"][n]["emissiveTexture"]) == "table" then 
            if type(t["materials"][n]["emissiveTexture"]["index"]) == "number" then
                local textureindex = t["materials"][n]["emissiveTexture"]["index"]
                local imageindex = t["textures"][textureindex + 1]["source"]
                local imagefile = t["images"][imageindex + 1]["uri"]
                CompressTexture(dir..imagefile, TEXTURE_BC7)
            end
        end

        if type(t["materials"][n]["pbrMetallicRoughness"]) == "table" then 
            
            --Convert base texture to BC7
            if type(t["materials"][n]["pbrMetallicRoughness"]["baseColorTexture"]) == "table" then
                if type(t["materials"][n]["pbrMetallicRoughness"]["baseColorTexture"]["index"]) == "number" then
                    local textureindex = t["materials"][n]["pbrMetallicRoughness"]["baseColorTexture"]["index"]
                    local imageindex = t["textures"][textureindex + 1]["source"]
                    local imagefile = t["images"][imageindex + 1]["uri"]
                    CompressTexture(dir..imagefile, TEXTURE_BC7)
                end
            end

            local metalroughnesstextureindex = -1

            --Convert metal/roughness texture to BC7
            if type(t["materials"][n]["pbrMetallicRoughness"]["metallicRoughnessTexture"]) == "table" then
                if type(t["materials"][n]["pbrMetallicRoughness"]["metallicRoughnessTexture"]["index"]) == "number" then
                    local textureindex = t["materials"][n]["pbrMetallicRoughness"]["metallicRoughnessTexture"]["index"]
                    local imageindex = t["textures"][textureindex + 1]["source"]
                    local imagefile = t["images"][imageindex + 1]["uri"]
                    CompressTexture(dir..imagefile, TEXTURE_BC7)
                    metalroughnesstextureindex = textureindex
                end
            end

            --Convert AO texture to BC4, unless it is merged with metal/roughness texture
            if type(t["materials"][n]["pbrMetallicRoughness"]["occlusionTexture"]) == "table" then
                if type(t["materials"][n]["pbrMetallicRoughness"]["occlusionTexture"]["index"]) == "number" then
                    local textureindex = t["materials"][n]["pbrMetallicRoughness"]["occlusionTexture"]["index"]
                    if textureindex ~= metalroughnesstextureindex then
                        local imageindex = t["textures"][textureindex + 1]["source"]
                        local imagefile = t["images"][imageindex + 1]["uri"]
                        CompressTexture(dir..imagefile, TEXTURE_BC4)
                    end
                end
            end

        end
    end

    --Add DDS images into image list
    local imagecount = #t["images"]
    for n = 1, imagecount do
        local imagefile = t["images"][n]["uri"]
        local ddsimg = {}
        ddsimg["uri"] = StripExt(imagefile)..".dds"
        table.insert(t["images"], ddsimg)
    end

    --Add DDS images to textures
    for n = 1, #t["textures"] do
        if type(t["textures"][n]["extensions"]) ~= "table" then
            t["textures"][n]["extensions"] = {}
        end
        t["textures"][n]["extensions"]["MSFT_texture_dds"] = {}
        t["textures"][n]["extensions"]["MSFT_texture_dds"]["source"] = imagecount + n - 1
    end

    --Save JSON data as glTF
    --return SaveTable(t, StripExt(path).."_out.gltf")
    return SaveTable(t, path)
end

--test
--glTFCompressTextures("models/gltf/boombox.gltf")

 

  • Like 1

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...