Houdini18 HDK Offline Test
cmake_minimum_required(VERSION 3.5) project(Triangle) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) # OPENGL find_package(OpenGL REQUIRED) include_directories(${OpenGL_INCLUDE_DIRS}) link_directories(${OpenGL_LIBRARY_DIRS}) add_definitions(${OpenGL_DEFINITIONS}) if(NOT OPENGL_FOUND) message(ERROR " OPENGL not found!") endif(NOT OPENGL_FOUND) # GLEW set(GLEW_HOME D:/plugin_dev/libs/glew-2.1.0) include_directories(${GLEW_HOME}/include) link_directories(${GLEW_HOME}/lib/Release/x64) # GLFW set(GLFW_HOME D:/plugin_dev/libs/glfw-3.3.1.bin.WIN64) include_directories(${GLFW_HOME}/include/) link_directories(${GLFW_HOME}/lib-vc2019) # STB include_directories(D:/plugin_dev/libs/stb) # GLM include_directories(D:/plugin_dev/libs/GLM_include) # ---------------- HOUDINI if (MSVC) # Prevent Boost auto-linking. add_definitions(-DBOOST_ALL_NO_LIB ) add_definitions(-D_SCL_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS -D_WIN32 -D_WINSOCK_DEPRECATED_NO_WARNINGS -D__x86_64__) # HOUDINI : add_definitions(-TP -Zc:forScope -DVERSION="18.0.348" -DI386 -DWIN32 -DSWAP_BITFIELDS -DWINVER=0x0501 -DNOMINMAX -DSTRICT -DWIN32_LEAN_AND_MEAN -D_USE_MATH_DEFINES -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE -D_SCL_SECURE_NO_WARNINGS -DSESI_LITTLE_ENDIAN -DHBOOST_ALL_NO_LIB -DEIGEN_MALLOC_ALREADY_ALIGNED=0 -DFBX_ENABLED=1 -DOPENCL_ENABLED=1 -DOPENVDB_ENABLED=1 -MD -EHsc -GR -DNEED_SPECIALIZATION_STORAGE -DAMD64 -DSIZEOF_VOID_P=8) endif() set(HOUDINI_HOME "D:/Program Files/Side Effects Software/Houdini 18.0.348") include_directories("${HOUDINI_HOME}/toolkit/include") link_directories("${HOUDINI_HOME}/custom/houdini/dsolib") # output excutable dir set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/build) # SRC FILE FILE( GLOB SRC *.cpp *.h ) add_executable(Triangle ${SRC}) target_link_libraries(Triangle PRIVATE libGA.lib libGU.lib libUT.lib libCE.lib libLM.lib libFS.lib libSYS.lib libGEO.lib )
HDK Geometry Struct:
Houdini Geometry responsed to this figure:
1, get GLDraw info from this code:
#include <GU/GU_Detail.h> #include <GEO/GEO_Primitive.h> #include <GEO/GEO_PrimPoly.h> #include <GA/GA_Primitive.h> #include <GA/GA_Iterator.h> #include <iostream> using namespace std; int main(){ GU_Detail gdp; gdp.load("geos/box.bgeo"); cout << "Numpoints:"<<gdp.getNumPoints() <<endl; cout << "NumVerticles" << gdp.getNumVertices() << endl; cout << "NumFace:" << gdp.getNumPrimitives() << endl; // LOOP All face, cout this vertex count GEO_Primitive *geoPrim; GA_FOR_ALL_PRIMITIVES(&gdp,geoPrim){ int faceCount = geoPrim->getVertexCount() ;// per face have 3 point } cout << "------------------ Iterator Face ID & Per face point ID, this can used GL_DRAW_ELMENTS()----------------\n"; GA_Iterator primIter(gdp.getPrimitiveRange()); fpreal start_primtive_num = *primIter; cout << "START primtive num:" << start_primtive_num << endl; // loop the face(prim) for (;!primIter.atEnd();++primIter) { GA_Primitive *prim = gdp.getPrimitive(*primIter); // iterator face points cout <<"this face id :" << *primIter <<"->have vertex count:" <<prim->getVertexCount() << endl; GA_Iterator pointIter(prim->getPointRange()); for(;!pointIter.atEnd();++pointIter){ cout <<"share point id:" <<*pointIter << endl; } } cout << "------------------ access points Iterator directly not opengl draw indcices----------------\n"; // Loop the point, direct access the point , not prim vertex shared point GA_Iterator pointIter(gdp.getPointRange()); while(!pointIter.atEnd()){ int pointNum = *pointIter ; GA_Index pointIndex = gdp.pointIndex(*pointIter); GA_Offset pointOffset = gdp.pointOffset(pointIndex); cout <<"Lookup -> Point id:" <<*pointIter << " Point Index:" << pointIndex << " Point offset:" << pointOffset << endl; GA_OffsetArray orry; gdp.getVerticesReferencingPoint(orry,pointOffset); cout <<"And this point have "<< orry.size() << " verticles, and the vertex number:" ; for(auto &of: orry){ cout << of << " "; } cout << endl; ++pointIter; } cin.get(); return 0; }
The GA_Primitive class is a base class, GEO manipulate 3d Geometry further .
一些名词:Attribute Type Implementation (ATI), Each ATI class maintains arrays of data for each element in the geometry.The ATI provides interfaces (AIFs) for accessing the data.
Some ATIs include GA_ATINumeric, GA_ATIString, GA_ATIIndexPair. Some AIFs include GA_AIFTuple, GA_AIFSharedStringTuple, GA_AIFInterp. Numeric and string attributes can be accessed more easily and directly using the classes in GA_Handle.h (e.g. GA_ROHandleV3, GA_RWHandleS), and GA_PageHandle.h (e.g. GA_RWPageHandleV3).
属性的载体拥有者:
属性的GA_StorageClass
属性的长度:
GA_Attribute *att;
att->getTupleSize();
1为浮点(GA_StorageClass)的类型属性,
2为长度为2浮点(GA_StorageClass)类型,
3为长度为3的向量(GA_StorageClass)
.....
2,访问属性
GA_Attribute必须要作为参数输入到GA_RWHandle 开始的类对象,然后可以检查属性的可访问性。RW意思代表可以直接改属性到gdp
#include <GU/GU_Detail.h> #include <GEO/GEO_Primitive.h> #include <GEO/GEO_PrimPoly.h> #include <GA/GA_Primitive.h> #include <GA/GA_Iterator.h> #include <GA/GA_SaveOptions.h> #include <GEO/GEO_AttributeHandle.h> #include <iostream> using namespace std; int main(){ GU_Detail gdp; gdp.load("geos/box.bgeo"); cout << "Numpoints:"<<gdp.getNumPoints() <<endl; cout << "NumVerticles" << gdp.getNumVertices() << endl; cout << "NumFace:" << gdp.getNumPrimitives() << endl; // LOOP All face, cout this vertex count GEO_Primitive *geoPrim; GA_FOR_ALL_PRIMITIVES(&gdp,geoPrim){ int faceCount = geoPrim->getVertexCount() ;// per face have 3 point } cout << "------------------ Iterator Face ID & Per face point ID, this can used GL_DRAW_ELMENTS()----------------\n"; GA_Iterator primIter(gdp.getPrimitiveRange()); fpreal start_primtive_num = *primIter; cout << "START primtive num:" << start_primtive_num << endl; // loop the face(prim) for (;!primIter.atEnd();++primIter) { GA_Primitive *prim = gdp.getPrimitive(*primIter); // iterator face points cout <<"this face id :" << *primIter <<"->have vertex count:" <<prim->getVertexCount() << endl; GA_Iterator pointIter(prim->getPointRange()); for(;!pointIter.atEnd();++pointIter){ cout <<"share point id:" <<*pointIter << endl; } } cout << "------------------ access points Iterator directly not opengl draw indcices----------------\n"; cout << "method 1:\n"; GA_Attribute *att =gdp.findPointAttribute("P"); cout <<"attribute size:" <<att->getTupleSize() <<endl; GA_RWHandleV3 PAttribHandle(att); // Loop the point, direct access the point , not prim vertex shared point GA_Iterator pointIter(gdp.getPointRange()); while(!pointIter.atEnd()){ int pointNum = *pointIter ; // This is point offset GA_Index pointIndex = gdp.pointIndex(*pointIter); // This is point index GA_Offset pointOffset = gdp.pointOffset(pointIndex); // This is point offset // ------ access the Position attribute ---------- if(PAttribHandle.isValid()){ UT_Vector3 P = PAttribHandle.get(pointOffset); cout <<"position: "<< P.x() << " " << P.y() << " " << P.z() <<endl; } else{ cout << "can not access the Position \n"; } ++pointIter; } cout << "method 2:\n"; GA_RWHandleV3 Phandle(&gdp, GA_ATTRIB_POINT, "P"); if (Phandle.isValid()) { for (GA_Iterator it(gdp.getPointRange()); !it.atEnd(); ++it) { GA_Offset offset = *it; UT_Vector3 P = Phandle.get(offset); cout <<"position: "<< P.x() << " " << P.y() << " " << P.z() <<endl; P.y()+= 2.0; Phandle.set(offset, P); } } // save to disk GA_SaveOptions saveOptions; gdp.save("change.bgeo",&saveOptions); cout << "method 3\n"; GA_Attribute *attrib = gdp.findFloatTuple(GA_ATTRIB_POINT, "N", 3); const GA_AIFTuple *tuple = attrib->getAIFTuple(); if (tuple) { UT_Vector3 P; for (GA_Iterator it(gdp.getPointRange()); !it.atEnd(); it.advance()) { GA_Offset offset = it.getOffset(); tuple->get(attrib, offset, P.data(), 3); // change P // ..... tuple->set(attrib, offset, P.data(), 3); } } cin.get(); return 0; }
String Attribute:
假设面属性:
修改后:
#include <GU/GU_Detail.h> #include <GEO/GEO_Primitive.h> #include <GEO/GEO_PrimPoly.h> #include <GA/GA_Primitive.h> #include <GA/GA_Iterator.h> #include <GA/GA_SaveOptions.h> #include <GEO/GEO_AttributeHandle.h> #include <iostream> using namespace std; int main(){ GU_Detail gdp; gdp.load("geos/box.bgeo"); cout << "Numpoints:"<<gdp.getNumPoints() <<endl; cout << "NumVerticles" << gdp.getNumVertices() << endl; cout << "NumFace:" << gdp.getNumPrimitives() << endl; GA_RWHandleS strAttrib(&gdp,GA_ATTRIB_PRIMITIVE, "mystr"); if(!strAttrib.isValid()){ cout << "Can not find primtive attribute\n"; return 1; } for(GA_Iterator iter(gdp.getPrimitiveRange()); !iter.atEnd(); ++iter){ GA_Offset offset = *iter; UT_String value(strAttrib.get(offset) ); value.append("_CPP"); UT_StringHolder holder(value.c_str()); strAttrib.set(offset, holder); cout << value <<endl; } // save to disk GA_SaveOptions saveOptions; gdp.save("change.bgeo",&saveOptions); cin.get(); return 0; }
遍历器所有属性,但是始终需要GA_Offset来引导获得真正的属性值:祭出我以前把H17.5的GU_Detail发送给Katana3.2,这样katana可以读取houdini的bgeo
// Copyright (c) 2016 The Foundry Visionmongers, Ltd. #include <FnGeolib/op/FnGeolibOp.h> #include <FnAttribute/FnAttribute.h> #include <GU/GU_Detail.h> #include <iostream> #include <FnGeolibServices/FnGeolibCookInterfaceUtilsService.h> using namespace std; namespace { // "Hello World"-style op that sets a string attribute at the root location. class HelloWorldOp : public Foundry::Katana::GeolibOp { public: // Boilerplate that indicates the Op's cook() function is safe to be called // concurrently. static void setup(Foundry::Katana::GeolibSetupInterface& interface) { interface.setThreading( Foundry::Katana::GeolibSetupInterface::ThreadModeConcurrent); } static void cook(Foundry::Katana::GeolibCookInterface& interface) { FnAttribute::StringAttribute celAttr = interface.getOpArg("CEL"); if (!celAttr.isValid()) { interface.stopChildTraversal(); return; } FnGeolibServices::FnGeolibCookInterfaceUtils::MatchesCELInfo info; FnGeolibServices::FnGeolibCookInterfaceUtils::matchesCEL(info, interface, celAttr); if (!info.canMatchChildren) { interface.stopChildTraversal(); } // If the CEL doesn't match the current location, stop cooking if (!info.matches) { return; } FnAttribute::StringAttribute bgeoFileAttr = interface.getOpArg("bgeoFile"); if (!bgeoFileAttr.isValid()) { cout << "Can not find bgeoFile attribute in param\n"; return; } string bgeoStr = bgeoFileAttr.getValue(); interface.setAttr("type", FnAttribute::StringAttribute("pointcloud")); GU_Detail gdp; gdp.load(bgeoStr.c_str()); uint64 numpt = gdp.getNumPoints(); GA_Iterator iter(gdp.getPointRange()); fpreal start_point_num = *iter; for (GA_AttributeDict::iterator it = gdp.getAttributeDict(GA_ATTRIB_POINT).begin(GA_SCOPE_PUBLIC); !it.atEnd(); ++it) { GA_Attribute *attrib = it.attrib(); UT_String attribName (attrib->getName()); int attSize = attrib->getTupleSize(); GA_StorageClass storage = attrib->getStorageClass(); cout << "loop attribute " << attribName << endl; if (attSize == 1) { if (storage == GA_STORECLASS_FLOAT) { // FLOAT Attribute float * floatValues = new float[numpt]; GA_RWHandleF handle(attrib); for (uint64 i = start_point_num; i < numpt + start_point_num; i++) { uint64 KTNStride = i - start_point_num; // set Houdini attribute for mem floatValues[KTNStride] = handle.get(i); } // Attribute for arbitrary value string katanaAttributeName = string("geometry.arbitrary.") + string(attribName.c_str()) + string(".value"); string scopeAttribName = string("geometry.arbitrary.") + string(attribName.c_str()) + string(".scope"); // Set the scope attribute interface.setAttr(scopeAttribName.c_str(), FnAttribute::StringAttribute("point"), false); // create KATANA attribute for interface FnAttribute::FloatAttribute KTNAttribute(floatValues, numpt, 1); // create KATANA attribute for interface values interface.setAttr(katanaAttributeName.c_str(), KTNAttribute, false); // Release mem delete []floatValues; } if (storage == GA_STORECLASS_INT) { // INT Attribute int * intValues = new int[numpt]; GA_RWHandleI handle(attrib); for (uint64 i = start_point_num; i < numpt + start_point_num; i++) { uint64 KTNStride = i - start_point_num; // set Houdini attribute for mem intValues[KTNStride] = handle.get(i); } // Attribute for arbitrary value string katanaAttributeName = string("geometry.arbitrary.") + string(attribName.c_str()) + string(".value"); string scopeAttribName = string("geometry.arbitrary.") + string(attribName.c_str()) + string(".scope"); // Set the scope attribute interface.setAttr(scopeAttribName.c_str(), FnAttribute::StringAttribute("point"), false); // create KATANA attribute for interface values FnAttribute::IntAttribute KTNAttribute(intValues, numpt, 1); interface.setAttr(katanaAttributeName.c_str(), KTNAttribute, false); // Release mem delete[]intValues; } } else if (attSize == 3) { cout << "Vector attribute:" << attribName << endl; float * newPoints = new float[numpt * 3]; GA_RWHandleV3 handle(attrib); for (uint64 i = start_point_num; i < numpt + start_point_num; i++) { float x = float(handle.get(i).x()); float y = float(handle.get(i).y()); float z = float(handle.get(i).z()); // KTN index uint64 KTNStride = i - start_point_num; uint64 xIndex = KTNStride * 3; uint64 yIndex = KTNStride * 3 + 1; uint64 zIndex = KTNStride * 3 + 2; // set Houdini attribute for mem newPoints[xIndex] = x; newPoints[yIndex] = y; newPoints[zIndex] = z; } string katanaAttributeName; if (attribName == "P" || attribName == "v") { katanaAttributeName = string("geometry.point.") + string(attribName.c_str()); // create KATANA attribute for interface } else { katanaAttributeName = string("geometry.arbitrary.") + string(attribName.c_str()) + string(".value"); // SCOPE NAME FOR arnold AI_UserData_RGB string scopeAttribName = string("geometry.arbitrary.") + string(attribName.c_str()) + string(".scope"); string inputTypeAttribName = string("geometry.arbitrary.") + string(attribName.c_str()) + string(".inputType"); interface.setAttr(scopeAttribName.c_str(), FnAttribute::StringAttribute("point"), false); interface.setAttr(inputTypeAttribName.c_str(), FnAttribute::StringAttribute("vector3"), false); } FnAttribute::FloatAttribute vectorAttribute(newPoints, numpt * 3, 3); interface.setAttr(katanaAttributeName.c_str(), vectorAttribute, false); // Release mem delete[]newPoints; } else if (attSize == 4) { } else { cout << " do not support this the attribute:" << attribName << endl;; } } } }; DEFINE_GEOLIBOP_PLUGIN(HelloWorldOp) } // namespace void registerPlugins() { REGISTER_PLUGIN(HelloWorldOp, "HelloWorld", 0, 1); }
官网也说的清:
//Each GA_AttributeOwner has its own dictionary of attributes that can be searched or traversed independently. Aside from the public attributes, a dictionary can contain private and group attributes, so be careful about scope during traversal. //For example, to traverse all the public primitive attributes in an undefined order: for (GA_AttributeDict::iterator it = gdp->getAttributeDict(GA_ATTRIB_PRIMITIVE).begin(GA_SCOPE_PUBLIC); !it.atEnd(); it.advance()) { GA_Attribute *attrib = it.attrib(); ... } //To traverse all the public primitive attributes in a well-defined (alpabetic) order: for (GA_AttributeDict::ordered_iterator it = gdp->getAttributeDict(GA_ATTRIB_PRIMITIVE).obegin(GA_SCOPE_PUBLIC); !it.atEnd(); it.advance()) { GA_Attribute *attrib = it.attrib(); ... }
当然也可以使用 GA/GA_GBMacros.h 提供的宏函数:
GA_Attribute *Patt = gdp.findPointAttribute("P"); GA_RWHandleV3 Phandle(Patt); GA_Offset ptoff; GA_FOR_ALL_PTOFF(&gdp,ptoff){ UT_Vector3 P = Phandle.get(ptoff); P.y()+=1.0f; Phandle.set(ptoff,P ); }
当然:Handle的构造也可以直接从gdp构造,不用GA_Attribute,假设你不想知道 属性的信息。
// Read only, from named attribute GA_ROHandleV3 vel_h(const_gdp, GEO_POINT_DICT, "v"); // Read write, from a named attribute, but must be at least 2 floats GA_RWHandleF life_h(gdp, GEO_POINT_DICT, "life", 2); // From an existing const GA_Attribute * GA_ROHandleI id_h(const_attribute); // From a GA_AttributeRef, (common when interfacing with legacy code) GA_RWAttributeRef scale_gah(gdp->findFloatTuple(GEO_POINT_DICT, "pscale")); GA_RWHandleF scale_h(scale_gah.getAttribute());
3,并行访问设置属性:
cmake_minimum_required(VERSION 3.5) project(Triangle) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) # OPENGL find_package(OpenGL REQUIRED) include_directories(${OpenGL_INCLUDE_DIRS}) link_directories(${OpenGL_LIBRARY_DIRS}) add_definitions(${OpenGL_DEFINITIONS}) if(NOT OPENGL_FOUND) message(ERROR " OPENGL not found!") endif(NOT OPENGL_FOUND) # GLEW set(GLEW_HOME D:/plugin_dev/libs/glew-2.1.0) include_directories(${GLEW_HOME}/include) link_directories(${GLEW_HOME}/lib/Release/x64) # GLFW set(GLFW_HOME D:/plugin_dev/libs/glfw-3.3.1.bin.WIN64) include_directories(${GLFW_HOME}/include/) link_directories(${GLFW_HOME}/lib-vc2019) # STB include_directories(D:/plugin_dev/libs/stb) # GLM include_directories(D:/plugin_dev/libs/GLM_include) # openmp find_package(OpenMP) if (OPENMP_FOUND) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}") endif() # ---------------- HOUDINI if (MSVC) # Prevent Boost auto-linking. add_definitions(-DBOOST_ALL_NO_LIB ) add_definitions(-D_SCL_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS -D_WIN32 -D_WINSOCK_DEPRECATED_NO_WARNINGS -D__x86_64__) # HOUDINI : add_definitions(-TP -Zc:forScope -DVERSION="18.0.348" -DI386 -DWIN32 -DSWAP_BITFIELDS -DWINVER=0x0501 -DNOMINMAX -DSTRICT -DWIN32_LEAN_AND_MEAN -D_USE_MATH_DEFINES -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE -D_SCL_SECURE_NO_WARNINGS -DSESI_LITTLE_ENDIAN -DHBOOST_ALL_NO_LIB -DEIGEN_MALLOC_ALREADY_ALIGNED=0 -DFBX_ENABLED=1 -DOPENCL_ENABLED=1 -DOPENVDB_ENABLED=1 -MD -EHsc -GR -DNEED_SPECIALIZATION_STORAGE -DAMD64 -DSIZEOF_VOID_P=8) endif() set(HOUDINI_HOME "D:/Program Files/Side Effects Software/Houdini 18.0.348") include_directories("${HOUDINI_HOME}/toolkit/include") link_directories("${HOUDINI_HOME}/custom/houdini/dsolib") # output excutable dir set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/build) # SRC FILE FILE( GLOB SRC *.cpp *.h ) add_executable(Triangle ${SRC}) target_link_libraries(Triangle PRIVATE libGA.lib libGU.lib libUT.lib libCE.lib libLM.lib libFS.lib libSYS.lib libGEO.lib )
Add life attribute, then set value parallel:
1 >> 没有用GA_RWHandleF,因为我测试后是线程不安全。如果用GA_RWPageHandleF 将是线程安全。
// or iterate using a GA_PageIterator - this gives contiguous blocks GA_Attribute *LifeAtt = gdp.addFloatTuple(GA_ATTRIB_POINT,GA_SCOPE_PUBLIC,"life",1); GA_RWPageHandleF Life_pageHandle(LifeAtt); GA_Offset block_start, block_end; for (GA_Iterator pageI(gdp.getPointRange()); pageI.blockAdvance(block_start, block_end); ) { Life_pageHandle.setPage(block_start); #pragma omp parallel for for (int ptoff = block_start; ptoff < block_end; ++ptoff){ Life_pageHandle.value(ptoff) = ptoff; // direct data access } }
上面的指示把每一个page里的点并行了,不是并行的page,page相当于TBB的block.我觉得这个方式可能会出问题。相当于block是串行,block里面的东西并行。
所以属性可以直接作为Page的默认参数,也可以直接从gdp获取:
GA_ROPageHandleV3 v_ph(gdp, GEO_POINT_DICT, "v"); GA_RWPageHandleV3 p_ph(gdp->getP());
2 >> 使用UTparallelFor()来制作并行处理,实际上是TBB那套。TBB这套必须分Block,每个block有多大。有多少个Block(每个block都是相互独立并行),在houdini我觉得对应Page id(每个Page都是相互独立并行)
图示:
做了个20* 20 * 20的立方体共:2168个点,每个block/page 的大小为1024,总共能分三块:
#include <GU/GU_Detail.h> #include <GEO/GEO_Primitive.h> #include <GEO/GEO_PrimPoly.h> #include <GA/GA_Primitive.h> #include <GA/GA_Iterator.h> #include <GA/GA_SaveOptions.h> #include <GEO/GEO_AttributeHandle.h> #include <GA/GA_PageHandle.h> #include <GA/GA_GBMacros.h> #include <GA/GA_AttributeRefMap.h> #include <UT/UT_ThreadedAlgorithm.h> #include <UT/UT_ParallelUtil.h> #include <GA/GA_PageIterator.h> #include <GA/GA_Range.h> #include <iostream> #include <omp.h> using namespace std; struct MoveY{ MoveY(const GA_RWAttributeRef &attRef):rwAttrRef(attRef){ } void operator()(const GA_SplittableRange &r) const { GA_RWPageHandleV3 pageHandle(rwAttrRef.getAttribute()); // Use Page Handle to point attribute // Iterate over pages in the range for (GA_PageIterator pit = r.beginPages(); !pit.atEnd(); ++pit) { GA_Offset start, end; // iterate over the elements in the page. for (GA_Iterator it(pit.begin()); it.blockAdvance(start, end); ) { // Perform any per-page setup required, then pageHandle.setPage(start); cerr <<" --------------PAGE:" <<start <<"----------------------"<<endl; for (GA_Offset i = start; i < end; ++i) { UT_Vector3 P = pageHandle.get(i); P.y()+=5; pageHandle.set(i, P); } } } // page iter } GA_RWAttributeRef rwAttrRef; }; void DoMove(const GA_Range &range, const GA_RWAttributeRef &attRef) { // Create a GA_SplittableRange from the original range UTparallelFor(GA_SplittableRange(range), MoveY(attRef)); } int main(){ GU_Detail gdp; gdp.load("geos/box.bgeo"); GA_RWAttributeRef attRef(gdp.findPointAttribute("P")); GA_Range range = gdp.getPointRange(); if(!attRef.isValid()) cout << "can not change P\n"; else{ DoMove(range,attRef); } // save to disk GA_SaveOptions saveOptions; gdp.save("geos/change.bgeo.sc",&saveOptions); cout << "ret end\n"; cin.get(); return 0; }
从返回结果看是没问题的。每个块独立。
3>>还有一种方案,只不过对GA_Offset稍微麻烦点,如果单纯的bgeo直接操作属性,不用管这个事情
这里还有一个问题是page.setPage()不知道性能消耗大不,我将每个offset 对到 page上:
class MoveY2 { public: MoveY2(GA_Attribute *att) : attrib(att) {} void operator()(const UT_BlockedRange<int64> &range) const { GA_RWPageHandleV3 myPageHandle(attrib); for (int64 i = range.begin(); i != range.end(); ++i) { myPageHandle.setPage(i); UT_Vector3 &value = myPageHandle.value(i); value.y()+= 5.0f; } } GA_Attribute *attrib; }; void DoMove2(GA_Attribute *attrib, int64 length) { UTparallelFor(UT_BlockedRange<int64>(0, length), MoveY2(attrib)); }
C++11 Thread构建块我也做过,根据线程数目分块
4, add attribute
1,GA_Attribute&GA_RWHandleF,GA_RWHandleV3, Basis add point number to the age attribute and for normal <0,1,0>
#include <GU/GU_Detail.h> #include <GEO/GEO_Primitive.h> #include <GEO/GEO_PrimPoly.h> #include <GA/GA_Primitive.h> #include <GA/GA_Iterator.h> #include <GA/GA_SaveOptions.h> #include <GEO/GEO_AttributeHandle.h> #include <iostream> using namespace std; int main(){ GU_Detail gdp; gdp.load("geos/box.bgeo"); // add float attribute GA_Attribute *ageAttribute = gdp.addFloatTuple(GA_ATTRIB_POINT,GA_SCOPE_PUBLIC,"age",1); GA_RWHandleF ageHandle(ageAttribute); for(GA_Iterator it(gdp.getPointRange()) ; !it.atEnd(); it.advance()) { GA_Offset offset = *it; ageHandle.set(offset,*it); } // add vector N attribute GA_Attribute *normalAttribute = gdp.addFloatTuple(GA_ATTRIB_POINT, GA_SCOPE_PUBLIC, "N", 3); GA_RWHandleV3 NHandle(normalAttribute); if (!NHandle.isValid() ) { cout << "can not change N attribute\n"; return 0; } for(GA_Iterator it(gdp.getPointRange()) ; !it.atEnd(); it.advance()) { GA_Offset offset = *it; NHandle.set(offset,UT_Vector3(0.f,1.0f,0.0f)); } // save to disk GA_SaveOptions saveOptions; gdp.save("geos/change.bgeo",&saveOptions); cout << "ret end\n"; cin.get(); return 0; }
GU_Detail的添加属性方法重载比较多,最常用的添加public属性:
GA_Attribute *att = gdp.addFloatTuple(GA_ATTRIB_POINT,"attname",3); // float vector attribute GA_Attribute *att = gdp.addFloatTuple(GA_ATTRIB_POINT,GA_SCOPE_PUBLIC, "attname",3); // float vector attribute
5,选择一部分属性,执行线性插值:
GA_AttributeRefMap
#include <GU/GU_Detail.h> #include <GEO/GEO_Primitive.h> #include <GEO/GEO_PrimPoly.h> #include <GA/GA_Primitive.h> #include <GA/GA_Iterator.h> #include <GA/GA_SaveOptions.h> #include <GEO/GEO_AttributeHandle.h> #include <GA/GA_PageHandle.h> #include <GA/GA_GBMacros.h> #include <GA/GA_AttributeRefMap.h> #include <iostream> #include <omp.h> using namespace std; int main(){ GU_Detail gdp; gdp.load("geos/line.bgeo"); GA_Iterator iter(gdp.getPointRange()) ; GA_Offset pt0 = *iter; GA_Offset pt1 = pt0 + 1; GA_Offset new_pt = gdp.appendPoint(); GA_AttributeRefMap hmap(gdp); // Append all point & vertex attributes (including "P") hmap.append(GA_AttributeFilter::selectNumeric(), GA_ATTRIB_POINT); // Perform linear interpolation, writing to new_vtx hmap.lerpValue(GA_ATTRIB_POINT, new_pt, GA_ATTRIB_POINT, pt0, pt1 , .5); // save to disk GA_SaveOptions saveOptions; gdp.save("geos/change.bgeo.sc",&saveOptions); cout << "ret end\n"; cin.get(); return 0; }
中间生成的点,把所有的点属性都插值,包括P,Cd。这里按照0.5的bias
6, Read the binary .Bgeo. from python
try: # Try for ASCII/binary support import hjson json = hjson except: # Fall back to only ASCII support import simplejson json = simplejson fileName = "D:/line.bgeo" geo = json.load(open(fileName, 'rb')) print json.dumps(geo, binary=False, indent=4)
剩下的可以按照geo[]来取值。hjson文档说是python的高性能使用方法。
7,Eliminating GEO_Point,Do Not USE GEO_Point:
The GA library doesn't store point (GEO_Point) or vertex (GEO_Vertex) objects,然而你依然可以获取GB方式的GEO_Point:
GEO_Point *ppt = gdp->getGBPoint();
Rather than using GEO_Point objects, try to use the GA_Offset of the point. 访问GEO_Point属于间接方式,不是直接方式。GA Keep memory usage lower (no persistent objects)
8,Create Geometry
colsed polygon
#include <GU/GU_Detail.h> #include <GEO/GEO_Primitive.h> #include <GEO/GEO_PrimPoly.h> #include <GA/GA_Primitive.h> #include <GA/GA_Iterator.h> #include <GA/GA_SaveOptions.h> #include <GEO/GEO_AttributeHandle.h> #include <GA/GA_PageHandle.h> #include <GA/GA_GBMacros.h> #include <GA/GA_AttributeRefMap.h> #include <UT/UT_ThreadedAlgorithm.h> #include <UT/UT_ParallelUtil.h> #include <GA/GA_PageIterator.h> #include <GA/GA_Range.h> #include <iostream> #include <omp.h> using namespace std; const int npoints = 3; int main(){ GU_Detail gdp; //gdp.load("geos/box.bgeo"); gdp.clearAndDestroy(); GA_Offset start_vtxoff; GA_Offset start_ptoff ; // @arg1 = GA_PRIMPOLY // @arg2 = nprimitives // @arg3 = nvertices_each // @arg4 = vertex_block_start // @arg5 = close polygon gdp.appendPrimitivesAndVertices(GA_PRIMPOLY, 1, npoints, start_vtxoff, true); // Create the right number of points, as a contiguous block start_ptoff = gdp.appendPointBlock(npoints); // Wire the vertices to the points. for (exint i = 0; i < npoints; ++i) { gdp.getTopology().wireVertexPoint(start_vtxoff+i,start_ptoff+i); } // We added points, vertices, and primitives, // so this will bump all topology attribute data IDs, // P's data ID, and the primitive list data ID. gdp.bumpDataIdsForAddOrRemove(true, true, true); UT_Vector3 Ps[3] = { UT_Vector3(-1,0,0), UT_Vector3(1,0,0), UT_Vector3(0,1,0) }; for(int i =0; i< npoints;i++){ GA_Offset offset = i+ start_ptoff; gdp.setPos3(offset, Ps[i]); } // save to disk GA_SaveOptions saveOptions; gdp.save("geos/change.bgeo.sc",&saveOptions); cout << "ret end\n"; cin.get(); return 0; }
9:TBN Matrix
#include <GU/GU_Detail.h> #include <GEO/GEO_Primitive.h> #include <GEO/GEO_PrimPoly.h> #include <GA/GA_Primitive.h> #include <GA/GA_Iterator.h> #include <GA/GA_SaveOptions.h> #include <GEO/GEO_AttributeHandle.h> #include <GA/GA_PageHandle.h> #include <GA/GA_GBMacros.h> #include <GA/GA_AttributeRefMap.h> #include <UT/UT_ThreadedAlgorithm.h> #include <UT/UT_ParallelUtil.h> #include <GA/GA_PageIterator.h> #include <GA/GA_Range.h> #include <GU/GU_DetailHandle.h> #include <GU/GU_PackedGeometry.h> #include <GU/GU_PrimPacked.h> #include <GU/GU_PolyFrame.h> #include <iostream> #include <omp.h> using namespace std; int main(){ UT_Options option; GU_Detail *gdp = new GU_Detail; GU_Detail::IOStatus stat = gdp->load("geos/grid.bgeo"); if(! stat.success() ){ cout << "load file error\n"; } cout << gdp->getNumPoints() << endl; GU_PolyFrame polyframe(gdp); GU_PolyFrameParms polyframeParms; polyframeParms.style = GU_POLYFRAME_TEXTURE; polyframeParms.left_handed = false; polyframeParms.orthogonal = true; polyframeParms.which = GU_POLYFRAME_NORMAL | GU_POLYFRAME_BITANGENT | GU_POLYFRAME_TANGENT ; polyframeParms.uv_name = "uv"; polyframeParms.names[0] = "T"; polyframeParms.names[1] = "B"; polyframeParms.names[2] = "N"; polyframe.computeFrames(polyframeParms); GA_SaveOptions save_option; gdp->save("geos/grid_pf.bgeo",&save_option); delete gdp; cin.get(); return 0; }
10:GU_PrimPacked Packed GEOMETRY:
操作pack首选GU_PrimPacked,从类关系看应该是最全的。
REF:tookit->samples->SOP_CopyPacked.C
#include <GU/GU_Detail.h> #include <GEO/GEO_Primitive.h> #include <GEO/GEO_PrimPoly.h> #include <GA/GA_Primitive.h> #include <GA/GA_Iterator.h> #include <GA/GA_SaveOptions.h> #include <GEO/GEO_AttributeHandle.h> #include <GA/GA_PageHandle.h> #include <GA/GA_GBMacros.h> #include <GA/GA_AttributeRefMap.h> #include <UT/UT_ThreadedAlgorithm.h> #include <UT/UT_ParallelUtil.h> #include <GA/GA_PageIterator.h> #include <GA/GA_Range.h> #include <GU/GU_DetailHandle.h> #include <GU/GU_PackedGeometry.h> #include <GU/GU_PrimPacked.h> #include <GU/GU_PolyFrame.h> #include <GA/GA_LoadOptions.h> #include <iostream> #include <omp.h> using namespace std; int main(){ GA_LoadOptions load_option; GU_Detail *gdp = new GU_Detail; gdp->loadIODSOs(); // make sure can load packed geo GU_Detail::IOStatus stat = gdp->load("geos/packed.bgeo",&load_option); if(! stat.success() ){ cout << "load file error\n"; } cout << "static method->Has packed prim:"<<GU_PrimPacked::hasPackedPrimitives(*gdp) << endl; cout << "static method->Has packed num of prim:" << GU_PrimPacked::countPackedPrimitives(*gdp) << endl; cout << "Num points:"<<gdp->getNumPoints() << endl; cout << "Num Prims:"<<gdp->getNumPrimitives() << endl; GA_RWHandleS pathAttribHandle(gdp,GA_ATTRIB_PRIMITIVE,"path"); for(GA_Iterator it(gdp->getPrimitiveRange()); !it.atEnd(); it.advance()){ GA_Primitive *prim = gdp->getPrimitive(*it); GU_PrimPacked *pack_prim = static_cast<GU_PrimPacked*>(prim); cout << pathAttribHandle.get(*it) << endl; } //GA_SaveOptions save_option; //gdp->save("geos/grid_pf.bgeo",&save_option); delete gdp; cin.get(); return 0; }
11, NOT TESTED
https://www.sidefx.com/docs/hdk/class_g_a___attribute_ref_map.html
// Compute the average value of the P attribute and store in a // global attribute "averageP". GA_WeightedSum sum; GA_AttributeRefMap map(gdp); GA_AttributeRefMap::Handle gah(map); int npts; map.append( detail.findGlobalAttribute("averageP"), detail.findPointAttribute("P") ); gah.setGlobal(); // Write to global attributes gah.startSum(sum); for (GA_Iterator it = gdp.getPointRange(); !it.atEnd(); ++it) gah.sumPoint(sum, it.getOffset(), 1); npts = gdp.getNumPoints(); gah.finishSum(sum, npts ? 1./npts : 0);
REF:https://www.sidefx.com/docs/hdk/index.html
GA User Guide:https://www.sidefx.com/docs/hdk/_h_d_k__g_a__using.html#HDK_GA_Using_GEO_Point 讲解的非常详细GA/GB的各种操作
GA Porting Guide:https://www.sidefx.com/docs/hdk/_h_d_k__g_a__porting.html#HDK_GA_PortingCookbook_Simple_Name_Translation 各种GA的案例,必须删除点,删除未使用面....