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