GluSphere () का उपयोग किए बिना OpenGL में क्षेत्र को आकर्षित करना?


81

क्या कोई ट्यूटोरियल है जो समझाता है कि मैं ओपनजीएल में एक गोले का उपयोग किए बिना कैसे आकर्षित कर सकता हूं gluSphere()?

ओपनजीएल के लिए 3 डी ट्यूटोरियल के कई सिर्फ क्यूब्स पर हैं। मैंने खोज की है, लेकिन एक क्षेत्र को खींचने के अधिकांश समाधानों का उपयोग करना है gluSphere()। एक साइट भी है जिसमें इस साइट पर एक गोले को खींचने के लिए कोड है लेकिन यह गोले को खींचने के पीछे के गणित की व्याख्या नहीं करता है। मेरे पास उस लिंक में क्वैड के बजाय बहुभुज में गोले को कैसे आकर्षित करना है, इसके अन्य संस्करण भी हैं। लेकिन फिर से, मुझे समझ में नहीं आता है कि कैसे कोड के साथ गोले खींचे जाते हैं। मैं कल्पना करने में सक्षम होना चाहता हूं ताकि मुझे जरूरत पड़ने पर क्षेत्र को संशोधित कर सके।


3
गणित के स्पष्टीकरण के लिए गोलाकार निर्देशांक देखें (विशेष रूप से गोलाकार निर्देशांक से कार्टेशियन निर्देशांक में रूपांतरण)।
नेड बिंघम

जवाबों:


271

एक तरीका यह है कि आप त्रिकोणीय पक्षों के साथ एक प्लैटोनिक ठोस के साथ शुरू कर सकते हैं - उदाहरण के लिए, एक ऑक्टाहेड्रोन । फिर, प्रत्येक त्रिभुज को ले जाएं और पुन: इसे छोटे त्रिभुजों में विभाजित करें, जैसे:

पुनरावर्ती रूप से तैयार किए गए त्रिकोण

एक बार जब आपके पास पर्याप्त मात्रा में बिंदु होते हैं, तो आप उनके वैक्टर को सामान्य करते हैं ताकि वे सभी ठोस के केंद्र से निरंतर दूरी पर हों। यह पक्षों को एक आकार में उभारने का कारण बनता है जो एक गोले जैसा दिखता है, जैसे ही आप अंक बढ़ाते हैं, चिकनाई बढ़ती जाती है।

यहां सामान्यीकरण का मतलब एक बिंदु को स्थानांतरित करना है ताकि किसी अन्य बिंदु के संबंध में इसका कोण समान हो, लेकिन उनके बीच की दूरी अलग है। यहाँ एक दो आयामी उदाहरण है।

यहाँ छवि विवरण दर्ज करें

A और B 6 इकाइयाँ हैं। लेकिन मान लीजिए हम लाइन एबी पर एक बिंदु खोजना चाहते हैं जो ए से 12 यूनिट दूर है।

यहाँ छवि विवरण दर्ज करें

हम कह सकते हैं कि C, A के संबंध में B का सामान्यीकृत रूप है। दूरी 12 के साथ। हम C को इस तरह कोड के साथ प्राप्त कर सकते हैं:

#returns a point collinear to A and B, a given distance away from A. 
function normalize(a, b, length):
    #get the distance between a and b along the x and y axes
    dx = b.x - a.x
    dy = b.y - a.y
    #right now, sqrt(dx^2 + dy^2) = distance(a,b).
    #we want to modify them so that sqrt(dx^2 + dy^2) = the given length.
    dx = dx * length / distance(a,b)
    dy = dy * length / distance(a,b)
    point c =  new point
    c.x = a.x + dx
    c.y = a.y + dy
    return c

यदि हम एक ही बिंदु A के संबंध में और समान दूरी R के साथ, बहुत सारे बिंदुओं पर इस सामान्यीकरण प्रक्रिया को करते हैं, तो सामान्यीकृत बिंदु सभी केंद्र A और त्रिज्या R के साथ एक वृत्त के चाप पर स्थित होंगे।

उभड़ा हुआ रेखा खंड

यहां, काले बिंदु एक रेखा पर शुरू होते हैं और एक आर्क में "उभार" करते हैं।

इस प्रक्रिया को तीन आयामों में बढ़ाया जा सकता है, जिस स्थिति में आपको एक वृत्त की बजाय एक गोले की प्राप्ति होती है। फ़ंक्शन को सामान्य करने के लिए बस एक dz घटक जोड़ें।

