< 返回版块

Choi-Jungwoo 发表于 2022-12-15 23:09

Tags:maya,c++,cbindgen

前言

在 21 年年初我在 Rust 语言中文社区发布了一篇关于 Rust 接入 Maya API 的文章《Maya 中使用 Rust》,并在 21 年 Rust 社区晚会中讲解了一下当时的实现方式,Rust -> Python -> C++ 这套流程。这种方式写起来并不舒服,而且避免不了中间有个 Python 解释器。于是,时隔两年,我又琢磨了一套玩法 Rust -> C++。

开工

原理

使用 Rust 构建出一个动态链接库(dll),并使用 cbindgen 生成 C 头文件,C++ 去调用 Rust 生成的库。我们把核心的算法内容写在 Rust 库中,C++ 去操作 API 并调用 Rust 库。

准备环境

  • Maya 2018
  • Rust 1.68.0-nightly
  • Visual Studio 2019
  • Maya 2018 Devkit

创建项目

我们需要创建两个项目,一个 Rust 动态链接库项目,一个 Maya C++ API 项目,将这两个项目的输出目录都指到 build 文件夹,cbindgen 输出指到 build/include,mll 文件指到 build/plug-in。

如何创建这两个项目就不在这讲解了

build:构建结果

rust-noise-lib:Rust Dyn Library

rust-noise-plugin:Maya C++ Plugin

alt

配置一下 mod 文件(记得改路径)

+ RustNoiseModule 1.0 E:\User\Choi-Jungwoo\Desktop\rust-noise\build
PATH+:=release
MAYA_PLUG_IN_PATH+:=plug-ins

Rust 部分实现

在 Rust 中实现了个随机向量,是个很简单的 noise vector 的案例。


use rand::Rng;

/// cbindgen:derive-eq
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct NoiseVector {
    x: f32,
    y: f32,
    z: f32,
}

impl NoiseVector {
    pub fn new() -> NoiseVector {
        NoiseVector {
            x: 0f32,
            y: 0f32,
            z: 0f32,
        }
    }

    fn gen_point(displacement: f32) -> f32 {
        rand::thread_rng().gen::<f32>() * displacement
    }

    pub fn gen(&mut self, displacement: f32) {
        self.x = NoiseVector::gen_point(displacement);
        self.y = NoiseVector::gen_point(displacement);
        self.z = NoiseVector::gen_point(displacement);
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_gen_noise() {
        let mut noise = NoiseVector::new();
        noise.gen(0.002);

        println!("{:?}", noise);
    }
}

lib.rs


pub mod noise_vector;

#[no_mangle]
pub extern "C" fn new_rust_noise_vector() -> noise_vector::NoiseVector {
    noise_vector::NoiseVector::new()
}

#[no_mangle]
pub extern "C" fn gen_noise(noise_vector: &mut noise_vector::NoiseVector, displacement: f32) {
    noise_vector.gen(displacement);
}

Maya C++ Plugin 中的实现

本文仅展示了部分代码,删除了插件初始化,类构建函数等,完整代码请到 git 上查看,此文章也会在 Rust 语言中文社区中发布。24 行 - 30 行,就是 Rust 与 C++ 交互的部分。


#include "RustNoisePlugin.h"

MStatus RustNoisePlugin::rustNoise(MString objectName, double displacementNum)
{
  MStatus status;

  MSelectionList selection;
  MDagPath dagPath;
  MItSelectionList iter(selection);
  selection.add(objectName);
  selection.getDagPath(0, dagPath);
  MItGeometry geoIter(dagPath);
  MPointArray pArray;
  status = geoIter.allPositions(pArray, MSpace::kWorld);

  if (status != MS::kSuccess)
  {
    MGlobal::displayError("Failed get " + objectName + " positions");
    return status;
  }

  for (int i = 0; i < pArray.length(); i++)
  {
    // -----------------------------------------------
    struct NoiseVector noise = new_rust_noise_vector();
    gen_noise(&noise, displacementNum);
    pArray[i].x += noise.x;
    pArray[i].y += noise.y;
    pArray[i].z += noise.z;
    // -----------------------------------------------
  }

  status = geoIter.setAllPositions(pArray, MSpace::kWorld);
  if (status != MS::kSuccess)
  {
    MGlobal::displayError("Failed set " + objectName + " positions");
    return status;
  }

  MFnMesh meshFn(dagPath);
  status = meshFn.updateSurface();
  if (status != MS::kSuccess)
  {
    MGlobal::displayError("Failed update " + objectName + " surface");
    return status;
  }

  return status;
}

在 Maya 中运行

运行以下命令,我们会得到一个凹凸不平的球体。

rustNoise -n pSphere1 -d 0.005

alt

源码

Github


Ext Link: https://mp.weixin.qq.com/s?__biz=MzkxNjQzMjg2MQ==&amp;mid=2247483663&amp;idx=1&amp;sn=bfdc6b1b0beb638f060064a768b42826&amp;chksm=c14eb3bdf6393aabf36811c38b414c1b89da64b411844440ccd2e371c4a99eb3fb870e39480c&token=562105694&lang=zh_CN#rd

评论区

写评论

还没有评论

1 共 0 条评论, 1 页