2012-03-07 35 views
6

में सिलेंडर impostor मैं अणुओं के 3 डी विज़ुअलाइजेशन के लिए एक छोटा सा उपकरण विकसित कर रहा हूँ। मेरी प्रोजेक्ट के लिए मैं अपने ऐप्पल सॉफ़्टवेयर "अणुओं" के साथ श्री "ब्रैड लार्सन" के तरीके में एक चीज़ बनाने का विकल्प चुनता हूं। एक लिंक जहां तकनीक का एक छोटा सा प्रस्तुति पा सकते हैं: Brad Larsson software presentationजीएलएसएल

मेरा काम कर रही है के लिए मैं गणना करना चाहिए क्षेत्र कपटी और सिलेंडर कपटी

पल मैं एक ट्यूटोरियल Lies and Impostors

की मदद से "क्षेत्र पाखण्डी" ऐसा करने के लिए क्षेत्र कपटी की कंप्यूटिंग संक्षेप में प्रस्तुत करने के लिए सफल होने के लिए है के लिए: पहले हम एक "क्षेत्र की स्थिति" और "क्षेत्र त्रिज्या भेज "वर्टेक्स शेडर" के लिए जो कैमरे-स्पेस में एक स्क्वायर जो हमेशा कैमरे का सामना करेगा, उसके बाद हम अपने वर्ग को टुकड़े टुकड़े में भेज देंगे जहां हम एक साधारण रे ट्रेसिंग का उपयोग करते हैं ताकि यह पता चल सके कि वर्ग का कौन सा टुकड़ा शामिल है क्षेत्र, और अंत में हम प्रकाश की गणना करने के लिए सामान्य और खंड की स्थिति की गणना करते हैं। (एक और बात हम अपने impostor क्षेत्र में अच्छी गहराई देने के लिए gl_fragdepth भी लिखते हैं!)

लेकिन अब मैं सिलेंडर impostor की कंप्यूटिंग में अवरुद्ध हूँ, मैं क्षेत्र impostor और सिलेंडर impostor के बीच समानांतर करने की कोशिश लेकिन मुझे कुछ भी नहीं मिला, मेरी समस्या यह है कि क्षेत्र के लिए यह कुछ आसान था क्योंकि क्षेत्र हमेशा समान होता है चाहे हम इसे कैसे देखते हैं, हम हमेशा एक ही चीज़ देखेंगे: "एक सर्कल" और दूसरी बात यह है कि क्षेत्र को गणित द्वारा पूरी तरह से परिभाषित किया गया था, फिर हम प्रकाश की गणना करने और हमारे अपवित्र बनाने के लिए आसानी से स्थिति और सामान्य पा सकते हैं।

सिलेंडर यह एक ही बात नहीं है के लिए, और मैं, एक रूप है जिसमें "के रूप में सिलेंडर कपटी" इस्तेमाल किया जा सकता मॉडलिंग क्योंकि सिलेंडर कई अलग अलग कोण हम इसे देख के आधार पर रूपों से पता चलता करने के लिए एक संकेत खोजने में असफल रहा!

इसलिए मेरा अनुरोध आपको "सिलेंडर impostor" की मेरी समस्या के लिए एक समाधान या संकेत के बारे में पूछना है।

+3

क्यों तुम करोगी इसके लिए एक impostor का उपयोग करें? क्यों न केवल सिलेंडर खींचें? साथ ही, जब मैंने ट्यूटोरियल लिखा था, तो मैं गोलाकारों का चयन करने के लिए एक कारण नहीं था और सिलेंडरों नहीं। गोलाकार सममित हैं; वे एक स्थिति और त्रिज्या द्वारा परिभाषित किया जाता है। रेट्रैसिंग गणित सरल है। सिलेंडर * दूर * अधिक जटिल हैं। ट्यूटोरियल से बाहर निकलने वाले सिलेंडर मॉडल को खींचने और इसे प्रस्तुत करना आपके लिए बहुत आसान होगा। –

+0