सामान्यीकृत बहुभुज

स्तर 1 उभड़ा हुआ ऑक्टाहेड्रोन स्तर 3 उभड़ा हुआ ऑक्टाहेड्रोन

यदि आप एप्कोट पर क्षेत्र को देखते हैं, तो आप इस तकनीक को काम पर देख सकते हैं। यह गोल-गोल दिखने के लिए उभरे हुए चेहरों वाला एक डोडेकेर्रॉन है।


1
बल्कि मैं एपकॉट क्षेत्र के लिंक को हटा दूंगा। यह शुरुआती को भ्रमित कर सकता है क्योंकि हर त्रिभुज को फिर से तीन समद्विबाहु त्रिभुजों में विभाजित किया गया है (sqrt (3) -subdivision के पहले भाग के समान)। मुझे यकीन है कि आपको एक बेहतर उदाहरण मिलेगा।
क्रिश्चियन राउ

मैं अपने घर मशीन पर इसका एक अच्छा कार्यान्वयन है। मुझे काम के बाद कुछ स्क्रीनशॉट में एडिट करके खुशी होगी।
केविन

विचार के लिए धन्यवाद। लेकिन मुझे यह समझ नहीं आ रहा है कि कैसे वैक्टरों को सामान्य करके, मैं पक्षों को एक आकार में उभारा जा सकता है जो गोलाकार जैसा दिखता है? मैं पक्षों को कैसे बाहर निकालूं?
कारवां

1
@xEnOn, मैंने सामान्यीकरण को थोड़ा और समझाने के लिए अपना उत्तर संपादित किया है। मुझे लगता है कि समस्या यह है कि सामान्यीकरण उस प्रक्रिया के लिए वास्तविक तकनीकी शब्द नहीं है जिसे मैं समझाने की कोशिश कर रहा था, इसलिए आपके लिए इस पर कहीं और जानकारी प्राप्त करना मुश्किल होगा। उसके लिए माफ़ करना।
केविन

1
शायद "सामान्यीकरण" प्रक्रिया को समझाने का एक बेहतर तरीका यह है कि बिंदुओं को एक गोले पर पेश किया जा रहा है। यह भी ध्यान दें कि परिणाम इस आधार पर अलग-अलग होते हैं कि क्या सामान्यीकरण / प्रक्षेपण केवल एक बार अंत में लागू किया जाता है (सभी उपखंड के बाद, जो लगता है कि जो यहां सुझाया जा रहा है) या (पुनरावर्ती) उपखंड चरणों के साथ interleaved है। ऐसा प्रतीत होता है कि सिर्फ़ एक बार प्रोजेक्ट करने से प्रारंभिक ऑक्टाहेड्रोन के कोने के पास वर्टिकल क्लैरिज़ हो जाता है, जबकि इंटरलेव्ड सबडिविज़न और प्रोजेक्शन वर्ज़न के बीच एक समान दूरी पैदा करता है।
टायलर स्ट्रीटर सेप

26

मैं आगे अक्षांश और देशांतर का उपयोग करके एक क्षेत्र उत्पन्न करने का एक लोकप्रिय तरीका समझाऊंगा (दूसरा तरीका, इकोस्फेरेस , इस लेखन के समय पहले से ही सबसे लोकप्रिय उत्तर में समझाया गया था।)

एक क्षेत्र निम्नलिखित पैरामीट्रिक समीकरण द्वारा व्यक्त किया जा सकता है:

एफ ( यू , v ) = [cos (u) * sin (v) * r, cos (v) * r, sin (u) * sin (v) * r]

कहाँ पे:

  • आर त्रिज्या है;
  • यू देशांतर है, 0 से 2 the तक; तथा
  • v अक्षांश है, 0 से π तक।

क्षेत्र को उत्पन्न करने के बाद निश्चित अंतराल पर पैरामीट्रिक फ़ंक्शन का मूल्यांकन करना शामिल है।

उदाहरण के लिए, देशांतर की 16 लाइनें उत्पन्न करने के लिए, यू के साथ 17 ग्रिड लाइनें होंगी अक्ष के , step / 8 (2π / 16) के चरण के साथ (17 वीं पंक्ति चारों ओर लपेटती है)।

निम्नलिखित pseudocode नियमित अंतराल पर पैरामीट्रिक फ़ंक्शन का मूल्यांकन करके एक त्रिकोण जाल उत्पन्न करता है (यह किसी के लिए भी काम करता है पैरामीट्रिक सतह फ़ंक्शन के , न कि केवल गोले)।

