如何在C ++中实现向量泛滥? [英] How to achieve vector swizzling in C++?

查看:85
本文介绍了如何在C ++中实现向量泛滥?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

struct vec2
{
    union
    {
        struct { float x, y; };
        struct { float r, g; };
        struct { float s, t; };
    };
    vec2() {}
    vec2(float a, float b) : x(a), y(b) {}
};
struct vec3
{
    union
    {
        struct { float x, y, z; };
        struct { float r, g, b; };
        struct { float s, t, p; };
        // Here is the problem with g++.
        struct { vec2 xy; float z; };
        struct { float x; vec2 yz; };
    };
    vec3() {}
    vec3(float a, float b, float c) : x(a), y(b), z(c) {}
};

上面的代码可以在Visual Studio中按预期方式编译和工作,因此我可以像使用它一样

The code above compiles and works as expected in Visual Studio and so I can use it like

vec3 v1(1.f, 2.f, 3.f);
vec2 v2 = v1.yz; // (2, 3)

在g ++(MinGW)中为

不是.

Not in g++ (MinGW).

src/main.cpp:22:23: error: member 'vec2 vec3::<unnamed union>::<unnamed struct>::xy' with constructor not allowed in anonymous aggregate
src/main.cpp:22:33: error: redeclaration of 'float vec3::<unnamed union>::<unnamed struct>::z'
src/main.cpp:18:30: note: previous declaration 'float vec3::<unnamed union>::<unnamed struct>::z'
src/main.cpp:23:32: error: member 'vec2 vec3::<unnamed union>::<unnamed struct>::yz' with constructor not allowed in anonymous aggregate
src/main.cpp:23:24: error: redeclaration of 'float vec3::<unnamed union>::<unnamed struct>::x'
src/main.cpp:18:24: note: previous declaration 'float vec3::<unnamed union>::<unnamed struct>::x'

我认为我一开始就不应该那样做.有任何想法吗?

I think I shouldn't be doing it like that in the first place. Any Ideas?

在阅读了很多文章并探索了开源项目之后,我开始了解矢量旋转的方式并将其发布在下面的解决方案中,尽管如此仍在等待更好的答案.

After reading a lot of articles and exploring open-source projects, I started to get how vector swizzling should be like and posted the solution below, still waiting for better answers though.

所有 vec * 成员 只能从父级访问 ,如GLM 库.

推荐答案

好吧,我自己仅使用C ++标准找到了解决方案.
没有命令行,也没有使用特定于编译器的代码.

Well, I've found the solution myself using only the C++ Standards.
No command-lines neither using compiler-specific code.

这是我的新的和简单的实现方式

So this is my new and simple implementation

template<unsigned int I>
struct scalar_swizzle
{
    float v[1];
    float &operator=(const float x)
    {
        v[I] = x;
        return v[I];
    }
    operator float() const
    {
        return v[I];
    }
    float operator++(int)
    {
        return v[I]++;
    }
    float operator++()
    {
        return ++v[I];
    }
    float operator--(int)
    {
        return v[I]--;
    }
    float operator--()
    {
        return --v[I];
    }
};
// We use a vec_type in a template instead of forward declartions to prevent erros in some compilers.
template<typename vec_type, unsigned int A, unsigned int B>
struct vec2_swizzle
{
    float d[2];
    vec_type operator=(const vec_type& vec)
    {
        return vec_type(d[A] = vec.x, d[B] = vec.y);
    }
    operator vec_type()
    {
        return vec_type(d[A], d[B]);
    }
};
struct vec2
{
    union
    {
        float d[2];
        scalar_swizzle<0> x, r, s;
        scalar_swizzle<1> y, g, t;
        vec2_swizzle<vec2, 0, 0> xx;
        vec2_swizzle<vec2, 1, 1> yy;
    };
    vec2() {}
    vec2(float all)
    {
        x = y = all;
    }
    vec2(float a, float b)
    {
        x = a;
        y = b;
    }
};
/* Debugging */
inline std::ostream& operator<<(std::ostream &os, vec2 vec)
{
    os << "(" << vec.x << ", " << vec.y << ")";
    return os;
}
template<typename vec_type, unsigned int A, unsigned int B, unsigned int C>
struct vec3_swizzle
{
    float d[3];
    vec_type operator=(const vec_type& vec)
    {
        return vec_type(d[A] = vec.x, d[B] = vec.y, d[C] = vec.z);
    }
    operator vec_type()
    {
        return vec_type(d[A], d[B], d[C]);
    }
};
struct vec3
{
    union
    {
        float d[3];
        scalar_swizzle<0> x, r, s;
        scalar_swizzle<1> y, g, t;
        scalar_swizzle<2> z, b, p;
        vec2_swizzle<vec2, 0, 1> xy;
        vec2_swizzle<vec2, 1, 2> yz;
        vec3_swizzle<vec3, 0, 1, 2> xyz;
        vec3_swizzle<vec3, 2, 1, 0> zyx;
    };
    vec3() {}
    vec3(float all)
    {
        x = y = z = all;
    }
    vec3(float a, float b, float c)
    {
        x = a;
        y = b;
        z = c;
    }
};
/* Debugging */
inline std::ostream& operator<<(std::ostream &os, vec3 vec)
{
    os << "(" << vec.x << ", " << vec.y << ", " << vec.z << ")";
    return os;
}

当然,您可以添加/创建更多的毛发.现在进行一些测试.

Of course, you can add/create more swizzlings. Now with a little test.

int main()
{
    vec3 v0(10, 20, 30);
    std::cout << v0.zyx << std::endl;
    vec2 c(-5, -5);
    v0.xy = c;
    vec2 v1(v0.yz);
    std::cout << v0 << std::endl;
    std::cout << v1 << std::endl;
    vec3 v(50, 60, 70);
    vec2 d = v.yz;
    std::cout << d << std::endl;
    float f = d.x * d.y;
    std::cout << f << std::endl;

    return 0;
}

退出:

(30, 20, 10)
(-5, -5, 30)
(-5, 30)
(60, 70)
4200

如果您不像我在gcc中那样使用 IDE ,则可以使用 std :: cout 打印矢量以进行调试.

You can print the vectors for debugging with std::cout if you're not using an IDE as I did in gcc.

这篇关于如何在C ++中实现向量泛滥?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