2012-04-19 65 views
19

मैं एक अच्छा रे-ऑक्टेट्री चौराहे एल्गोरिदम की तलाश में हूं, जो मुझे रे को एक पुनरावृत्ति के माध्यम से पारित करता है। मैं इसे सीपीयू पर लागू करने की योजना बना रहा हूं, क्योंकि मैं अभी तक CUDA में डुबकी नहीं लेना चाहता हूं :)रे - ऑक्ट्री चौराहे एल्गोरिदम

फिलहाल, मेरे वोक्सेल रेकास्टर केवल गैर-पदानुक्रम पर 3 डी डीडीए (अमानाटाइड्स/वू संस्करण) करता है XxYxZ voxels की सरणी। आप कल्पना कर सकते हैं कि यह बहुत महंगा है जब वहाँ खाली जगह का एक बहुत है के रूप में निम्न चित्र (चटख लाल रंग = अधिक काम :)) में प्रदर्शन किया:

Workload for dumb 3D DDA - red = more work

मैं पहले से ही समझ गए होंगे देखते हैं कि इस कार्य के लिए दो प्रकार के एल्गोरिदम: नीचे-ऊपर, जो ऊपर के पत्ते से ऊपर काम करता है, और शीर्ष-डाउन, जो मूल रूप से गहराई से पहली खोज है।

मुझे पहले से ही 2000 से रेवेलिस 'एल्गोरिदम मिला है, जिसे An efficient parametric algorithm for octree traversal कहा जाता है, जो दिलचस्प लग रहा है, लेकिन काफी पुराना है। यह एक शीर्ष-डाउन एल्गोरिदम है।

सबसे लोकप्रिय नीचे-अप दृष्टिकोण के। सुंग, रे ट्रेसिंग, यूरोग्राफिक्स 9 1, नॉर्थ हॉलैंड-एल्सेवियर, आईएसबीएन 0444 89096 3, पी के लिए एक डीडीए ऑट्री ट्रैवर्सल एल्गोरिदम लगता है। 73-85। समस्या यह है कि अधिकांश डीडीए ऑक्ट्री ट्रैवर्सल एल्गोरिदम octree की समान गहराई की अपेक्षा करते हैं, जो मैं नहीं चाहता - खाली उपट्री सिर्फ एक शून्य सूचक या कुछ समान होना चाहिए।

विरल Voxel Octrees के बारे में और अधिक हाल के साहित्य में मैं के माध्यम से पढ़ने के लिए, सबसे विशेष रूप Laine's work on SVO's वे सब डीडीए (Amanatides/वू शैली) के GPU से लागू संस्करण के कुछ प्रकार के आधार पर हो रहे हैं प्रबंधित किया है (,।

अब, यहाँ मेरे सवाल है? किसी को भी करता है किसी भी अनुभव एक बुनियादी फ़्रिल रहित रे-octree चौराहे एल्गोरिथ्म को लागू करने के लिए है आप क्या सलाह देंगे

+1

क्या डरावना ओग्रे बनी है? :) – RBarryYoung

+3

यह स्टैनफोर्ड आर्मडिलो है, यहां उपलब्ध है: http://graphics.stanford.edu/data/3Dscanrep/ –

+0

Google इनगो वाल्ड (उनकी वास्तव में शुरुआती सामग्री में अद्भुत मूल बातें हैं)। मैं अभी सही कागज़ खोजने के लिए आलसी हूं। अपनी खोजों और सोच से ऑक्ट्री को भी छोड़ दें - सही शब्द केडी-ट्री है। लिंक संपादित करें: http://web.archive.org/web/20091211153343/http://graphics.cs.uni-sb.de/~wald/Publications/EG2001_IRCRT/InteractiveRenderingWithCoherentRayTracing.pdf – starmole

उत्तर

9

रिकॉर्ड के लिए, इस Revelles कागज मैं समाप्त हो गया की मेरी कार्यान्वयन है उपयोग कर रहे हैं:

#include "octree_traversal.h" 

using namespace std; 

unsigned char a; // because an unsigned char is 8 bits 

int first_node(double tx0, double ty0, double tz0, double txm, double tym, double tzm){ 
unsigned char answer = 0; // initialize to 00000000 
// select the entry plane and set bits 
if(tx0 > ty0){ 
    if(tx0 > tz0){ // PLANE YZ 
     if(tym < tx0) answer|=2; // set bit at position 1 
     if(tzm < tx0) answer|=1; // set bit at position 0 
     return (int) answer; 
    } 
} 
else { 
    if(ty0 > tz0){ // PLANE XZ 
     if(txm < ty0) answer|=4; // set bit at position 2 
     if(tzm < ty0) answer|=1; // set bit at position 0 
     return (int) answer; 
    } 
} 
// PLANE XY 
if(txm < tz0) answer|=4; // set bit at position 2 
if(tym < tz0) answer|=2; // set bit at position 1 
return (int) answer; 
} 

int new_node(double txm, int x, double tym, int y, double tzm, int z){ 
if(txm < tym){ 
    if(txm < tzm){return x;} // YZ plane 
} 
else{ 
    if(tym < tzm){return y;} // XZ plane 
} 
return z; // XY plane; 
} 