नीचे pseudocode में, Uesolution U अक्ष (यहाँ, देशांतर की रेखाएँ) के साथ ग्रिड बिंदुओं की संख्या है , और VResolution V अक्ष (यहाँ, अक्षांश की रेखाएँ) के साथ ग्रिड बिंदुओं की संख्या है

var startU=0
var startV=0
var endU=PI*2
var endV=PI
var stepU=(endU-startU)/UResolution // step size between U-points on the grid
var stepV=(endV-startV)/VResolution // step size between V-points on the grid
for(var i=0;i<UResolution;i++){ // U-points
 for(var j=0;j<VResolution;j++){ // V-points
 var u=i*stepU+startU
 var v=j*stepV+startV
 var un=(i+1==UResolution) ? EndU : (i+1)*stepU+startU
 var vn=(j+1==VResolution) ? EndV : (j+1)*stepV+startV
 // Find the four points of the grid
 // square by evaluating the parametric
 // surface function
 var p0=F(u, v)
 var p1=F(u, vn)
 var p2=F(un, v)
 var p3=F(un, vn)
 // NOTE: For spheres, the normal is just the normalized
 // version of each vertex point; this generally won't be the case for
 // other parametric surfaces.
 // Output the first triangle of this grid square
 triangle(p0, p2, p1)
 // Output the other triangle of this grid square
 triangle(p3, p1, p2)
 }
}

डाउन वोट थोड़ा कठोर लगता है। यह एकमात्र ऐसे उत्तर और उदाहरण के साथ है जिसमें क्षेत्र के पैरामीट्रिक समीकरण के माध्यम से असतत निर्माण का उल्लेख है। इस आधार पर समझना आसान भी हो सकता है कि एक गोले को उन हलकों के ढेर के रूप में माना जा सकता है जो ध्रुवों के पास सिकुड़ते हैं।
Spacen Jasset

2
नमस्कार, मैं केवल यह बताना चाहता था कि p0, p1, P2, p3 के प्रत्येक मान का दूसरा या तो v या vn होना चाहिए, जैसा कि u या un के विपरीत है।
निकोल

9

नमूने में कोड जल्दी से समझाया गया है। आपको समारोह में देखना चाहिए void drawSphere(double r, int lats, int longs):

void drawSphere(double r, int lats, int longs) {
    int i, j;
    for(i = 0; i <= lats; i++) {
        double lat0 = M_PI * (-0.5 + (double) (i - 1) / lats);
        double z0  = sin(lat0);
        double zr0 =  cos(lat0);

        double lat1 = M_PI * (-0.5 + (double) i / lats);
        double z1 = sin(lat1);
        double zr1 = cos(lat1);

        glBegin(GL_QUAD_STRIP);
        for(j = 0; j <= longs; j++) {
            double lng = 2 * M_PI * (double) (j - 1) / longs;
            double x = cos(lng);
            double y = sin(lng);

            glNormal3f(x * zr0, y * zr0, z0);
            glVertex3f(r * x * zr0, r * y * zr0, r * z0);
            glNormal3f(x * zr1, y * zr1, z1);
            glVertex3f(r * x * zr1, r * y * zr1, r * z1);
        }
        glEnd();
    }
}

पैरामीटर latपरिभाषित करता है कि आप अपने क्षेत्र में कितनी क्षैतिज रेखाएँ और lonकितनी ऊर्ध्वाधर रेखाएँ चाहते हैं। rआपके क्षेत्र की त्रिज्या है।

अब एक डबल चलना है lat/ lonऔर शीर्ष निर्देशांक की गणना सरल त्रिकोणमिति का उपयोग करके की जाती है।

गणना किए गए कोने अब आपके GPU के glVertex...()रूप में उपयोग किए जा रहे हैं GL_QUAD_STRIP, जिसका अर्थ है कि आप प्रत्येक दो कोने भेज रहे हैं जो पहले भेजे गए दो के साथ एक क्वाड बनाते हैं।

अब आपको यह समझना होगा कि त्रिकोणमिति फ़ंक्शन कैसे काम करता है, लेकिन मुझे लगता है कि आप इसे आसानी से समझ सकते हैं।


@PintoDoido: यह ओपी के मूल लिंक से था जो किसी बिंदु पर मर गया; मैंने लिंक को स्पष्टता के लिए इस उत्तर में लिंक को संपादित किया और फ़ंक्शन को संपादित किया।
जेनपफल्ट

2
त्रिज्या गायब है।
tomasantunes

1
पहले पैरामीटर "डबल आर" का उपयोग नहीं किया जाता है।
ओलिड्डबग २३

1
वह सही है। कोड नमूना मेरे मूल उत्तर का हिस्सा नहीं है। @genpfault: आपने एक एडिट में कोड सैंपल जोड़ा। क्या आप कृपया उदाहरण को ठीक कर सकते हैं?
कांस्टेंटिनियस

1
धन्यवाद एक गुच्छा :)
कॉन्स्टेंटिनियस


1

यदि आप एक लोमड़ी की तरह धूर्त बनना चाहते हैं तो आप GLU से कोड का आधा-इंच हिस्सा ले सकते हैं। MesaGL स्रोत कोड देखें (http://cgit.freedesktop.org/mesa/mesa/)।


4
जब तक मैं इस संदर्भ में "आधा-इंच" का अर्थ समझता था, मुझे लगता है कि आप इसे अन्य 95% पाठकों के लिए संपादित करना चाह सकते हैं जो कॉकनी राइमिंग स्लैंग में धाराप्रवाह नहीं हैं !
फ्लेक्सो

1

मेरा उदाहरण है कि "ध्रुवीय" क्षेत्र को खींचने के लिए 'त्रिकोण पट्टी' का उपयोग कैसे किया जाता है, इसमें जोड़े में ड्राइंग बिंदु होते हैं:

const float PI = 3.141592f;
GLfloat x, y, z, alpha, beta; // Storage for coordinates and angles        
GLfloat radius = 60.0f;
int gradation = 20;

for (alpha = 0.0; alpha < GL_PI; alpha += PI/gradation)
{        
    glBegin(GL_TRIANGLE_STRIP);
    for (beta = 0.0; beta < 2.01*GL_PI; beta += PI/gradation)            
    {            
        x = radius*cos(beta)*sin(alpha);
        y = radius*sin(beta)*sin(alpha);
        z = radius*cos(alpha);
        glVertex3f(x, y, z);
        x = radius*cos(beta)*sin(alpha + PI/gradation);
        y = radius*sin(beta)*sin(alpha + PI/gradation);
        z = radius*cos(alpha + PI/gradation);            
        glVertex3f(x, y, z);            
    }        
    glEnd();
}

पहला बिंदु (glVertex3f) पैरामीट्रिक समीकरण का अनुसरण करता है और दूसरा एक अल्फा कोण (अगले समानांतर से) के एकल चरण द्वारा स्थानांतरित किया जाता है।


1

यद्यपि स्वीकृत उत्तर प्रश्न को हल करता है, अंत में थोड़ी गलत धारणा है। डोडेकेहेड्रोन नियमित पॉलीहेड्रॉन हैं (या हो सकते हैं) जहां सभी चेहरों का एक ही क्षेत्र हो। ऐसा लगता है कि एपकोट (जो, वैसे, डोडेकाहेड्रॉन बिल्कुल नहीं है) का मामला है । चूंकि @Kevin द्वारा प्रस्तावित समाधान इस विशेषता को प्रदान नहीं करता है मैंने सोचा कि मैं एक दृष्टिकोण जोड़ सकता हूं जो करता है।

एक एन-सामना करना पड़ा पॉलीहेड्रोन उत्पन्न करने का एक अच्छा तरीका है जहां सभी कोने एक ही गोले में स्थित हैं और इसके सभी चेहरों में समान क्षेत्र / सतह एक आइकोसैहेड्रन के साथ शुरू हो रहा है और पुनरावृत्त उप-विभाजन और इसके त्रिकोणीय चेहरों को सामान्य करता है (जैसा कि स्वीकृत उत्तर में सुझाया गया है) ) है। उदाहरण के लिए, डोडेकेहेड्रोन, वास्तव में इकोसैड्रोन को काट दिया जाता है

नियमित इकोसैड्रोन में 20 चेहरे (12 कोने) होते हैं और आसानी से 3 स्वर्ण आयतों से निर्माण किया जा सकता है; यह केवल एक ऑक्टाहेड्रोन के बजाय एक शुरुआती बिंदु के रूप में होने की बात है। आपको यहां एक उदाहरण मिल सकता है

मुझे पता है कि यह थोड़ा ऑफ-टॉपिक है, लेकिन मेरा मानना ​​है कि अगर कोई इस विशिष्ट मामले की तलाश में यहां पहुंचता है तो यह मदद कर सकता है।


