1
\$\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\$
2
  • \$\begingroup\$ I suggest you accept the current answer. And ask a new question for your follow up question. \$\endgroup\$
    – concept3d
    Nov 22, 2014 at 14:07
  • \$\begingroup\$ @concept3d ok, done. \$\endgroup\$ Nov 22, 2014 at 16:17

1 Answer 1

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\$
3
  • \$\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\$ Nov 22, 2014 at 13:21
  • \$\begingroup\$ @UnresolvedExternal - if you have a follow-up question you should ask it as a separate question. \$\endgroup\$ Nov 22, 2014 at 15:21
  • \$\begingroup\$ @DarthSatan ok, I've removed the follow-up question. \$\endgroup\$ Nov 22, 2014 at 16:17

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .