将 glm.mat4 从 Python 传回 C++ (glm::mat4)

Posted

技术标签:

【中文标题】将 glm.mat4 从 Python 传回 C++ (glm::mat4)【英文标题】:Passing glm.mat4 from Python back to C++ (glm::mat4) 【发布时间】:2020-06-21 07:55:10 【问题描述】:

我有一个 boost python 应用程序,它将一个类导出到 Python,执行计算并将输出返回给 C++:

import engine # c++ library
import glm # pyglm

class Game(engine.Application):
    def __init__(self):
        engine.Application.__init__(self, title, fullscreen)
        self.shader = engine.Shader();
        self.shader.setup("shader.vs", "shader.fs")
        self.shader.setMat4("model", glm.mat4(1.0)
    def update(self):
        ...

在其他类中,着色器是这样从 C++ 包装和导出的:

struct ShaderWrap : Shader, boost::python::wrapper<Shader>

  int setup(const char* vertexPath, const char* fragmentPath)
  
    return Shader::setup(vertexPath, fragmentPath);
  
  int setMat4(std::string name, glm::mat4 mat)
  
    return Shader::setMat4(name, mat);
  
;

...

BOOST_PYTHON_MODULE(engine)

  namespace python = boost::python;

  ...

  python::class_<ShaderWrap, boost::noncopyable>("Shader")
    .def("setup", &Shader::setup)
    .def("setMat4", &Shader::setMat4)
    ;

  ...

在调用self.shader.setMat4 之前,该应用程序运行良好,但我收到错误消息:

Boost.Python.ArgumentError: Python argument types in
    StaticShader.setMat4(StaticShader, str, glm::detail::tmat4x4)
did not match C++ signature:
    setMat4(StaticShader lvalue, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, glm::mat<4, 4, float, (glm::qualifier)0>)

我尝试将 mat4 值作为 float* 传递回 C++,但没有成功。 我也试过调用value_ptr(mat4),它返回一个c_void_p,但编译器抱怨说c_void_pvoid*不是同一种类型(也尝试过使用ctypes库进行转换的各种尝试)。 this question 和 this question 基本上是同一个问题,但是我在实现中迷路了。

在 PyGLM 文档中,开发人员说该库是用 C++ 编写的。所以,

glm.mat4 值传递给C++ 以被解释为glm::mat4 值的可能方法是什么?

我想传递一个 glm.mat4,例如视图矩阵,在 Python 代码更新函数中被更新回 C++ 以供进一步使用,并希望 pyGLM 库/GLM 库之间有一个相当简单的接口通过 boost::python。提前致谢。

【问题讨论】:

【参考方案1】:

最后就这个问题联系了开发者,得到了回复:

这是矩阵对象在 C++ 代码中的样子:

template<int C, int R, typename T>
struct mat 
    PyObject ob_base;
    uint8_t info;
    glm::mat<C, R, T> super_type;
;

这很可能是它与 glm 矩阵不太兼容的原因。

如果您使用的是最新版本的 PyGLM,value_ptr(mat4) 应该返回一个 LP_c_float 对象,即一个 float*。 我确信有一种方法可以将这样的指针传递给 boost::python,尽管正如我所说,我不知道如何。

从技术上讲,您可以将指针转换为整数,将其传输并转换回float*。 您可以使用以下方法获取指针的地址:

int.from_bytes(ptr, "little")

或者你可以简单地发送一个字节对象。

as_bytes = bytes(mat4)

或者作为一个元组:

as_tuple = mat4.to_tuple()

或者作为一个 numpy 数组(它似乎有它自己的 boost::python::numpy 模块):

np_arr = numpy.array(mat4)

我能够通过将内存地址作为 int* 传递回 C++ 来获得正确的输出,然后进行一些切片以将其恢复为 glm::mat4,但我发现这个解决方案过于复杂并最终包装手动 glm::mat4 类(参见 https://***.com/a/62672081/9238288 了解如何实现此目的的基本示例)。

【讨论】:

以上是关于将 glm.mat4 从 Python 传回 C++ (glm::mat4)的主要内容,如果未能解决你的问题,请参考以下文章

如何从 glm::quat 和 glm::mat4 中提取偏航俯仰滚动

glm - 将 mat4 分解为平移和旋转?

将mat3转换为mat4的最简单方法

glm::mat4 构造函数如何工作?

如何用数组初始化 glm::mat4?

如何在 glRotatef 中使用 glm::mat4