How to pack 3 numbers into an int and then do the reverse

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
User avatar
kicknbritt
Citizen
Posts: 96
Joined: Sat May 30, 2015 2:15 am
Location: Chicago, IL/Anchorage,AK

How to pack 3 numbers into an int and then do the reverse

Post by kicknbritt »

Hello. I am instancing a bunch of cube faces in a shader, and I am using imagedata to store the per instance values in 3 different floats using the "rg11b10f" Image format.
I would like to pass as little data to the shader as possible and also keep it light for mobile devices, so I am storing the data like this:

-----------| variable | value -------
1st float: ChunkPos (40x40x40)
2nd float: BlockPos (32x32x32)
3rd float: BlockType (0 - 65024) (You can Ignore this one)

Basically I am trying to find a way to store the 1st and 2nd values within the "rg11b10f" range of [0, 65024] so I can send them to my shader,
and then I need a way to unpack them back into the when they are in the shader. I know they both fit because 40^3 < 65024, I just don't understand the math needed to accomplish this. Thanks.

For reference, this is the code I am using (yes it's not great, any pointers or tips are appreciated.)
Keep in mind that this code is not working yet because I have not finished setting up the 3 shader variables above.

Also If anyone knows how to transform the block face vertices in the shader to move to one of the 6 positions of the cube so I don't need 6
different instances of the faces I would appreciate the help :D

Vertex Shader

Code: Select all

    local VertexCode = [[

        uniform mat4 view;
        uniform mat4 model_matrix;
        uniform mat4 model_matrix_inverse;

        // Whether or not we are handling instanced block faces in the shader
        uniform bool BlockInstance;
        // The current block coordinate we are on
        uniform vec3 CurrentBlockPos;
        // How far we render in blocks.
        uniform int BlockRenderDist;
        // The size of blocks in the GlobalBlockTextureAtlas in both width and height
        uniform int BlockTextureSize;
        // The size of chunks in block dimensions
        uniform int ChunkSize;
        // An integer that keeps track of what block face we are instancing. 1top 2front 3left 4right 5back 6bot
        uniform int CurrentBlockFace;

        attribute int ChunkPos;
        attribute int BlockPos;
        // An integer that contains the ID of the blocktype of the instanced blockface. This also is used to find the block texture in the block texture atlas.
        attribute int BlockType;

        attribute float InstanceRot;

        varying mat4 modelView;
        varying mat4 modelViewProjection;
        varying vec3 normal;
        varying vec3 vposition;


        varying int ChunkX;
        varying int ChunkY;
        varying int ChunkZ;
        varying int BlockX;
        varying int BlockY;
        varying int BlockZ;

        attribute vec4 VertexNormal;

        vec4 position(mat4 transform_projection, vec4 vertex_position) {

            // Check if this model is an instance or not
            if (BlockInstance) {

                // Break down the integer we passed into the shader for the ChunkPos into 3 different positions
                ChunkX = //Unpacked from ChunkPos
                ChunkY = //Unpacked from ChunkPos
                ChunkZ = //Unpacked from ChunkPos

                // Break down the integer we passed into the shader for the BlockPos into 3 different positions
                BlockX = //Unpacked from BlockPos 
                BlockY = //Unpacked from BlockPos 
                BlockZ = //Unpacked from BlockPos          
                
                // Move the vertices to the correct position
                vertex_position.x = (ChunkX*ChunkSize) + BlockX
                vertex_position.y = (ChunkY*ChunkSize) + BlockY
                vertex_position.z = (ChunkZ*ChunkSize) + BlockZ

                // Apply the projection matrix to give it perspective.
                return view*vertex_position;

            } else {

                modelView = view * model_matrix;
                modelViewProjection = view * model_matrix * transform_projection;

                normal = vec3(model_matrix_inverse * vec4(VertexNormal));
                vposition = vec3(model_matrix * vertex_position);

                return view * model_matrix * vertex_position;
            }
        }


    ]]

Part where I create instance data

Code: Select all

 
    ------------------------------------------------------------------------------------------------------------------
    -- Vertices for the instanced block meshes
    SS3D.Scene.TopFaceInstanceVertices = {{1,1,1,}, {0,1,0,}, {1,1,0,}, {1,1,1,}, {0,1,1,}, {0,1,0,},}

    SS3D.Scene.BotFaceInstanceVertices = {{0,0,1,}, {1,0,1,}, {1,0,0,}, {0,0,1,}, {1,0,0,}, {0,0,0,},}

    SS3D.Scene.RightFaceInstanceVertices = {{1,0,0,}, {1,0,1,}, {1,1,1,}, {1,0,0,}, {1,1,1,}, {1,1,0,},}

    SS3D.Scene.LeftFaceInstanceVertices = {{0,0,1,}, {0,0,0,}, {0,1,0,}, {0,0,1,}, {0,1,0,}, {0,1,1,},}

    SS3D.Scene.FrontFaceInstanceVertices = {{1,0,1,}, {0,0,1,}, {0,1,1,}, {1,0,1,}, {0,1,1,}, {1,1,1,},}

    SS3D.Scene.BackFaceInstanceVertices = {{0,0,0,}, {1,0,0,}, {1,1,0,}, {0,0,0,}, {1,1,0,}, {0,1,0,},}

    -- Mesh used for instances
    local InstanceVertexFormat = {
            {"VertexPosition", "float", 3},
        }
    SS3D.Scene.TopFaceInstanceMesh = love.graphics.newMesh(InstanceVertexFormat, SS3D.Scene.TopFaceInstanceVertices, "triangles", "static")
    SS3D.Scene.TopFaceInstanceMesh:setTexture(Blocks.GlobalBlockTextureAtlas)

    SS3D.Scene.BotFaceInstanceMesh = love.graphics.newMesh(InstanceVertexFormat, SS3D.Scene.BotFaceInstanceVertices, "triangles", "static")
    SS3D.Scene.BotFaceInstanceMesh:setTexture(Blocks.GlobalBlockTextureAtlas)

    SS3D.Scene.RightFaceInstanceMesh = love.graphics.newMesh(InstanceVertexFormat, SS3D.Scene.RightFaceInstanceVertices, "triangles", "static")
    SS3D.Scene.RightFaceInstanceMesh:setTexture(Blocks.GlobalBlockTextureAtlas)

    SS3D.Scene.LeftFaceInstanceMesh = love.graphics.newMesh(InstanceVertexFormat, SS3D.Scene.LeftFaceInstanceVertices, "triangles", "static")
    SS3D.Scene.LeftFaceInstanceMesh:setTexture(Blocks.GlobalBlockTextureAtlas)

    SS3D.Scene.FrontFaceInstanceMesh = love.graphics.newMesh(InstanceVertexFormat, SS3D.Scene.FrontFaceInstanceVertices, "triangles", "static")
    SS3D.Scene.FrontFaceInstanceMesh:setTexture(Blocks.GlobalBlockTextureAtlas)

    SS3D.Scene.BackFaceInstanceMesh = love.graphics.newMesh(InstanceVertexFormat, SS3D.Scene.BackFaceInstanceVertices, "triangles", "static")
    SS3D.Scene.BackFaceInstanceMesh:setTexture(Blocks.GlobalBlockTextureAtlas)

    local size = 32

    -- a list of all block instances in the SS3D.Scene
    SS3D.Scene.TopFaceInstanceList = love.image.newImageData((size^3), 1, "rg11b10f")

    SS3D.Scene.BotFaceInstanceList = love.image.newImageData((size^3), 1, "rg11b10f")

    SS3D.Scene.RightFaceInstanceList = love.image.newImageData((size^3), 1, "rg11b10f")

    SS3D.Scene.LeftFaceInstanceList = love.image.newImageData((size^3), 1, "rg11b10f")

    SS3D.Scene.FrontFaceInstanceList = love.image.newImageData((size^3), 1, "rg11b10f")

    SS3D.Scene.BackFaceInstanceList = love.image.newImageData((size^3), 1, "rg11b10f")

    local rnd = math.random
    local i = 0
    for x=1, size do
        for y=1, size do
            for z=1, size do
                local chance = 1--math.random(1, 5)
                if chance == 1 then
                    SS3D.Scene.TopFaceInstanceList:setPixel(i, 0, Pair3(1, 1, 1, 32), Pair3(x, y, z, 16), rnd(0, 65024))
                    SS3D.Scene.BotFaceInstanceList:setPixel(i, 0, Pair3(1, 1, 1, 32), Pair3(x, y, z, 16), rnd(0, 65024))
                    SS3D.Scene.RightFaceInstanceList:setPixel(i, 0, Pair3(1, 1, 1, 32), Pair3(x, y, z, 16), rnd(0, 65024))
                    SS3D.Scene.LeftFaceInstanceList:setPixel(i, 0, Pair3(1, 1, 1, 32), Pair3(x, y, z, 16), rnd(0, 65024))
                    SS3D.Scene.FrontFaceInstanceList:setPixel(i, 0, Pair3(1, 1, 1, 32), Pair3(x, y, z, 16), rnd(0, 65024))
                    SS3D.Scene.BackFaceInstanceList:setPixel(i, 0, Pair3(1, 1, 1, 32), Pair3(x, y, z, 16), rnd(0, 65024))
                    i = i + 1
                end
            end
        end
    end


    -- This mesh is used whenever a new model is added with the 'isBlockInstance' parameter is created
    SS3D.Scene.TopFaceInstanceMeshTemplate = love.graphics.newMesh({{"ChunkPos","float",1},{"BlockPos","float",1},{"BlockType","float",1},},SS3D.Scene.TopFaceInstanceList, nil, "static")

    SS3D.Scene.BotFaceInstanceMeshTemplate = love.graphics.newMesh({{"ChunkPos","float",1},{"BlockPos","float",1},{"BlockType","float",1},},SS3D.Scene.BotFaceInstanceList, nil, "static")

    SS3D.Scene.RightFaceInstanceMeshTemplate = love.graphics.newMesh({{"ChunkPos","float",1},{"BlockPos","float",1},{"BlockType","float",1},},SS3D.Scene.RightFaceInstanceList, nil, "static")

    SS3D.Scene.LeftFaceInstanceMeshTemplate = love.graphics.newMesh({{"ChunkPos","float",1},{"BlockPos","float",1},{"BlockType","float",1},},SS3D.Scene.LeftFaceInstanceList, nil, "static")

    SS3D.Scene.FrontFaceInstanceMeshTemplate = love.graphics.newMesh({{"ChunkPos","float",1},{"BlockPos","float",1},{"BlockType","float",1},},SS3D.Scene.FrontFaceInstanceList, nil, "static")

    SS3D.Scene.BackFaceInstanceMeshTemplate = love.graphics.newMesh({{"ChunkPos","float",1},{"BlockPos","float",1},{"BlockType","float",1},},SS3D.Scene.BackFaceInstanceList, nil, "static")


    -- Attach attributes to the instance block mesh
    SS3D.Scene.TopFaceInstanceMesh:attachAttribute("ChunkPos", SS3D.Scene.TopFaceInstanceMeshTemplate, "perinstance")
    SS3D.Scene.TopFaceInstanceMesh:attachAttribute("BlockPos", SS3D.Scene.TopFaceInstanceMeshTemplate, "perinstance")
    SS3D.Scene.TopFaceInstanceMesh:attachAttribute("BlockType", SS3D.Scene.TopFaceInstanceMeshTemplate, "perinstance")

    -- Attach attributes to the instance block mesh
    SS3D.Scene.BotFaceInstanceMesh:attachAttribute("ChunkPos", SS3D.Scene.BotFaceInstanceMeshTemplate, "perinstance")
    SS3D.Scene.BotFaceInstanceMesh:attachAttribute("BlockPos", SS3D.Scene.BotFaceInstanceMeshTemplate, "perinstance")
    SS3D.Scene.BotFaceInstanceMesh:attachAttribute("BlockType", SS3D.Scene.BotFaceInstanceMeshTemplate, "perinstance")

    -- Attach attributes to the instance block mesh
    SS3D.Scene.RightFaceInstanceMesh:attachAttribute("ChunkPos", SS3D.Scene.RightFaceInstanceMeshTemplate, "perinstance")
    SS3D.Scene.RightFaceInstanceMesh:attachAttribute("BlockPos", SS3D.Scene.RightFaceInstanceMeshTemplate, "perinstance")
    SS3D.Scene.RightFaceInstanceMesh:attachAttribute("BlockType", SS3D.Scene.RightFaceInstanceMeshTemplate, "perinstance")

    -- Attach attributes to the instance block mesh
    SS3D.Scene.LeftFaceInstanceMesh:attachAttribute("ChunkPos", SS3D.Scene.LeftFaceInstanceMeshTemplate, "perinstance")
    SS3D.Scene.LeftFaceInstanceMesh:attachAttribute("BlockPos", SS3D.Scene.LeftFaceInstanceMeshTemplate, "perinstance")
    SS3D.Scene.LeftFaceInstanceMesh:attachAttribute("BlockType", SS3D.Scene.LeftFaceInstanceMeshTemplate, "perinstance")

    -- Attach attributes to the instance block mesh
    SS3D.Scene.FrontFaceInstanceMesh:attachAttribute("ChunkPos", SS3D.Scene.FrontFaceInstanceMeshTemplate, "perinstance")
    SS3D.Scene.FrontFaceInstanceMesh:attachAttribute("BlockPos", SS3D.Scene.FrontFaceInstanceMeshTemplate, "perinstance")
    SS3D.Scene.FrontFaceInstanceMesh:attachAttribute("BlockType", SS3D.Scene.FrontFaceInstanceMeshTemplate, "perinstance")

    -- Attach attributes to the instance block mesh
    SS3D.Scene.BackFaceInstanceMesh:attachAttribute("ChunkPos", SS3D.Scene.BackFaceInstanceMeshTemplate, "perinstance")
    SS3D.Scene.BackFaceInstanceMesh:attachAttribute("BlockPos", SS3D.Scene.BackFaceInstanceMeshTemplate, "perinstance")
    SS3D.Scene.BackFaceInstanceMesh:attachAttribute("BlockType", SS3D.Scene.BackFaceInstanceMeshTemplate, "perinstance")

    --------------------------------------------------------------------------------------------------------------------
"I AM THE ARBITER!!!" *Pulls out Energy sword and kills everything*
Xugro
Party member
Posts: 110
Joined: Wed Sep 29, 2010 8:14 pm

Re: How to pack 3 numbers into an int and then do the reverse

Post by Xugro »

I cannot help you with the technical stuff, but I know the trick with the numbers. It is the same trick how one converts binary numbers to decimal numbers and back - just with base 40 and not with base 2.

Let say you have three numbers: 0 <= a <= 39, 0 <= b <= 39, 0 <= c <= 39. To convert it into a number n with 0 <= n <= 64000 you just do the following:
n = a*40^2+b*40^1+c*40^0

The conversion backwards is a little bit more complicated: Take the number n and use the modulo operator to get c:
c = n % 40

Then you have to subtract c and divide by 40 to start anew:
m = (n - c) / 40

Now you can get b by using modulo again:
b = m % 40

Do the same trick again to get a:
a = (m - b) / 40

Here is a simple example with a=9, b=10 and c=37:
n = 9*40^2+10*40^1+37*40^0 = 14837

c = 14837 % 40 = 37

m = (14837 - 37) / 40 = 14800 / 40 = 370

b = 370 % 40 = 10

a = (370 - 10) / 40 = 360 / 40 = 9
User avatar
kicknbritt
Citizen
Posts: 96
Joined: Sat May 30, 2015 2:15 am
Location: Chicago, IL/Anchorage,AK

Re: How to pack 3 numbers into an int and then do the reverse

Post by kicknbritt »

Hey thanks dude this looks like exactly what I need.
I just needed something I could easily put in the shader as well as lua and this was spot on.
😊
"I AM THE ARBITER!!!" *Pulls out Energy sword and kills everything*
Post Reply

Who is online

Users browsing this forum: No registered users and 82 guests