我将如何制作一个模板(如 C++ 中的模板)来在 Rust 中设置着色器制服?

Dec*_*gis 14 traits rust

我最近一直在学习 Rust,并正在使用 glfw3 和 gl 开发 3d 引擎。我已经尝试获得一个可以在我的 C++ 引擎中运行的着色器程序,并且可以在我的 Rust 引擎上运行,但在设置着色器制服的实现上遇到了障碍。

着色器.h:

template <typename T> void SetUniform(const GLchar* name, const T& data);
Run Code Online (Sandbox Code Playgroud)

着色器.cpp

template <> void ShaderProgram::SetUniform<int>(const GLchar* name, const int& data) {
    glUniform1i(GetUniformLocation(name), data);
}

template <> void ShaderProgram::SetUniform<float>(const GLchar* name, const float& data) {
    glUniform1f(GetUniformLocation(name), data);
}

template <> void ShaderProgram::SetUniform(const GLchar* name, const glm::vec2& data) {
    glUniform2f(GetUniformLocation(name), data.x, data.y);
}
//etc...
Run Code Online (Sandbox Code Playgroud)

由于我对 Rust 的了解有限,我尝试使用 match 语句,因为它到目前为止为我节省了很多麻烦,但没有成功。

pub fn set_uniform<T>(&mut self, value: T){
    match T {
        u32 => {/*insert gl call here*/},
        f32 => {/*insert gl call here*/},
        //etc...
        _ => {panic!()}
    }
}
Run Code Online (Sandbox Code Playgroud)

我也遇到了一些特质,但没能尝试调整它们来满足我的需要。我希望它会是这样的,尽管我知道语法非常奇怪。

trait SetUniform<T, Self = ShaderProgram> {
    fn set_uniform(self: &mut Self, value: T)
    where
        T: Sized;
}
Run Code Online (Sandbox Code Playgroud)

有没有什么方法可以只用一个可以接受任何类型参数的函数名来做到这一点,或者我应该放弃并为每种不同类型创建一堆不同命名的 set_uniform 函数?

isa*_*tfa 14

这可以通过特征来完成。

改变的是 的类型,value所以我们需要一个可以在这些类型上实现的特征,i32f32等。这可能看起来像这样:

trait SetUniform {
    fn set_uniform(location: GLint, value: Self);
}
Run Code Online (Sandbox Code Playgroud)

(我假设这些glUniform函数都有类似或相似的签名fn(GLint, ...)

现在我们为我们的参数类型实现它:

impl SetUniform for f32 {
    fn set_uniform(location: GLint, value: Self) {
        glUniform1f(location, value)
    }
}

impl SetUniform for i32 {
    fn set_uniform(location: GLint, value: Self) {
        glUniform1i(location, value)
    }
}

// guessing the types here, but the principle should be clear
impl SetUniform for &Vec2 {
    fn set_uniform(location: GLint, value: Self) {
        glUniform2f(location, value.x, value.y)
    }
}

// etc for other types
Run Code Online (Sandbox Code Playgroud)

然后你的调用函数(在本图中进行了简化)可以如下所示:

fn set_uniform<T: SetUniform>(location: GLint, value: T) {
    //         ^^^^^^^^^^^^^ `T` is now bound on the `SetUniform` trait...
    SetUniform::set_uniform(location, value)
    //                                ^^^^^ ... which is why this works
}
Run Code Online (Sandbox Code Playgroud)

  • 小提示:按照惯用方式,“set_uniform”会将“self”作为第一个参数。它将调用位置简化为:“value.set_uniform(location);” (2认同)