【开发日志】2023.04 ZENO----Composite----CompImport、ReadImageFlie

CompImport

TEST:

用ParticlesWrangle创造属性A(紫色),B(青色) ,用CompImport结点将属性转化为图片输入到Composite3进行合成

Input:

Output:

/* 导入地形网格的属性,可能会有多个属性。它将地形的属性转换为图
像,每个属性对应一个图层。
可能需要的参数:outRemapRange,分辨率,属性名称,属性数据
类型为float32 */
struct CompImport : INode {
    virtual void apply() override {
        auto prim = get_input<PrimitiveObject>("prim");
        auto &ud = prim->userData();
        int nx = ud.get2<int>("nx");
        int ny = ud.get2<int>("ny");
        auto attrName = get_input2<std::string>("attrName");

        auto image = std::make_shared<PrimitiveObject>();
        image->resize(nx * ny);

        if (prim->verts.attr_is<float>(attrName)) {
            auto &attr = prim->attr<float>(attrName);
            for (auto i = 0; i < nx * ny; i++) {
                float v = attr[i];
                image->verts[i] = {v, v, v};
            }
        }
        else if (prim->verts.attr_is<vec3f>(attrName)) {
            auto &attr = prim->attr<vec3f>(attrName);
            for (auto i = 0; i < nx * ny; i++) {
                image->verts[i] = attr[i];
            }
        }

        image->userData().set2("isImage", 1);
        image->userData().set2("w", nx);
        image->userData().set2("h", ny);

        set_output("image", image);
    }
};

ZENDEFNODE(CompImport, {
    {
        {"prim"},
        {"string", "attrName", ""},
    },
    {
        {"image"},
    },
    {},
    { "comp" },
});

ReadImageFlie

stb_image 库读取 PNG 文件,使用 OpenEXR 库读取 EXR 文件。读取 EXR 文件并使用图像数据(包括 alpha 通道)填充。

  1. stbi_set_flip_vertically_on_load(true);设置在使用stb_image库加载图像时垂直翻转图像的选项。这是计算机图形学中的常见约定,因为图像数据通常首先存储在顶行,而 OpenGL 和其他图形 API 期望首先存储底行。
  2. float* data = stbi_loadf(path.c_str(), &w, &h, &n, 0);在给定路径处加载图像文件,并返回指向包含其像素数据的缓冲区的指针。、 和 是分别接收图像的宽度、高度和通道数的输出参数。该函数用于将图像加载为浮点数据。whnstbi_loadf
  3. if (!data) { ... }通过检查指针是否为 null 来检查图像加载是否成功。如果为 null,则引发异常。data
  4. scope_exit delData = [=] { stbi_image_free(data); };定义使用 C++11 的作用域保护,以便在函数返回或引发异常时自动释放stb_image分配的内存。这对于防止内存泄漏非常重要。scope_exit
  5. auto img = std::make_shared<PrimitiveObject>();创建指向 .PrimitiveObject
  6. img->verts.resize(w * h);调整 的矢量大小以容纳元素。 可能以某种形式表示图像的顶点。vertsPrimitiveObjectw * hverts
  7. if (n == 3) { ... }检查图像是否具有三个通道(红色、绿色、蓝色)。如果是这样,则使用 .vertsstd::memcpy
  8. else if (n == 4) { ... }检查图像是否有四个通道(红色、绿色、蓝色、Alpha)。如果是这样,像素数据将分别拆分为 RGB 和 alpha 通道的单独数组和数组,并使用下标表示法存储在矢量中。vec3ffloatverts
  9. else if (n == 2) { ... }检查图像是否具有两个通道(亮度、Alpha)。如果是这样,则像素数据存储为矢量中具有零 Z 分量的对象。vec3fverts
  10. else if (n == 1) { ... }检查图像是否具有一个通道(亮度)。如果是这样,则像素数据存储为对象,其中 X 分量中的单通道值为零,Y 和 Z 分量为零。vec3f
  11. else { ... }如果通道数不是预期值之一,则引发异常。
  12. img->userData().set2("isImage", 1);设置用户数据字段 以指示它表示图像。PrimitiveObject
  13. img->userData().set2("w", w);设置的用户数据字段以存储图像的宽度。PrimitiveObject
  14. img->userData().set2("h", h);设置的用户数据字段以存储图像的高度。PrimitiveObject
  15. return img;返回指向表示加载图像的共享指针。PrimitiveObject
std::shared_ptr<PrimitiveObject> readImageFile(std::string const &path) {
    int w, h, n;
    stbi_set_flip_vertically_on_load(true);
    float* data = stbi_loadf(path.c_str(), &w, &h, &n, 0);
    if (!data) {
        throw zeno::Exception("cannot open image file at path: " + path);
    }
    scope_exit delData = [=] { stbi_image_free(data); };
    auto img = std::make_shared<PrimitiveObject>();
    img->verts.resize(w * h);
    if (n == 3) {
        std::memcpy(img->verts.data(), data, w * h * n * sizeof(float));
    } else if (n == 4) {
        auto &alpha = img->verts.add_attr<float>("alpha");
        for (int i = 0; i < w * h; i++) {
            img->verts[i] = {data[i*4+0], data[i*4+1], data[i*4+2]};
            alpha[i] = data[i*4+3];
        }
    } else if (n == 2) {
        for (int i = 0; i < w * h; i++) {
            img->verts[i] = {data[i*2+0], data[i*2+1], 0};
        }
    } else if (n == 1) {
        for (int i = 0; i < w * h; i++) {
            img->verts[i] = vec3f(data[i*2+0]);
        }
    } else {
        throw zeno::Exception("too much number of channels");
    }
    img->userData().set2("isImage", 1);
    img->userData().set2("w", w);
    img->userData().set2("h", h);
    return img;
}

std::shared_ptr<PrimitiveObject> readExrFile(std::string const &path) {
    int nx, ny, nc = 4;
    float* rgba;
    const char* err;
    int ret = LoadEXR(&rgba, &nx, &ny, path.c_str(), &err);
    if (ret != 0) {
        zeno::log_error("load exr: {}", err);
        throw std::runtime_error(zeno::format("load exr: {}", err));
    }
    nx = std::max(nx, 1);
    ny = std::max(ny, 1);
//    for (auto i = 0; i < ny / 2; i++) {
//        for (auto x = 0; x < nx * 4; x++) {
//            auto index1 = i * (nx * 4) + x;
//            auto index2 = (ny - 1 - i) * (nx * 4) + x;
//            std::swap(rgba[index1], rgba[index2]);
//        }
//    }

    auto img = std::make_shared<PrimitiveObject>();
    img->verts.resize(nx * ny);

    auto &alpha = img->verts.add_attr<float>("alpha");
    for (int i = 0; i < nx * ny; i++) {
        img->verts[i] = {rgba[i*4+0], rgba[i*4+1], rgba[i*4+2]};
        alpha[i] = rgba[i*4+3];
    }
//
    img->userData().set2("isImage", 1);
    img->userData().set2("w", nx);
    img->userData().set2("h", ny);
    return img;
}

struct ReadImageFile : INode {
    virtual void apply() override {
        auto path = get_input2<std::string>("path");
        if (zeno::ends_with(path, ".exr", false)) {
            set_output("image", readExrFile(path));
        }
        else {
            set_output("image", readImageFile(path));
        }
    }
};
ZENDEFNODE(ReadImageFile, {
    {
        {"readpath", "path"},
    },
    {
        {"PrimitiveObject", "image"},
    },
    {},
    {"comp"},
});
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值