0
\$\begingroup\$

I have a struct on the CPU which I'm sending to a uniform block in my shader. After a bit frustration I finally got it to work. The problem I had was that vec3s are actually treated as 16-bytes, or in other words they need to have padding. So to solve this I added a dummy-float after each vec3 (see below).

I know I could just use vec4, but since I want to treat alpha as a separate component I don't want to type that 4th component for each vector every time. Furthermore, I would have to use swizzling in the shader as well to separate alpha.

Now to the question, is there any nicer/better way to solve the padding problem than having to add an extra float?

// CPU
struct Material
{
public:
    vec3 Emissive; float p1;
    vec3 Ambient; float p2;
    vec3 Diffuse; float p3;
    vec3 Specular;
    float Shininess;
    float Alpha;
};

// Fragment shader
layout(std140) uniform uniMaterial
{
    vec3 Emissive;
    vec3 Ambient;
    vec3 Diffuse;
    vec3 Specular;
    float Shininess;
    float Alpha;
};

Regards, Tobias

My solution:

struct GpuVec3
{
public:
    GpuVec3() {}

    GpuVec3& GpuVec3::operator=(const vec3& other) 
    {
        v.x = other.x;
        v.y = other.y;
        v.z = other.z;
        v.w = 1.0f;

        return *this;
    }

    GpuVec3& GpuVec3::operator=(const vec4& other)
    {
        v.x = other.x;
        v.y = other.y;
        v.z = other.z;
        v.w = other.w;

        return *this;
    }

private:
    vec4 v;
};

typedef GpuVec3 GpuVec4;
\$\endgroup\$
  • \$\begingroup\$ I suggest you accept the current answer. And ask a new question for your follow up question. \$\endgroup\$ – concept3d Nov 22 '14 at 14:07
  • \$\begingroup\$ @concept3d ok, done. \$\endgroup\$ – Unresolved External Nov 22 '14 at 16:17
1
\$\begingroup\$

Tobias,

If you declare your vec3 class in C++ as having 16 byte alignment, you will have the matching offset.

struct vec3
{
float x,y,z;
} __attribute__ ((aligned(16)));

However this will align it everywhere. You might want a GPUVec3 which is aligned, and has copy constructor from your general vec3 so you don't burn that extra float everywhere.

I would, however, suggest stuffing your alpha into the w component of some of those vectors to improve bandwidth since you are just burning memory there. I wouldn't surprised that, in addition to losing a float per vector3, you are also losing 2 floats at the end of your uniform structure.

struct Material
{
public:
    vec4 EmissiveAndShineness;
    vec4 AmbientAndAlpha;
    vec3 Diffuse; float pad;
    vec3 Specular;
};

or

struct Material
{
public:
    GPUVec4 EmissiveAndShineness; // sizeof(GPUVec4) == 16
    GPUVec4 AmbientAndAlpha; // sizeof(GPUVec4) == 16
    GPUVec3 Diffuse; // sizeof(GPUVec3) == 16
    GPUVec3 Specular; // sizeof(GPUVec3) == 16
};
\$\endgroup\$
  • \$\begingroup\$ Thanks a lot @Steven, this solved my problem! However, now I have a follow-up question. Please have a look at update #1 above for my solution and follow-up question. \$\endgroup\$ – Unresolved External Nov 22 '14 at 13:21
  • \$\begingroup\$ @UnresolvedExternal - if you have a follow-up question you should ask it as a separate question. \$\endgroup\$ – Maximus Minimus Nov 22 '14 at 15:21
  • \$\begingroup\$ @DarthSatan ok, I've removed the follow-up question. \$\endgroup\$ – Unresolved External Nov 22 '14 at 16:17

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.