जैसा कि मैंने कहा था कि मैं एक स्कूल प्रोजेक्ट के लिए 3 डी अणुओं के विज़ुअलाइज़ेशन के लिए एक छोटा सा टूल विकसित करता हूं, इसलिए मैं पहली बार इस तकनीक के अनुसार 3 डी क्षेत्र इंपोस्टर और सिलेंडर इंपॉस्टर करने का निर्णय लेता हूं कि ब्रैड लार्सन अपने आवेदन ब्रैड लार्सन एप्लिकेशन में उपयोग करते हैं और एक अन्य कारण के रूप में यह है कि impostors सौ पॉलीगॉन लिखने के असली सिलेंडर ड्राइंग से अधिक हल्के होते हैं, और यह अणुओं के 3 डी विज़ुअलाइज़ेशन के लिए वास्तव में महत्वपूर्ण है क्योंकि बड़ी संख्या में अणुओं की गणना की जाएगी! लेकिन अगर आपने मुझे कहा कि यह बहुत मुश्किल है, तो मुझे कुछ डरना शुरू हो रहा है? – nadir

+0

मैं आपके प्रश्न का उत्तर नहीं दे सकता, लेकिन लार्सन द्वारा आपके द्वारा लिंक किया गया पेपर बहुत दिलचस्प है, इसलिए इसके लिए धन्यवाद। अगर मैं सलाह देने जा रहा था, तो मैं कहूंगा कि इसे गोलाकारों में छोड़ दें और सिलेंडरों को अनदेखा करें: पी। – Robinson

उत्तर

1

मैं कागज के बारे में क्या समझ सकता हूं, मैं इसे निम्नानुसार समझूंगा।

किसी भी कोण से देखे जाने वाले एक अपवित्र सिलेंडर में निम्नलिखित विशेषताएं हैं।

  1. शीर्ष से, यह एक सर्कल है। तो इस पर विचार करते हुए कि आपको कभी भी सिलेंडर टॉप डाउन देखने की आवश्यकता नहीं होगी, आपको कुछ भी प्रस्तुत करने की आवश्यकता नहीं है।
  2. तरफ से, यह एक आयताकार है। पिक्सेल शेडर को केवल सामान्य के रूप में रोशनी की गणना करने की आवश्यकता है।
  3. किसी भी अन्य कोण से, यह एक आयत है (चरण 2 में गणना की गई वही है) वक्र। इसके वक्रता को पिक्सेल शेडर के अंदर शीर्ष अंडाकार के वक्रता के रूप में मॉडलिंग किया जा सकता है। देखने वाले कोण के आधार पर, इस वक्रता को बनावट स्थान में प्रत्येक "कॉलम" के ऑफसेट के रूप में माना जा सकता है। वर्तमान अंडाकार (कोण/9 0) के कारक के साथ प्रमुख अक्ष (सिलेंडर की मोटाई) को गुणा करके इस अंडाकार के नाबालिग धुरी की गणना की जा सकती है, यह मानते हुए कि 0 का मतलब है कि आप सिलेंडर साइड-ऑन देख रहे हैं।

Fig 1. कोण देखना। मैंने नीचे गणित में केवल 0-90 मामले को ध्यान में रखा है, लेकिन अन्य मामले मामूली रूप से भिन्न हैं।

Fig 2. देखने के कोण (PHI) और सिलेंडर (क) यहाँ कैसे शेडर बनावट अंतरिक्ष वाई = बी 'पाप में Y- अक्ष ताना करने की जरूरत है (PHI) के व्यास को देखते हुए। और बी '= ए * (फाई/9 0)। मामले phi = 0 और phi = 90 कभी प्रस्तुत नहीं किया जाना चाहिए। जो अपने विशेष प्रक्षेपण पर निर्भर करते हैं और एक छवि अंतरिक्ष समस्या नहीं है होगा -

बेशक, मैं खाते में सिलेंडर की लंबाई नहीं ले लिया है।

+0

के लिए धन्यवाद स्पष्टीकरण, मैं अपनी समस्या को थोड़ा बेहतर समझता हूं, लेकिन मैं हमेशा यह नहीं देखता कि आपने जो कुछ कहा है उसे कैसे जोड़ना है और इसे कार्यान्वित करना है, इसलिए यदि आपके पास विवरण में और अधिक व्याख्या करने के बाद समय है तो यह मेरे लिए बहुत उपयोगी होगा। सभी मामलों में आपके पिछले उत्तर के लिए धन्यवाद! – nadir

+0

आपके स्पष्ट स्पष्टीकरण के लिए बहुत बढ़िया धन्यवाद, केवल मेरे पास कुछ सवाल है, पहले "बनावट स्थान" से आपका क्या मतलब है? और इन मामलों का अध्ययन करने के लिए और देखने वाले कोण को ढूंढने के लिए मुझे लगता है कि मुझे "सामान्य" की आवश्यकता होगी, लेकिन मेरा सिलेंडर केवल अपवित्र है और इसलिए प्रत्येक टुकड़े के लिए टुकड़े टुकड़े में सामान्य गणना की जाती है, यह क्षेत्र के अपवित्र के साथ होता है , सामान्य के बिना इस देखने कोण को कैसे ढूंढें! – nadir

+0

बस शब्दों में कहें, बनावट की जगह (u, v) स्थान है - वह स्थान जिसे आप एक टुकड़े टुकड़े के अंदर काम करते हैं। उपर्युक्त स्पष्टीकरण में मैंने प्रकाश व्यवस्था पर बिल्कुल विचार नहीं किया है - मैं समझाता हूं कि व्यूअर को कैसे बदलना है क्योंकि देखने कोण परिवर्तन (एक्स-अक्ष के आसपास)। मैं आपको पहले प्रकाश के बिना एक बुनियादी सिलेंडर impostor प्रतिपादन प्राप्त करने की सलाह देंगे और फिर बाद में इसे जोड़ें। – Ani

2

मुझे पता है कि यह प्रश्न एक वर्ष से अधिक पुराना है, लेकिन मैं अभी भी अपना 2 सेंट देना चाहता हूं।

मैं एक और तकनीक के साथ सिलेंडर impostors उत्पादन करने में सक्षम था, मैंने pymol के कोड से प्रेरणा ली। यहाँ बुनियादी रणनीति है:

1) आप सिलेंडर के लिए बाउंडिंग बॉक्स (एक cuboid) आकर्षित करने के लिए चाहते हैं। ऐसा करने के लिए आपको 6 चेहरों की आवश्यकता है, जो 18 त्रिभुजों में अनुवाद करता है जो 36 त्रिकोण शीर्षकों में अनुवाद करता है। यह मानते हुए कि आपके पास ज्यामिति शेडर्स तक पहुंच नहीं है, आप एक कशेरुक शेडर को सिलेंडर के शुरुआती बिंदु 36 गुना, सिलेंडर की दिशा में 36 गुणा, और उन प्रत्येक चरम सीमा के लिए आप बाउंडिंग बॉक्स के संबंधित बिंदु को पास करते हैं । उदाहरण के लिए बिंदु (0, 0, 0) से जुड़े एक कशेरुका का अर्थ है कि इसे बाउंडिंग बॉक्स के निचले बाएं कोने में बदल दिया जाएगा, (1,1,1) का अर्थ है विकर्ण विपरीत बिंदु आदि ..

2) कशेरुक शेडर में, आप प्रत्येक वर्टेक्स को विस्थापित करके सिलेंडर के बिंदु बना सकते हैं (आपने 36 बराबर शिखर पारित किए हैं) आपके द्वारा पारित संबंधित बिंदुओं के अनुसार इस चरण के अंत में आपको बाध्य होना चाहिए सिलेंडर के लिए बॉक्स।

3) यहां आपको बाउंडिंग बॉक्स की दृश्य सतह पर बिंदुओं का पुनर्निर्माण करना होगा। आपके द्वारा प्राप्त बिंदु से, आपको एक रे-सिलेंडर चौराहे करना है।

4) चौराहे बिंदु से आप गहराई और सामान्य पुनर्निर्माण कर सकते हैं। आपको बाउंडिंग बॉक्स के बाहर पाए जाने वाले चौराहे बिंदुओं को भी छोड़ना होगा (यह तब हो सकता है जब आप अपनी धुरी के साथ सिलेंडर देखते हैं, चौराहे बिंदु असीम रूप से दूर जाएगा)।

https://github.com/chemlab/chemlab/blob/master/chemlab/graphics/renderers/shaders/cylinderimp.frag

https://github.com/chemlab/chemlab/blob/master/chemlab/graphics/renderers/shaders/cylinderimp.vert

2

pygabriels के अलावा का जवाब मैं का उपयोग कर एक स्टैंडअलोन कार्यान्वयन साझा करना चाहते हैं:

जिस तरह से यह एक बहुत ही मुश्किल काम है, यहाँ है कि अगर किसी को दिलचस्पी है द्वारा स्रोत कोड है ब्लेन बेल (पीईएमओएल, श्रोडिंगर, इंक) से शेडर कोड का उल्लेख किया गया।

पाइगब्रियल द्वारा समझाया गया दृष्टिकोण भी सुधार किया जा सकता है। बाउंडिंग बॉक्स को इस तरह से गठबंधन किया जा सकता है, कि यह हमेशा दर्शक को सामना करता है। अधिकांश में केवल दो चेहरे दिखाई दे रहे हैं। इसलिए, केवल 6 शिखर (यानी 4 त्रिकोणों से बने दो चेहरे) की आवश्यकता होती है। डाउनलोड
Image: Aligned bounding box

स्रोत कोड के लिए,: cylinder impostor source code

कोड कैप और ओर्थोग्रफिक अनुमानों दौर को कवर नहीं करता

देखें चित्र यहाँ, बॉक्स (अपनी दिशा वेक्टर) हमेशा दर्शक को सामना करना पड़ता है। यह वर्टेक्स पीढ़ी के लिए ज्यामिति शेडर का उपयोग करता है। आप पीएमएमओएल लाइसेंस समझौते के तहत शेडर कोड का उपयोग कर सकते हैं।

1

एक सिलेंडर impostor वास्तव में एक क्षेत्र के समान ही किया जा सकता है, जैसे Nicol Bolas ने इसे अपने ट्यूटोरियल में किया था। आप कैमरे का सामना कर एक वर्ग बना सकते हैं और इसे रंग सकते हैं कि यह एक सिलेंडर की तरह दिखाई देगा, ठीक उसी तरह निकोल ने गोलाकारों के लिए किया था। और यह नहीं है हार्ड।

जिस तरह से किया जाता है वह निश्चित रूप से रे-ट्रेसिंग है। ध्यान दें कि कैमरे की जगह में ऊपर की ओर एक सिलेंडर का सामना करना आसान है। उदाहरण के लिए पक्ष के साथ चौराहे को xz सादे में पेश किया जा सकता है, यह एक सर्कल के साथ छेड़छाड़ वाली रेखा की 2 डी समस्या है। ऊपर और नीचे प्राप्त करना कठिन नहीं है, चौराहे का जेड समन्वय दिया जाता है, इसलिए आप वास्तव में किरण के चौराहे बिंदु और सर्कल के मैदान को जानते हैं, आपको बस यह करना है कि यह सर्कल के अंदर है या नहीं। और मूल रूप से, यह है, आपको दो अंक मिलते हैं, और करीब एक लौटते हैं (मानक भी बहुत तुच्छ हैं)।

और जब यह मनमाने ढंग से धुरी की बात आती है, तो यह लगभग एक ही समस्या होती है। जब आप निश्चित धुरी सिलेंडर पर समीकरण हल करते हैं, तो आप उन्हें एक पैरामीटर के लिए हल कर रहे हैं जो बताता है कि सिलेंडर तक पहुंचने के लिए किसी दिए गए दिशा में आपको किसी दिए गए बिंदु से कितना समय जाना है। इसकी "परिभाषा" से, आपको ध्यान रखना चाहिए कि यदि आप दुनिया को घुमाते हैं तो यह पैरामीटर नहीं बदलता है। तो आप वाई अक्ष बनने के लिए मनमानी अक्ष को घुमा सकते हैं, उस स्थान में समस्या को हल कर सकते हैं जहां समीकरण आसान हैं, उस स्थान में रेखा समीकरण के लिए पैरामीटर प्राप्त करें, लेकिन परिणाम को कैमरा स्थान में वापस कर दें।

आप here से शेडरफ़ाइल डाउनलोड कर सकते हैं। कार्रवाई में यह बस एक चित्र: screenshot http://oi40.tinypic.com/2h5tqhy.jpg

कोड जहां जादू होता है (यह केवल लंबी है 'क्योंकि यह टिप्पणी से भरा हुआ है, लेकिन कोड में ही अधिकतम 50 लाइनों है):

void CylinderImpostor(out vec3 cameraPos, out vec3 cameraNormal) 
{ 
    // First get the camera space direction of the ray. 
    vec3 cameraPlanePos = vec3(mapping * max(cylRadius, cylHeight), 0.0) + cameraCylCenter; 
    vec3 cameraRayDirection = normalize(cameraPlanePos); 

    // Now transform data into Cylinder space wherethe cyl's symetry axis is up. 
    vec3 cylCenter = cameraToCylinder * cameraCylCenter; 
    vec3 rayDirection = normalize(cameraToCylinder * cameraPlanePos); 


    // We will have to return the one from the intersection of the ray and circles, 
    // and the ray and the side, that is closer to the camera. For that, we need to 
    // store the results of the computations. 
    vec3 circlePos, sidePos; 
    vec3 circleNormal, sideNormal; 
    bool circleIntersection = false, sideIntersection = false; 

    // First check if the ray intersects with the top or bottom circle 
    // Note that if the ray is parallel with the circles then we 
    // definitely won't get any intersection (but we would divide with 0). 
    if(rayDirection.y != 0.0){ 
     // What we know here is that the distance of the point's y coord 
     // and the cylCenter is cylHeight, and the distance from the 
     // y axis is less than cylRadius. So we have to find a point 
     // which is on the line, and match these conditions. 

     // The equation for the y axis distances: 
     // rayDirection.y * t - cylCenter.y = +- cylHeight 
     // So t = (+-cylHeight + cylCenter.y)/rayDirection.y 
     // About selecting the one we need: 
     // - Both has to be positive, or no intersection is visible. 
     // - If both are positive, we need the smaller one. 
     float topT = (+cylHeight + cylCenter.y)/rayDirection.y; 
     float bottomT = (-cylHeight + cylCenter.y)/rayDirection.y; 
     if(topT > 0.0 && bottomT > 0.0){ 
      float t = min(topT,bottomT); 

      // Now check for the x and z axis: 
      // If the intersection is inside the circle (so the distance on the xz plain of the point, 
      // and the center of circle is less than the radius), then its a point of the cylinder. 
      // But we can't yet return because we might get a point from the the cylinder side 
      // intersection that is closer to the camera. 
      vec3 intersection = rayDirection * t; 
      if(length(intersection.xz - cylCenter.xz) <= cylRadius) { 
       // The value we will (optianally) return is in camera space. 
       circlePos = cameraRayDirection * t; 
       // This one is ugly, but i didn't have better idea. 
       circleNormal = length(circlePos - cameraCylCenter) < 
           length((circlePos - cameraCylCenter) + cylAxis) ? cylAxis : -cylAxis; 
       circleIntersection = true; 
      } 
     } 
    } 


    // Find the intersection of the ray and the cylinder's side 
    // The distance of the point and the y axis is sqrt(x^2 + z^2), which has to be equal to cylradius 
    // (rayDirection.x*t - cylCenter.x)^2 + (rayDirection.z*t - cylCenter.z)^2 = cylRadius^2 
    // So its a quadratic for t (A*t^2 + B*t + C = 0) where: 
    // A = rayDirection.x^2 + rayDirection.z^2 - if this is 0, we won't get any intersection 
    // B = -2*rayDirection.x*cylCenter.x - 2*rayDirection.z*cylCenter.z 
    // C = cylCenter.x^2 + cylCenter.z^2 - cylRadius^2 
    // It will give two results, we need the smaller one 

    float A = rayDirection.x*rayDirection.x + rayDirection.z*rayDirection.z; 
    if(A != 0.0) { 
     float B = -2*(rayDirection.x*cylCenter.x + rayDirection.z*cylCenter.z); 
     float C = cylCenter.x*cylCenter.x + cylCenter.z*cylCenter.z - cylRadius*cylRadius; 

     float det = (B * B) - (4 * A * C); 
     if(det >= 0.0){ 
      float sqrtDet = sqrt(det); 
      float posT = (-B + sqrtDet)/(2*A); 
      float negT = (-B - sqrtDet)/(2*A); 

      float IntersectionT = min(posT, negT); 
      vec3 Intersect = rayDirection * IntersectionT; 

      if(abs(Intersect.y - cylCenter.y) < cylHeight){ 
       // Again it's in camera space 
       sidePos = cameraRayDirection * IntersectionT; 
       sideNormal = normalize(sidePos - cameraCylCenter); 
       sideIntersection = true; 
      } 
     } 
    } 

    // Now get the results together: 
    if(sideIntersection && circleIntersection){ 
     bool circle = length(circlePos) < length(sidePos); 
     cameraPos = circle ? circlePos : sidePos; 
     cameraNormal = circle ? circleNormal : sideNormal; 
    } else if(sideIntersection){ 
     cameraPos = sidePos; 
     cameraNormal = sideNormal; 
    } else if(circleIntersection){ 
     cameraPos = circlePos; 
     cameraNormal = circleNormal; 
    } else 
     discard; 
}