自分用Houdiniメモ (形状処理と自作SOPまわり)
Visualization
- 時系列Geometry filesを読む: File geometry node使用後にFile Cache geometry nodeを使う
- Point -> 任意Geometry: Copy to Points geometry node
- 1番目の入力のジオメトリを2番目の入力のポイント上にコピー
- 頂点に色(Cd)付与: Color geometry node
Texture
- Mesh上のtexture colorを頂点カラーとして追加: Attribute from Map geometry node
- 参考: テクスチャを頂点カラーに変換する
VDBの変換
- Polygon -> VDB: VDB from Polygons geometry node
- VDB -> Points: Points from Volume geometry node
Wrangle
- 第1引数の属性
Cd
を取得:vector d = @opinput1_Cd;
orpoint(1, "Cd", [id]);
(idは1番目のgeometry上のpoint id) - 第2引数Geometryの属性
Cd
を第1引数Geometryの最近傍点へ転写- ref: 君はお隣さん?一番近い点?それとも座標?
int id = nearpoint(1, @P);
@Cd = point(1, "Cd", id);
Export
-
.obj
だとPoint Cloudの頂点カラーは吐けないっぽいので.ply
で吐く
自作SOPまわり
- 自作SOPを作るときは
SOP_Node
を継承して、overrideしたcookMySop
に実装したい処理を書くと良い - Houdini側のGUI経由でc++側のパラメタを設定したい場合は、C++側で
PRM_Template
を用意してあげる必要がある - Houdiniには頂点をpoint, 面(face)をvertexと呼ぶ謎の文化がある
- 入力geometryからgeometryの属性を引っ張りたい場合は
gdp->findAttribute()
を使う - 頂点listのiteratorをぶん回したいときはGA_FOR_ALL_PTOFFまわりのマクロを読む
- 入力geometryからgeometryの属性を引っ張りたい場合は
tiny example (公式exampleのSOP/SOP_CPPWave.h, SOP/SOP_CPPWave.Cの改変)
SOP_Sample.h
#pragma once
#include <SOP/SOP_Node.h>
#include <string>
namespace Samples {
class SOP_Sample : public SOP_Node {
public:
SOP_Sample(OP_Network *net, const char *name, OP_Operator *op);
~SOP_Sample() override;
static PRM_Template myTemplateList[];
static OP_Node *myConstructor(OP_Network *, const char *, OP_Operator *);
static const std::string INTERNAL_LAMBDA;
protected:
OP_ERROR cookMySop(OP_Context &context) override;
private:
fpreal LAMBDA() {
return evalFloat(INTERNAL_LAMBDA.c_str(), 0, 0);
}
};
SOP_Sample.cpp
#include "SOP_Sample.h"
#include <GA/GA_Handle.h>
#include <GU/GU_Detail.h>
#include <OP/OP_AutoLockInputs.h>
#include <OP/OP_Director.h>
#include <OP/OP_Operator.h>
#include <OP/OP_OperatorTable.h>
#include <PRM/PRM_Include.h>
#include <SYS/SYS_Math.h>
#include <UT/UT_DSOVersion.h>
#include <Eigen/Dense>
#include "SOP_Sample.proto.h"
using namespace Samples;
const std::string SOP_Sample::INTERNAL_LAMBDA = "lambda";
void newSopOperator(OP_OperatorTable *table) {
table->addOperator(
new OP_Operator("sample", // generated name at tree view
"Sample", // SOP name
// ref. https://www.sidefx.com/docs/hdk/class_o_p___operator.html
SOP_Sample::myConstructor,
SOP_Sample::myTemplateList, 1, 1, 0));
}
static PRM_Name sop_names[] = {
PRM_Name(SOP_Sample::INTERNAL_LAMBDA, "Lambda"), // 0: internal name, 1: name at Houdini
};
static PRM_Default sop_lambda_default(0.01);
static PRM_Range sop_lambda_range(PRM_RANGE_RESTRICTED, 0.0001, PRM_RANGE_UI,
0.1);
PRM_Template SOP_MeshSmoothing::myTemplateList[] = {
PRM_Template(PRM_FLT_J, 1, &sop_names[0], &sop_lambda_default, 0,
&sop_lambda_range),
PRM_Template()};
OP_Node *SOP_Sample::myConstructor(OP_Network *net, const char *name,
OP_Operator *op) {
return new SOP_Sample(net, name, op);
}
SOP_Sample::SOP_Sample(OP_Network *net, const char *name,
OP_Operator *op)
: SOP_Node(net, name, op) {
mySopFlags.setManagesDataIDs(true);
}
SOP_Sample::~SOP_Sample() {}
OP_ERROR
SOP_Sample::cookMySop(OP_Context &context) {
OP_AutoLockInputs inputs(this);
if (inputs.lock(context) >= UT_ERROR_ABORT) {
return error();
}
duplicateSource(0, context);
// If you want to use animated mesh
flags().setTimeDep(true);
fpreal frame =
OPgetDirector()->getChannelManager()->getSample(context.getTime());
frame *= 0.03;
auto pt_range = gdp->getPointRange();
auto pt_size = pt_range.getEntries(); // vertex size
auto face_range = gdp->getVertexRange();
auto face_size = face_range.getEntries(); // face size (flattened)
auto prim_range = gdp->getPrimitiveRange();
auto prim_size = prim_range.getEntries(); // face size
// (Optional)
float prim_float_num = face_size / prim_size;
int prim_int_num = static_cast<int>(prim_float_num);
if (prim_int_num != prim_float_num || prim_int_num !=3) {
addWarning(SOP_MESSAGE, "Please input a triangular mesh.");
return error();
}
addMessage(SOP_MESSAGE, ("lambda: " + std::to_string(LAMBDA())).c_str());
addMessage(SOP_MESSAGE, ("#V: " + std::to_string(pt_size)).c_str());
addMessage(SOP_MESSAGE, ("#F: " + std::to_string(face_size)).c_str());
addMessage(SOP_MESSAGE, ("#Prim: " + std::to_string(prim_size)).c_str());
// Convert vertices to Eigen
Eigen::MatrixXd V(pt_size, 3);
GA_RWHandleV3 Phandle(gdp->findAttribute(GA_ATTRIB_POINT, "P"));
GA_Offset ptoff;
GA_FOR_ALL_PTOFF(gdp, ptoff) {
UT_Vector3 Pvalue = Phandle.get(ptoff);
V(ptoff, 0) = Pvalue.x();
V(ptoff, 1) = Pvalue.y();
V(ptoff, 2) = Pvalue.z();
}
// Convert faces to Eigen
Eigen::MatrixXi F(prim_size, prim_int_num);
for (auto primoff : prim_range) {
const auto *face = gdp->getGEOPrimitive(primoff);
int face_idx = 0;
for (auto ptoff : face->getPointRange()) {
F(primoff, face_idx) = gdp->pointIndex(ptoff);
face_idx++;
}
}
auto out = F; // apply your geometry processing
for (auto ptoff : pt_range) {
UT_Vector3 Pvalue = Phandle.get(ptoff);
Pvalue.x() = out(ptoff, 0);
Pvalue.y() = out(ptoff, 1);
Pvalue.z() = out(ptoff, 2);
Phandle.set(ptoff, Pvalue);
}
Phandle.bumpDataId();
return error();
}
TODO
-
deep copyせずにHoudiniの頂点属性から
Eigen::MatrixXd
をつくりたい
Author And Source
この問題について(自分用Houdiniメモ (形状処理と自作SOPまわり)), 我々は、より多くの情報をここで見つけました https://qiita.com/mocobt/items/0b3c53225503ee1f9dfc著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .