To translate or rotate a surface modeled as an CSG tree, apply the inverse transformation to the point for SDFs or the ray for raytracing before doing the SDF distance calc or ray tracing intersection calc.
Nope, I dont think this is possible as with boolean CSG need to apply different transforms to basis shapes underneath a single optix primitive.
Same symptoms as before with interlocked box minus sphere, the translated/rotated and scaled volume shows bits of sphere that should not be there from some angles. The peculiarites go away when rotate by 360.
The fix before was to apply the transform to the normals. but that aint correct, it probably worked by accident due to pre/post multiply and row-major/column-major confusion.
There was some confusion over normalizing ray direction at that juncture also.
Anyhow the correct way to handle normals is to transfrom by the transpose of the inverse.
In order to make that available without getting confused by using inconsistent pre/post multiply and row-major/column-major have passed transforms in triplicate, so the transform of the inverse (Q) is available from tranBuffer.
184 unsigned tIdx = 3*(gtransformIdx-1) ; // transform
...
191 optix::Matrix4x4 T = tranBuffer[tIdx+0] ; // transform
192 optix::Matrix4x4 V = tranBuffer[tIdx+1] ; // inverse transform
193 optix::Matrix4x4 Q = tranBuffer[tIdx+2] ; // inverse transform transposed
194
195 float4 origin = make_float4( ray.origin.x, ray.origin.y, ray.origin.z, 1.f ); // w=1 for position
196 float4 direction = make_float4( ray.direction.x, ray.direction.y, ray.direction.z, 0.f ); // w=0 for vector
197
198 origin = origin * V ; // world frame into primitive frame with inverse transform
199 direction = direction * V ; // <-- will loose normalization with scaling, intersects MUST NOT assume normalized ray direction
200
201 float3 ray_origin = make_float3( origin.x, origin.y, origin.z );
202 float3 ray_direction = make_float3( direction.x, direction.y, direction.z ); // with scaling normalization will be off ?
203
204 bool valid_intersect = false ;
205
206 switch(partType)
207 {
208 case CSG_SPHERE: valid_intersect = csg_intersect_sphere(pt.q0,tt_min, tt, ray_origin, ray_direction ) ; break ;
209 case CSG_BOX: valid_intersect = csg_intersect_box( pt.q0,tt_min, tt, ray_origin, ray_direction ) ; break ;
210 }
211
212 if(valid_intersect)
213 {
214 float4 ttn = make_float4( tt.x, tt.y, tt.z , 0.f );
215
216 ttn = ttn * Q ; // primitive frame normal into world frame, using inverse transform transposed
217
218 tt.x = ttn.x ;
219 tt.y = ttn.y ;
220 tt.z = ttn.z ;
221 }
tboolean-sphere-py-(){ cat << EOP
from opticks.dev.csg.csg import CSG
container = CSG("box", param=[0,0,0,1000], boundary="$(tboolean-container)", poly="MC", nx="20" )
im = dict(poly="IM", resolution="50", verbosity="1", ctrl="0" )
tr = dict(scale="1,1,1")
kwa = {}
kwa.update(im)
kwa.update(tr)
sphere = CSG("sphere", param=[0,0,0,100], boundary="$(tboolean-object)", **kwa )
CSG.Serialize([container, sphere], "$TMP/$FUNCNAME" )
EOP
}
At boolean level the isect normal coming from csg_intersect_part is compared with ray.direction to classify the intersect:
158 static __device__
159 void csg_intersect_part(unsigned partIdx, const float& tt_min, float4& tt )
160 {
481 void evaluative_csg( const uint4& prim, const uint4& identity )
...
623 IntersectionState_t l_state = CSG_CLASSIFY( csg.data[left], ray.direction, tmin );
624 IntersectionState_t r_state = CSG_CLASSIFY( csg.data[right], ray.direction, tmin );
625
626 float t_left = fabsf( csg.data[left].w );
627 float t_right = fabsf( csg.data[right].w );
628
629 int ctrl = boolean_ctrl_packed_lookup( typecode , l_state, r_state, t_left <= t_right ) ;
630 history_append( hist, nodeIdx, ctrl );
248 tboolean-sphere-py-(){ cat << EOP
249 from opticks.dev.csg.csg import CSG
250
251 container = CSG("box", param=[0,0,0,1000], boundary="$(tboolean-container)", poly="MC", nx="20" )
252
253
254 kwa = {}
255 im = dict(poly="IM", resolution="50", verbosity="1", ctrl="0" )
256 tr = dict(translate="0,0,0", scale="1,1,2")
257 kwa.update(im)
258 kwa.update(tr)
259
260 sphere = CSG("sphere", param=[0,0,0,100], boundary="$(tboolean-object)", **kwa )
261
262 CSG.Serialize([container, sphere], "$TMP/$FUNCNAME" )
263 EOP
264 }
GPU side
##test_tranBuffer tr
1.000 0.000 0.000 0.000
0.000 1.000 0.000 0.000
0.000 0.000 2.000 0.000
0.000 0.000 200.000 1.000
##test_tranBuffer irit
1.000 0.000 0.000 0.000
0.000 1.000 0.000 0.000
0.000 0.000 0.500 0.000
0.000 0.000 -100.000 1.000
##bounds primIdx 0 partOffset 0 numParts 1 height 0 numNodes 1 tranBuffer_size 2
##bounds primIdx 1 partOffset 1 numParts 1 height 0 numNodes 1 tranBuffer_size 2
## bounds nodeIdx 1 depth 0 elev 0 partType 6 gtransformIdx 0
## bounds nodeIdx 1 depth 0 elev 0 partType 5 gtransformIdx 1
##intersect_analytic.cu:bounds primIdx 0 primFlag 101 min -1000.0000 -1000.0000 -1000.0000 max 1000.0000 1000.0000 1000.0000
##intersect_analytic.cu:bounds primIdx 1 primFlag 101 min -100.0000 -100.0000 0.0000 max 100.0000 100.0000 400.0000
Simplify, even with an non-one uniform scaling, the sphere is disappearing:
##test_tranBuffer tr
1.100 0.000 0.000 0.000
0.000 1.100 0.000 0.000
0.000 0.000 1.100 0.000
0.000 0.000 0.000 1.000
##test_tranBuffer irit
0.909 0.000 0.000 0.000
0.000 0.909 0.000 0.000
0.000 0.000 0.909 0.000
0.000 0.000 0.000 1.000
##bounds primIdx 0 partOffset 0 numParts 1 height 0 numNodes 1 tranBuffer_size 2
##bounds primIdx 1 partOffset 1 numParts 1 height 0 numNodes 1 tranBuffer_size 2
## bounds nodeIdx 1 depth 0 elev 0 partType 6 gtransformIdx 0
## bounds nodeIdx 1 depth 0 elev 0 partType 5 gtransformIdx 1
##intersect_analytic.cu:bounds primIdx 0 primFlag 101 min -1000.0000 -1000.0000 -1000.0000 max 1000.0000 1000.0000 1000.0000
##intersect_analytic.cu:bounds primIdx 1 primFlag 101 min -110.0000 -110.0000 -110.0000 max 110.0000 110.0000 110.0000
tboolean-sphere-py-(){ cat << EOP
from opticks.dev.csg.csg import CSG
container = CSG("box", param=[0,0,0,1000], boundary="$(tboolean-container)", poly="MC", nx="20" )
kwa = {}
im = dict(poly="IM", resolution="50", verbosity="1", ctrl="0" )
tr = dict(translate="0,0,100", rotate="1,1,1,45", scale="1,1,2")
kwa.update(im)
kwa.update(tr)
sphere = CSG("sphere", param=[0,0,0,100], boundary="$(tboolean-object)", **kwa )
CSG.Serialize([container, sphere], "$TMP/$FUNCNAME" )
EOP
}
Note that
X*V = Q*X
Y*V = Q*Y
Z*V = Q*Z
##test_tranBuffer T(transform) primitive frame -> world frame
0.805 0.506 -0.311 0.000
-0.311 0.805 0.506 0.000
1.012 -0.621 1.609 0.000
0.000 0.000 100.000 1.000
##test_tranBuffer V(inverse) world frame -> primitive frame
0.805 -0.311 0.253 0.000
0.506 0.805 -0.155 0.000
-0.311 0.506 0.402 0.000
31.062 -50.588 -40.237 1.000
##test_tranBuffer Q(inverse.T)
0.805 0.506 -0.311 31.062
-0.311 0.805 0.506 -50.588
0.253 -0.155 0.402 -40.237
0.000 0.000 0.000 1.000
##test_tranBuffer TV(~identity)
1.000 0.000 -0.000 0.000
0.000 1.000 0.000 0.000
-0.000 0.000 1.000 0.000
0.000 0.000 0.000 1.000
##test_tranBuffer VT(~identity)
1.000 0.000 0.000 0.000
0.000 1.000 -0.000 0.000
0.000 -0.000 1.000 0.000
0.000 0.000 0.000 1.000
# transform primitive frame points and vectors into world frame
# _________________________________________
O 0.000 0.000 0.000 1.000 O*T 0.000 0.000 100.000 1.000 T*O 0.000 0.000 0.000 1.000
P 1.000 1.000 1.000 1.000 P*T 1.506 0.689 101.805 1.000 T*P 1.000 1.000 2.000 101.000
N -1.000 -1.000 -1.000 1.000 N*T -1.506 -0.689 98.195 1.000 T*N -1.000 -1.000 -2.000 -99.000
X 1.000 0.000 0.000 0.000 X*T 0.805 0.506 -0.311 0.000 T*X 0.805 -0.311 1.012 0.000
Y 0.000 1.000 0.000 0.000 Y*T -0.311 0.805 0.506 0.000 T*Y 0.506 0.805 -0.621 0.000
Z 0.000 0.000 1.000 0.000 Z*T 1.012 -0.621 1.609 0.000 T*Z -0.311 0.506 1.609 100.000
# transform world frame points and vectors into primitive frame
# ________________________________________
O 0.000 0.000 0.000 1.000 O*V 31.062 -50.588 -40.237 1.000 V*O 0.000 0.000 0.000 1.000
P 1.000 1.000 1.000 1.000 P*V 32.062 -49.588 -39.737 1.000 V*P 0.747 1.155 0.598 -58.763
N -1.000 -1.000 -1.000 1.000 N*V 30.062 -51.588 -40.737 1.000 V*N -0.747 -1.155 -0.598 60.763
X 1.000 0.000 0.000 0.000 X*V 0.805 -0.311 0.253 0.000 V*X 0.805 0.506 -0.311 31.062
Y 0.000 1.000 0.000 0.000 Y*V 0.506 0.805 -0.155 0.000 V*Y -0.311 0.805 0.506 -50.588
Z 0.000 0.000 1.000 0.000 Z*V -0.311 0.506 0.402 0.000 V*Z 0.253 -0.155 0.402 -40.237
# bring primitive frame normal vectors out to world frame, but by inspection Q * [X/Y/Z] = [X/Y/Z] * V
# which is handy as I dont have Q available on GPU
#
O 0.000 0.000 0.000 1.000 O*Q 0.000 0.000 0.000 1.000 Q*O 31.062 -50.588 -40.237 1.000
P 1.000 1.000 1.000 1.000 P*Q 0.747 1.155 0.598 -58.763 Q*P 32.062 -49.588 -39.737 1.000
N -1.000 -1.000 -1.000 1.000 N*Q -0.747 -1.155 -0.598 60.763 Q*N 30.062 -51.588 -40.737 1.000
# ________________________________________
X 1.000 0.000 0.000 0.000 X*Q 0.805 0.506 -0.311 31.062 Q*X 0.805 -0.311 0.253 0.000
Y 0.000 1.000 0.000 0.000 Y*Q -0.311 0.805 0.506 -50.588 Q*Y 0.506 0.805 -0.155 0.000
Z 0.000 0.000 1.000 0.000 Z*Q 0.253 -0.155 0.402 -40.237 Q*Z -0.311 0.506 0.402 0.000
# W-leakage suggestive of unintended transformations ?
##bounds primIdx 0 partOffset 0 numParts 1 height 0 numNodes 1 tranBuffer_size 2
##bounds primIdx 1 partOffset 1 numParts 1 height 0 numNodes 1 tranBuffer_size 2
## bounds nodeIdx 1 depth 0 elev 0 partType 6 gtransformIdx 0
## bounds nodeIdx 1 depth 0 elev 0 partType 6 gtransformIdx 1
##intersect_analytic.cu:bounds primIdx 0 primFlag 101 min -1000.0000 -1000.0000 -1000.0000 max 1000.0000 1000.0000 1000.0000
##intersect_analytic.cu:bounds primIdx 1 primFlag 101 min -425.4227 -386.3703 -385.1945 max 425.4227 386.3703 585.1945
MAYBE:
FIX
##bounds primIdx 0 partOffset 0 numParts 1 height 0 numNodes 1 tranBuffer_size 2
##bounds primIdx 1 partOffset 1 numParts 7 height 2 numNodes 7 tranBuffer_size 2
##hemi-pmt.cu:bounds primIdx 0 is_csg:0 min -1000.0000 -1000.0000 -1000.0000 max 1000.0000 1000.0000 1000.0000
## bounds nodeIdx 4 depth 2 elev 0 partType 6 gtransformIdx 1
## bounds nodeIdx 5 depth 2 elev 0 partType 5 gtransformIdx 1
## bounds nodeIdx 2 depth 1 elev 1 partType 3 gtransformIdx 1
## bounds nodeIdx 6 depth 2 elev 0 partType 6 gtransformIdx 1
## bounds nodeIdx 7 depth 2 elev 0 partType 5 gtransformIdx 1
## bounds nodeIdx 3 depth 1 elev 1 partType 3 gtransformIdx 1
## bounds nodeIdx 1 depth 0 elev 2 partType 1 gtransformIdx 1
##hemi-pmt.cu:bounds primIdx 1 is_csg:1 min -325.4228 -355.3086 -185.1945 max 374.8348 486.3704 604.7207
Fixed by not writing the bbox and getting nsphere::part to use nnode::part and then specialize, but now get bad bbox for container which has disappeared in raytrace:
##bounds primIdx 0 partOffset 0 numParts 1 height 0 numNodes 1 tranBuffer_size 2
##bounds primIdx 1 partOffset 1 numParts 7 height 2 numNodes 7 tranBuffer_size 2
##hemi-pmt.cu:bounds primIdx 0 is_csg:0 min 0.0000 0.0000 0.0000 max 0.0000 0.0000 0.0000
## bounds nodeIdx 4 depth 2 elev 0 partType 6 gtransformIdx 0
## bounds nodeIdx 5 depth 2 elev 0 partType 5 gtransformIdx 0
## bounds nodeIdx 2 depth 1 elev 1 partType 3 gtransformIdx 0
## bounds nodeIdx 6 depth 2 elev 0 partType 6 gtransformIdx 1
## bounds nodeIdx 7 depth 2 elev 0 partType 5 gtransformIdx 1
## bounds nodeIdx 3 depth 1 elev 1 partType 3 gtransformIdx 0
## bounds nodeIdx 1 depth 0 elev 2 partType 1 gtransformIdx 0
##hemi-pmt.cu:bounds primIdx 1 is_csg:1 min -273.6589 -355.3086 -300.0000 max 374.8348 300.0000 604.7207
Dumping the GParts from OGeo shows that still have the bboxen and my gtransformIdx is being overwritten with a nodeIdx.
In [11]: pt = np.load("/tmp/blyth/opticks/OGeo_makeAnalyticGeometry/analytic/partBuffer.npy")
In [12]: pt
Out[12]:
array([[[ 0. , 0. , 0. , 1000. ],
[ 0. , 0. , 0. , 0. ],
[-1000. , -1000. , -1000. , 0. ],
[ 1000. , 1000. , 1000. , 0. ]],
[[ 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. ],
[ -273.6589, -355.3086, -300. , 0. ],
[ 374.8348, 300. , 604.7207, 0. ]],
[[ 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. ],
[ -100. , -100. , -300. , 0. ],
[ 300. , 300. , 100. , 0. ]],
[[ 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. ],
[ -273.6589, -355.3086, -43.7731, 0. ],
[ 374.8348, 293.1852, 604.7207, 0. ]],
[[ 100. , 100. , -100. , 150.1111],
[ 0. , 0. , 0. , 0. ],
[ -50.1111, -50.1111, -250.1111, 0. ],
[ 250.1111, 250.1111, 50.1111, 0. ]],
[[ 100. , 100. , -100. , 200. ],
[ 0. , 0. , 0. , 0. ],
[ -200. , -200. , -300. , 0. ],
[ 200. , 200. , 100. , 0. ]],
[[ 0. , 0. , 100. , 150.1111],
[ 0. , 0. , 0. , 0. ],
[ -192.7773, -274.427 , 37.1086, 0. ],
[ 293.9532, 212.3035, 523.839 , 0. ]],
[[ 0. , 0. , 100. , 200. ],
[ 0. , 0. , 0. , 0. ],
[ -200. , -200. , -100. , 0. ],
[ 200. , 200. , 300. , 0. ]]], dtype=float32)
In [14]: pt = np.load("/tmp/blyth/opticks/OGeo_makeAnalyticGeometry/analytic/partBuffer.npy")
In [15]: pt
Out[15]:
array([[[ 0. , 0. , 0. , 1000. ],
[ 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. ]],
[[ 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. ]],
[[ 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. ]],
[[ 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. ]],
[[ 100. , 100. , -100. , 150.1111],
[ 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. ]],
[[ 100. , 100. , -100. , 200. ],
[ 0. , 0. , 0. , 0. ],
[ -200. , -200. , -300. , 0. ],
[ 200. , 200. , 100. , 0. ]],
[[ 0. , 0. , 100. , 150.1111],
[ 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. ]],
[[ 0. , 0. , 100. , 200. ],
[ 0. , 0. , 0. , 0. ],
[ -200. , -200. , -100. , 0. ],
[ 200. , 200. , 300. , 0. ]]], dtype=float32)
In [13]: pt.view(np.uint32)
Out[13]:
array([[[ 0, 0, 0, 1148846080],
[ 0, 0, 123, 0],
[3296329728, 3296329728, 3296329728, 6],
[1148846080, 1148846080, 1148846080, 0]],
[[ 0, 0, 0, 0],
[ 0, 1, 124, 0],
[3280524376, 3283199872, 3281387520, 1],
[1136356060, 1133903872, 1142369824, 1]],
[[ 0, 0, 0, 0],
[ 0, 2, 124, 0],
[3267887104, 3267887104, 3281387520, 3],
[1133903872, 1133903872, 1120403456, 1]],
[[ 0, 0, 0, 0],
[ 0, 3, 124, 0],
[3280524376, 3283199872, 3257866152, 3],
[1136356060, 1133680564, 1142369824, 1]],
[[1120403456, 1120403456, 3267887104, 1125522543],
[ 0, 4, 124, 0],
[3259527612, 3259527612, 3279559791, 6],
[1132076143, 1132076143, 1112043964, 1]],
[[1120403456, 1120403456, 3267887104, 1128792064],
[ 0, 5, 124, 0],
[3276275712, 3276275712, 3281387520, 5],
[1128792064, 1128792064, 1120403456, 1]],
[[ 0, 0, 1120403456, 1125522543],
[ 0, 6, 124, 0],
[3275802366, 3280549543, 1108635432, 6],
[1133705730, 1129598387, 1141044658, 1]],
[[ 0, 0, 1120403456, 1128792064],
[ 0, 7, 124, 0],
[3276275712, 3276275712, 3267887104, 5],
[1128792064, 1128792064, 1133903872, 1]]], dtype=uint32)
In [4]: n = np.load("/tmp/blyth/opticks/tboolean-csg-two-box-minus-sphere-interlocked-py-/1/nodes.npy")
In [5]: n
Out[5]:
array([[[ 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. ]],
[[ 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. ]],
[[ 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. ]],
[[ 100. , 100. , -100. , 150.1111],
[ 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. ]],
[[ 100. , 100. , -100. , 200. ],
[ 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. ]],
[[ 0. , 0. , 100. , 150.1111],
[ 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. ]],
[[ 0. , 0. , 100. , 200. ],
[ 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. ]]], dtype=float32)
In [6]: n.view(np.int32)
Out[6]:
array([[[ 0, 0, 0, 0],
[ 0, 0, 0, 0],
[ 0, 0, 0, 1], CSG_UNION
[ 0, 0, 0, 1]], <----- whats this 1 ? IT IS THE RTRANSFORM REFERENCE
[[ 0, 0, 0, 0],
[ 0, 0, 0, 0],
[ 0, 0, 0, 3], CSG_DIFFERENCE
[ 0, 0, 0, 0]],
[[ 0, 0, 0, 0],
[ 0, 0, 0, 0],
[ 0, 0, 0, 3], CSG_DIFFERENCE
[ 0, 0, 0, 0]],
[[ 1120403456, 1120403456, -1027080192, 1125522543],
[ 0, 0, 0, 0],
[ 0, 0, 0, 6], CSG_BOX
[ 0, 0, 0, 0]],
[[ 1120403456, 1120403456, -1027080192, 1128792064],
[ 0, 0, 0, 0],
[ 0, 0, 0, 5], CSG_SPHERE
[ 0, 0, 0, 0]],
[[ 0, 0, 1120403456, 1125522543],
[ 0, 0, 0, 0],
[ 0, 0, 0, 6], CSG_BOX
[ 0, 0, 0, 0]],
[[ 0, 0, 1120403456, 1128792064],
[ 0, 0, 0, 0],
[ 0, 0, 0, 5], CSG_SPHERE
[ 0, 0, 0, 0]]], dtype=int32)
simon:opticks blyth$ sysrap-csg
typedef enum {
CSG_ZERO=0,
CSG_UNION=1,
CSG_INTERSECTION=2,
CSG_DIFFERENCE=3,
CSG_PARTLIST=4,
CSG_SPHERE=5,
CSG_BOX=6,
CSG_ZSPHERE=7,
CSG_ZLENS=8,
CSG_PMT=9,
CSG_PRISM=10,
CSG_TUBS=11,
CSG_UNDEFINED=12
} OpticksCSG_t ;
In [1]: p = np.load("/usr/local/opticks/opticksdata/export/DayaBay/GPmt/1/GPmt.npy")
In [2]: p
Out[2]:
array([[[ 0. , 0. , 69. , 102. ],
[ 0. , 0. , 0. , 0. ],
[-101.1682, -101.1682, -23.8382, 0. ],
[ 101.1682, 101.1682, 56. , 0. ]],
[[ 0. , 0. , 43. , 102. ],
[ 0. , 0. , 0. , 0. ],
[-101.1682, -101.1682, 56. , 0. ],
[ 101.1682, 101.1682, 100.0698, 0. ]],
[[ 0. , 0. , 0. , 131. ],
[ 0. , 0. , 0. , 0. ],
[ -84.5402, -84.5402, 100.0698, 0. ],
[ 84.5402, 84.5402, 131. , 0. ]],
[[ 0. , 0. , -84.5 , 42.25 ],
[ 169. , 0. , 0. , 0. ],
[ -42.25 , -42.25 , -169. , 0. ],
[ 42.25 , 42.25 , -23.8382, 0. ]],
[[ 0. , 0. , 69. , 99. ],
[ 0. , 0. , 0. , 0. ],
[ -98.1428, -98.1428, -21.8869, 0. ],
[ 98.1428, 98.1428, 56. , 0. ]],
[[ 0. , 0. , 43. , 99. ],
[ 0. , 0. , 0. , 0. ],
[ -98.1428, -98.1428, 56. , 0. ],
[ 98.1428, 98.1428, 98.0465, 0. ]],
[[ 0. , 0. , 0. , 128. ],
[ 0. , 0. , 0. , 0. ],
[ -82.2854, -82.2854, 98.0465, 0. ],
[ 82.2854, 82.2854, 128. , 0. ]],
[[ 0. , 0. , -81.5 , 39.25 ],
[ 166. , 0. , 0. , 0. ],
[ -39.25 , -39.25 , -164.5 , 0. ],
[ 39.25 , 39.25 , -21.8869, 0. ]],
[[ 0. , 0. , 0. , 127.95 ],
[ 0. , 0. , 0. , 0. ],
[ -82.2478, -82.2478, 98.0128, 0. ],
[ 82.2478, 82.2478, 127.95 , 0. ]],
[[ 0. , 0. , 43. , 98.95 ],
[ 0. , 0. , 0. , 0. ],
[ -98.0932, -98.0932, 55.9934, 0. ],
[ 98.0932, 98.0932, 98.0128, 0. ]],
[[ 0. , 0. , 69. , 98. ],
[ 0. , 0. , 0. , 0. ],
[ -97.1514, -97.1514, -29. , 0. ],
[ 97.1514, 97.1514, 56.1313, 0. ]],
[[ 0. , 0. , -81.5 , 27.5 ],
[ 166. , 0. , 0. , 0. ],
[ -27.5 , -27.5 , -164.5 , 0. ],
[ 27.5 , 27.5 , 1.5 , 0. ]]], dtype=float32)
In [3]: p.view(np.int32)
Out[3]:
array([[[ 0, 0, 1116340224, 1120665600],
[ 0, 1, 0, 0],
[-1026927077, -1026927077, -1044466509, 5],
[ 1120556571, 1120556571, 1113587712, 0]],
[[ 0, 0, 1110179840, 1120665600],
[ 0, 2, 0, 0],
[-1026927077, -1026927077, 1113587712, 5],
[ 1120556571, 1120556571, 1120412601, 0]],
[[ 0, 0, 0, 1124270080],
[ 0, 3, 0, 0],
[-1029106542, -1029106542, 1120412601, 5],
[ 1118377106, 1118377106, 1124270080, 0]],
[[ 0, 0, -1029111808, 1109983232],
[ 1126760448, 4, 0, 1],
[-1037500416, -1037500416, -1020723200, 11],
[ 1109983232, 1109983232, -1044466509, 0]],
[[ 0, 0, 1116340224, 1120272384],
[ 0, 5, 0, 0],
[-1027323625, -1027323625, -1045489543, 5],
[ 1120160023, 1120160023, 1113587712, 1]],
[[ 0, 0, 1110179840, 1120272384],
[ 0, 6, 0, 0],
[-1027323625, -1027323625, 1113587712, 5],
[ 1120160023, 1120160023, 1120147408, 1]],
[[ 0, 0, 0, 1124073472],
[ 0, 7, 0, 0],
[-1029402084, -1029402084, 1120147408, 5],
[ 1118081564, 1118081564, 1124073472, 1]],
[[ 0, 0, -1029505024, 1109196800],
[ 1126563840, 8, 0, 1],
[-1038286848, -1038286848, -1021018112, 11],
[ 1109196800, 1109196800, -1045489543, 1]],
[[ 0, 0, 0, 1124066918],
[ 0, 9, 0, 0],
[-1029407013, -1029407013, 1120142989, 5],
[ 1118076635, 1118076635, 1124066918, 2]],
[[ 0, 0, 1110179840, 1120265830],
[ 0, 10, 0, 0],
[-1027330122, -1027330122, 1113585991, 5],
[ 1120153526, 1120153526, 1120142989, 2]],
[[ 0, 0, 1116340224, 1120141312],
[ 0, 11, 0, 0],
[-1027453562, -1027453562, -1041760256, 5],
[ 1120030086, 1120030086, 1113622135, 3]],
[[ 0, 0, -1029505024, 1104936960],
[ 1126563840, 12, 0, 0],
[-1042546688, -1042546688, -1021018112, 11],
[ 1104936960, 1104936960, 1069547520, 4]]], dtype=int32)
In [4]:
##test_tranBuffer tr
0.805 0.506 -0.311 0.000
-0.311 0.805 0.506 0.000
0.506 -0.311 0.805 0.000
0.000 0.000 200.000 1.000
tr0
0.805 0.506 -0.311 0.000
tr1
-0.311 0.805 0.506 0.000
tr2
0.506 -0.311 0.805 0.000
tr3
0.000 0.000 200.000 1.000
##test_tranBuffer irit
0.805 -0.311 0.506 0.000
0.506 0.805 -0.311 0.000
-0.311 0.506 0.805 0.000
62.123 -101.176 -160.948 1.000
##test_transform_bbox tr
0.805 0.506 -0.311 0.000
-0.311 0.805 0.506 0.000
0.506 -0.311 0.805 0.000
0.000 0.000 200.000 1.000
##test_transform_bbox min -162.123 -162.123 37.877 max 162.123 162.123 362.123
elta:optixu blyth$ NBBoxTest
( 0) 0.805 0.506 -0.311 0.000
( 0) -0.311 0.805 0.506 0.000
( 0) 0.506 -0.311 0.805 0.000
( 0) 0.000 0.000 200.000 1.000
tr 0.805 0.506 -0.311 0.000
-0.311 0.805 0.506 0.000
0.506 -0.311 0.805 0.000
0.000 0.000 200.000 1.000
tr[0] 0.805 0.506 -0.311 0.000
tr[1] -0.311 0.805 0.506 0.000
tr[2] 0.506 -0.311 0.805 0.000
tr[3] 0.000 0.000 200.000 1.000
bb mi (-100.00 -100.00 -100.00) mx ( 100.00 100.00 100.00)
tbb mi (-162.12 -162.12 37.88) mx ( 162.12 162.12 362.12)
- G4 allows the RHS of a boolean combination to be transformed using a transform that lives with the combination
111 double nunion::operator()(double px, double py, double pz)
112 {
/// just transform px,py,pz here only ?
113 assert( left && right );
114 double l = (*left)(px, py, pz) ;
115 double r = (*right)(px, py, pz) ;
116 return fmin(l, r);
117 }
Perhaps can just locally apply the transform ? to the coordinates passed down the tree ? Relying on subsequent transforms transforming again the transformed coordinates... this would be simplest.
The alternative would be to traverse up the tree thru parent links collecting and multiplying transforms and store that as a global transfrom within each node to apply to global coordinates.
Actually its not clear how to use global transforms as the evaluation is done treewise ... with each node not knowing where it is in the tree ?
BUT: for internal nodes the coordinates are not actually used, they are just being passed down the tree until reach the leaves/primitives ... so this means can collect ancestor transforms into the primitives : this is what will need to do on GPU, so actually its better to take same approach on CPU
09 // only used for CSG operator nodes
10 enum {
11 RTRANSFORM_J = 3,
12 RTRANSFORM_K = 3
13 }; // q3.u.w
14
58 enum {
59 NODEINDEX_J = 3,
60 NODEINDEX_K = 3
61 }; // q3.u.w
The below needs to pass a reference to the ray to the intersects and the transform can happen here.
float3: ray.direction, ray.origin
128 static __device__
129 void intersect_part(unsigned partIdx, const float& tt_min, float4& tt )
130 {
131 quad q0, q2 ;
132 q0.f = partBuffer[4*partIdx+0];
133 q2.f = partBuffer[4*partIdx+2];
134
135 OpticksCSG_t csgFlag = (OpticksCSG_t)q2.u.w ;
136
137 //if(partIdx > 1)
138 //rtPrintf("[%5d] intersect_part partIdx %u csgFlag %u \n", launch_index.x, partIdx, csgFlag );
139
140 switch(csgFlag)
141 {
142 case CSG_SPHERE: intersect_sphere(q0,tt_min, tt ) ; break ;
143 case CSG_BOX: intersect_box( q0,tt_min, tt ) ; break ;
144 }
145 }
9.005 Are OpenGL matrices column-major or row-major?
For programming purposes, OpenGL matrices are 16-value arrays with base vectors
laid out contiguously in memory. The translation components occupy the 13th,
14th, and 15th elements of the 16-element matrix, where indices are numbered
from 1 to 16 as described in section 2.11.2 of the OpenGL 2.1 Specification.
Column-major versus row-major is purely a notational convention. Note that
post-multiplying with column-major matrices produces the same result as
pre-multiplying with row-major matrices. The OpenGL Specification and the
OpenGL Reference Manual both use column-major notation. You can use any
notation, as long as it's clearly stated.
/Developer/OptiX/include/optixu/optixu_matrix_namespace.h
100 template <unsigned int M, unsigned int N>
101 class Matrix
102 {
103 public:
...
169 private:
170 /** The data array is stored in row-major order */
171 float m_data[M*N];
172 };
173
421 // Multiply matrix4x4 by float4
422 OPTIXU_INLINE RT_HOSTDEVICE float4 operator*(const Matrix<4,4>& m, const float4& vec )
423 {
424 float4 temp;
425 temp.x = m[ 0] * vec.x +
426 m[ 1] * vec.y +
427 m[ 2] * vec.z +
428 m[ 3] * vec.w;
429 temp.y = m[ 4] * vec.x +
430 m[ 5] * vec.y +
431 m[ 6] * vec.z +
432 m[ 7] * vec.w;
433 temp.z = m[ 8] * vec.x +
434 m[ 9] * vec.y +
435 m[10] * vec.z +
436 m[11] * vec.w;
437 temp.w = m[12] * vec.x +
438 m[13] * vec.y +
439 m[14] * vec.z +
440 m[15] * vec.w;
441
442 return temp;
443 }
709 typedef Matrix<2, 2> Matrix2x2;
710 typedef Matrix<2, 3> Matrix2x3;
711 typedef Matrix<2, 4> Matrix2x4;
712 typedef Matrix<3, 2> Matrix3x2;
713 typedef Matrix<3, 3> Matrix3x3;
714 typedef Matrix<3, 4> Matrix3x4;
715 typedef Matrix<4, 2> Matrix4x2;
716 typedef Matrix<4, 3> Matrix4x3;
717 typedef Matrix<4, 4> Matrix4x4;
718