131 tboolean-box-sphere()
132 {
133 local operation=${1:-difference}
134 local material=$(tboolean-material)
135 local inscribe=$(python -c "import math ; print 1.3*200/math.sqrt(3)")
136 local test_config=(
137 mode=BoxInBox
138 analytic=1
139
140 node=box parameters=0,0,0,1000 boundary=Rock//perfectAbsorbSurface/Vacuum
141
142 node=$operation parameters=0,0,0,300 boundary=Vacuum///$material
143 node=box parameters=0,0,0,$inscribe boundary=Vacuum///$material
144 node=sphere parameters=0,0,0,200 boundary=Vacuum///$material
145 )
146
147 echo "$(join _ ${test_config[@]})"
148 }
GGeoTestConfig::GGeoTestConfig(const char* config)
simon:opticks blyth$ opticks-lfind GGeoTestConfig
./bin/oks.bash
./cfg4/cfg4.bash
./ggeo/ggeodev.bash
./ggeo/CMakeLists.txt
./ggeo/GGeo.cc
./ggeo/GGeoTestConfig.cc
./ggeo/GGeoTestConfig.hh
./ggeo/GGeoTest.cc
./ggeo/GGeoTest.hh
./ggeo/tests/GGeoTestTest.cc
./cfg4/CGeometry.cc
./cfg4/CTestDetector.cc
./cfg4/CTestDetector.hh
./cfg4/tests/CTestDetectorTest.cc
743 void GGeo::modifyGeometry(const char* config)
744 {
745 // NB only invoked with test option : "ggv --test"
746 GGeoTestConfig* gtc = new GGeoTestConfig(config);
747
748 LOG(trace) << "GGeo::modifyGeometry"
749 << " config [" << ( config ? config : "" ) << "]" ;
750
751 assert(m_geotest == NULL);
752
753 m_geotest = new GGeoTest(m_opticks, gtc, this);
754 m_geotest->modifyGeometry();
755 }
233 GMergedMesh* GGeoTest::createBoxInBox()
234 {
235 std::vector<GSolid*> solids ;
236 unsigned int n = m_config->getNumElements();
237
238 for(unsigned int i=0 ; i < n ; i++)
239 {
240 std::string node = m_config->getNodeString(i);
241 char nodecode = m_config->getNode(i) ;
242 const char* spec = m_config->getBoundary(i);
243 glm::vec4 param = m_config->getParameters(i);
244 glm::mat4 trans = m_config->getTransform(i);
245 unsigned int boundary = m_bndlib->addBoundary(spec);
...
258 if(nodecode == 'U') LOG(fatal) << "GGeoTest::createBoxInBox configured node not implemented " << node ;
259 assert(nodecode != 'U');
260
261 GSolid* solid = m_maker->make(i, nodecode, param, spec );
262 solids.push_back(solid);
263
264 // TODO: handle csg tree nodes, that break the 1-to-1
265 }
104 GSolid* GMaker::make(unsigned int /*index*/, char shapecode, glm::vec4& param, const char* spec )
105 {
106 // invoked from eg GGeoTest::createBoxInBox while looping over configured shape/boundary/param entries
107 // hmm for generality a boolean shape needs to reference two others, the prior two?
108 // hmm this is too soon to do booleans, need the basis solids first
109 // unless handle booleans by setting constituent flag
110
111 GSolid* solid = NULL ;
112 switch(shapecode)
113 {
114 case 'B': solid = makeBox(param); break;
115 case 'M': solid = makePrism(param, spec); break;
116 case 'S': solid = makeSubdivSphere(param, 3, "I") ; break; // I:icosahedron O:octahedron HO:hemi-octahedron C:cube
117 case 'Z': solid = makeZSphere(param) ; break;
118 case 'L': solid = makeZSphereIntersect(param, spec) ; break; // composite handled by adding child node
119 case 'I': solid = makeBox(param); break ; // boolean intersect
120 case 'J': solid = makeBox(param); break ; // boolean union
121 case 'K': solid = makeBox(param); break ; // boolean difference
122 }
123 assert(solid);
124
125 OpticksShape_t shapeflag = GMaker::NodeFlag(shapecode) ;
126 solid->setShapeFlag( shapeflag );
127
128 // TODO: most parts alread hooked up above, do this uniformly
129 GParts* pts = solid->getParts();
130 if(pts == NULL)
131 {
132 pts = GParts::make(shapecode, param, spec);
133 solid->setParts(pts);
134 }
135 assert(pts);
136
137 unsigned boundary = m_bndlib->addBoundary(spec); // only adds if not existing
138 solid->setBoundaryAll(boundary); // All loops over immediate children, needed for composite
139 pts->setBoundaryAll(boundary);
140 pts->enlargeBBoxAll(0.01f );
141
142 return solid ;
143 }
1250 RT_PROGRAM void intersect(int primIdx)
1251 {
1252 const uint4& prim = primBuffer[primIdx];
1253
1254 unsigned partOffset = prim.x ;
1255 unsigned numParts = prim.y ;
1256 unsigned primFlags = prim.w ; // <-- hmm not good to keep flags up here, use flags in partBuffer for simplicity
////
//// primBuffer acts as index to the partBuffer
//// current intersect_boolean hardcoded to
//// handle operations between two basis parts only
////
//// TODO: work out tree generalization approach
//// (only small csg trees are envisaged with a couple of boolean ops)
////
1257
1258 uint4 identity = identityBuffer[instance_index] ;
1259
1260 // for analytic test geometry (PMT too?) the identityBuffer
1261 // is composed of placeholder zeros
1262
1263 if(primFlags & SHAPE_BOOLEAN)
1264 {
1265 quad q1 ;
1266 q1.f = partBuffer[4*(partOffset+0)+1];
1267 identity.z = q1.u.z ; // replace placeholder zero ? with test analytic geometry boundary
1268
1269 intersect_boolean( prim, identity );
1270 //intersect_boolean_only_first( prim, identity );
1271
1272 }
1273 else
1274 {
1275 for(unsigned int p=0 ; p < numParts ; p++)
1276 {
1277 unsigned int partIdx = partOffset + p ;
1278
1279 quad q0, q1, q2, q3 ;
1280
1281 q0.f = partBuffer[4*partIdx+0];
1282 q1.f = partBuffer[4*partIdx+1];
1283 q2.f = partBuffer[4*partIdx+2] ;
1284 q3.f = partBuffer[4*partIdx+3];
Issues
33 static __device__
34 void intersect_boolean( const uint4& prim, const uint4& identity )
35 {
36 // hmm to work with boolean CSG tree primitives this
37 // needs to have the same signature as intersect_part
38 // ie with deferring the reporting to OptiX to the caller
39
40 unsigned primFlags = prim.w ;
41
42
43 // TODO: pass "operation" enum from CPU side, instead of wishy-washy flags
44 enum { INTERSECT, UNION, DIFFERENCE };
45 int bop = primFlags & SHAPE_INTERSECTION ?
46 INTERSECT
47 :
48 ( primFlags & SHAPE_DIFFERENCE ? DIFFERENCE : UNION )
49 ;
50
51 unsigned a_partIdx = prim.x + 1 ;
52 unsigned b_partIdx = prim.x + 2 ;
53
//// hmm the partIdx needs to be able to point at an "operation" node,
//// not just a basis shape node
aiming to allow multiple small csg trees (for diffrent solids) to reside in a single parts buffer with the prim buffer being used to index into the into the relevant indices holding the csg tree
so view the prim buffer just as the high level splitting up index into the part buffer (not as a provider of flags) :
Keeping everything other than the splitting info in the part buffer is needed to allow intersects based on just a partIdx that could be pointing at a basis shape node or an operation node
recursion generaly best avoided in CUDA, so use stack to handle the tree
see oxrap/cu/bintree.py for prototype of CSG binary tree serialization/deserialization using breadth first ordering in order to work with simpler pointerless index navigation
From csg- with tree root at index i=0, with valid indices 0 through numParts − 1, then the i-th element has children at
// i: 0..n-1
// 2i+1,2i+2, floor((i − 1) ∕ 2)
0
1 2
3 4 5 6
7 8 9 10 11 12 13 14
// hmm storing multiple trees in one array requires offsets
// after the 1st