void proc_subtree (double tx0, double ty0, double tz0, double tx1, double ty1, double tz1, Node* node){ 
float txm, tym, tzm; 
int currNode; 

if(tx1 < 0 || ty1 < 0 || tz1 < 0) return; 
if(node->terminal){ 
    cout << "Reached leaf node " << node->debug_ID << endl; 
    return; 
} 
else{ cout << "Reached node " << node->debug_ID << endl;} 

txm = 0.5*(tx0 + tx1); 
tym = 0.5*(ty0 + ty1); 
tzm = 0.5*(tz0 + tz1); 

currNode = first_node(tx0,ty0,tz0,txm,tym,tzm); 
do{ 
    switch (currNode) 
    { 
    case 0: { 
     proc_subtree(tx0,ty0,tz0,txm,tym,tzm,node->children[a]); 
     currNode = new_node(txm,4,tym,2,tzm,1); 
     break;} 
    case 1: { 
     proc_subtree(tx0,ty0,tzm,txm,tym,tz1,node->children[1^a]); 
     currNode = new_node(txm,5,tym,3,tz1,8); 
     break;} 
    case 2: { 
     proc_subtree(tx0,tym,tz0,txm,ty1,tzm,node->children[2^a]); 
     currNode = new_node(txm,6,ty1,8,tzm,3); 
     break;} 
    case 3: { 
     proc_subtree(tx0,tym,tzm,txm,ty1,tz1,node->children[3^a]); 
     currNode = new_node(txm,7,ty1,8,tz1,8); 
     break;} 
    case 4: { 
     proc_subtree(txm,ty0,tz0,tx1,tym,tzm,node->children[4^a]); 
     currNode = new_node(tx1,8,tym,6,tzm,5); 
     break;} 
    case 5: { 
     proc_subtree(txm,ty0,tzm,tx1,tym,tz1,node->children[5^a]); 
     currNode = new_node(tx1,8,tym,7,tz1,8); 
     break;} 
    case 6: { 
     proc_subtree(txm,tym,tz0,tx1,ty1,tzm,node->children[6^a]); 
     currNode = new_node(tx1,8,ty1,8,tzm,7); 
     break;} 
    case 7: { 
     proc_subtree(txm,tym,tzm,tx1,ty1,tz1,node->children[7^a]); 
     currNode = 8; 
     break;} 
    } 
} while (currNode<8); 
} 

void ray_octree_traversal(Octree* octree, Ray ray){ 
a = 0; 

// fixes for rays with negative direction 
if(ray.direction[0] < 0){ 
    ray.origin[0] = octree->size[0] - ray.origin[0]; 
    ray.direction[0] = - ray.direction[0]; 
    a |= 4 ; //bitwise OR (latest bits are XYZ) 
} 
if(ray.direction[1] < 0){ 
    ray.origin[1] = octree->size[1] - ray.origin[1]; 
    ray.direction[1] = - ray.direction[1]; 
    a |= 2 ; 
} 
if(ray.direction[2] < 0){ 
    ray.origin[2] = octree->size[2] - ray.origin[2]; 
    ray.direction[2] = - ray.direction[2]; 
    a |= 1 ; 
} 

double divx = 1/ray.direction[0]; // IEEE stability fix 
double divy = 1/ray.direction[1]; 
double divz = 1/ray.direction[2]; 

double tx0 = (octree->min[0] - ray.origin[0]) * divx; 
double tx1 = (octree->max[0] - ray.origin[0]) * divx; 
double ty0 = (octree->min[1] - ray.origin[1]) * divy; 
double ty1 = (octree->max[1] - ray.origin[1]) * divy; 
double tz0 = (octree->min[2] - ray.origin[2]) * divz; 
double tz1 = (octree->max[2] - ray.origin[2]) * divz; 

if(max(max(tx0,ty0),tz0) < min(min(tx1,ty1),tz1)){ 
    proc_subtree(tx0,ty0,tz0,tx1,ty1,tz1,octree->root); 
} 
} 
+1

ऐसा लगता है कि इस समाधान में एक्स/जेड अक्षों को बदल दिया गया है (बिट 0 ज़ेड है, बिट 2 एक्स है)। क्या इसके लिए कोई विशेष कारण है? – paniq

+0

यह थोड़ी देर पहले था, लेकिन मैंने ओपनजीएल संगतता के लिए ऐसा किया होगा। –

+0

ray.origin [0] == आंख स्थिति x है? और ray.direction [0] == एक्स-आंख स्थिति x है? –

1

ऊपर से नीचे मेरे लिए बहुत अच्छी तरह से काम करता है, के ऊपरी भाग octree पॉइंटर आधारित हो सकता है इसलिए बड़ी खाली उप-वॉल्यूम मेमोरी नहीं लेते हैं; निचला हिस्सा पॉइंटर-फ्री को लागू करने के लिए अधिक कुशल है ... दीवार को हिट करने के लिए समय जटिलता लॉग 2 (एन) है (यह स्पष्ट है वाई सबसे अच्छा मामला)। पुनरावर्ती कार्यान्वयन काफी सरल है इसलिए कोड को अनुकूलित करना आसान है। सभी गणित को पूर्णांक एसएसई संचालन के माध्यम से प्रभावी ढंग से कार्यान्वित किया जा सकता है - इसमें प्रत्येक उप-वॉल्यूम कूद के लिए नए XYZ निर्देशांक की गणना करने के लिए लगभग x30 CPU चक्र होते हैं। Btw, octree traversals की सार्वजनिक संस्करण केवल शिक्षा के लिए अच्छे हैं - सही मायने में प्रभावी कार्यान्वयन में महारत हासिल करने को आसानी से कई महीनों लग सकते हैं ...

स्टीफन

+0

मुझे नहीं लगता कि यह ओ क्यों होना चाहिए (लॉग 2 (एन)) (जब तक आप एन की कुछ अजीब परिभाषा का उपयोग नहीं कर रहे हों)। इसके अलावा, आप जो भी सुझाव देते हैं वह वही बात है जो रेवेलिस एट अल। पेपर है जिसे ओपी ने पहले ही उल्लेख किया है। – Mikola

+0

आप किस शीर्ष एल्गोरिदम के बारे में बात कर रहे हैं? पैरामीट्रिक एक? –

संबंधित मुद्दे