0

एक तरीका यह है कि एक क्वाड बनाया जाए जो कैमरे का सामना करे और एक वर्टेक्स और फ्रैगरेशन शेडर लिखे जो कि एक गोले की तरह दिखने वाली चीज़ को प्रस्तुत करे। आप एक सर्कल / क्षेत्र के लिए समीकरणों का उपयोग कर सकते हैं जो आप इंटरनेट पर पा सकते हैं।

एक अच्छी बात यह है कि एक गोले का सिल्हूट किसी भी कोण से समान दिखता है। हालांकि, यदि क्षेत्र एक परिप्रेक्ष्य दृश्य के केंद्र में नहीं है, तो यह संभवतः एक दीर्घवृत्त की तरह दिखाई देगा। आप इसके लिए समीकरण बना सकते हैं और उन्हें खंडित छायांकन में डाल सकते हैं। फिर खिलाड़ी के चलते ही लाइट शेडिंग को बदलना पड़ता है, यदि आपके पास वास्तव में एक खिलाड़ी 3 डी स्पेस में घूम रहा है।

क्या कोई इस पर टिप्पणी कर सकता है कि क्या उन्होंने यह कोशिश की है या यदि यह व्यावहारिक होना बहुत महंगा है?


यह केवल एक समानांतर प्रक्षेपण के तहत सच है। यदि आप एक परिप्रेक्ष्य प्रक्षेपण का उपयोग करते हैं, तो रेंडरिंग आउटपुट में गोले का सिल्हूट आम तौर पर एक चक्र नहीं होता है।
रेटो कोराडी

0

@ कॉन्सटेंटिनियस उत्तर का पायथन अनुकूलन:

lats = 10
longs = 10
r = 10

for i in range(lats):
    lat0 = pi * (-0.5 + i / lats)
    z0 = sin(lat0)
    zr0 = cos(lat0)

    lat1 = pi * (-0.5 + (i+1) / lats)
    z1 = sin(lat1)
    zr1 = cos(lat1)

    glBegin(GL_QUAD_STRIP)
    for j in range(longs+1):
        lng = 2 * pi * (j+1) / longs
        x = cos(lng)
        y = sin(lng)

        glNormal(x * zr0, y * zr0, z0)
        glVertex(r * x * zr0, r * y * zr0, r * z0)
        glNormal(x * zr1, y * zr1, z1)
        glVertex(r * x * zr1, r * y * zr1, r * z1)

    glEnd()

0
void draw_sphere()
{

    //              z
    //              |
    //               __
    //             /|          
    //              |           
    //              |           
    //              |    *      \
    //              | _ _| _ _ _ |    _y
    //             / \c  |n     /                    p3 --- p2
    //            /   \o |i                           |     |
    //           /     \s|s      z=sin(v)            p0 --- p1
    //         |/__              y=cos(v) *sin(u)
    //                           x=cos(v) *cos(u) 
    //       /
    //      x
    //


    double pi = 3.141592;
    double di =0.02;
    double dj =0.04;
    double du =di*2*pi;
    double dv =dj*pi;


    for (double i = 0; i < 1.0; i+=di)  //horizonal
    for (double j = 0; j < 1.0; j+=dj)  //vertical
    {       
        double u = i*2*pi;      //0     to  2pi
        double v = (j-0.5)*pi;  //-pi/2 to pi/2

        double  p[][3] = { 
            cos(v)     * cos(u)      ,cos(v)     * sin(u)       ,sin(v),
            cos(v)     * cos(u + du) ,cos(v)     * sin(u + du)  ,sin(v),
            cos(v + dv)* cos(u + du) ,cos(v + dv)* sin(u + du)  ,sin(v + dv),
            cos(v + dv)* cos(u)      ,cos(v + dv)* sin(u)       ,sin(v + dv)};

        //normal
        glNormal3d(cos(v+dv/2)*cos(u+du/2),cos(v+dv/2)*sin(u+du/2),sin(v+dv/2));

        glBegin(GL_POLYGON);
            glTexCoord2d(i,   j);    glVertex3dv(p[0]);
            glTexCoord2d(i+di,j);    glVertex3dv(p[1]);
            glTexCoord2d(i+di,j+dj); glVertex3dv(p[2]);
            glTexCoord2d(i,   j+dj); glVertex3dv(p[3]);
        glEnd();
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.