ओपनजीएल: मुझे ग्लेनॉर्मल के साथ एक सामान्य सेट क्यों करना है?


19

मैं ओपनजीएल के कुछ मूल बातें सीख रहा हूं, लेकिन मैं सोच रहा हूं कि glNormalकोने के सामान्य सेट करने के लिए कॉल क्यों है ।

अगर मैं इस तरह एक सरल त्रिभुज बनाता हूं:

glBegin(GL_TRIANGLES);
    glVertex3f(0,0,0);
    glVertex3f(1,0,0);
    glVertex3f(0,1,0);
glEnd();

क्या ज्यामितीय आदिम के प्रकार से मानदंडों को स्पष्ट रूप से परिभाषित नहीं किया जाना चाहिए? अगर मैं एक सामान्य सेट नहीं करता तो OpenGL इसकी गणना करेगा?


7
मैं केवल यह बताना चाहूंगा कि यह कोड डीरेल्ड फिक्स्ड-फंक्शन पाइपलाइन का उपयोग कर रहा है, और आधुनिक ओपनजीएल में नॉर्म्स और वर्टिकल दोनों ही जेनेरिक वर्टेक्स विशेषताएँ हैं।
बार्टेक बैनवाक्विज़

4
तत्काल मोड का उपयोग न करें। यह पदावनत है। मैं अत्यधिक आधुनिक 3D ग्राफिक्स प्रोग्रामिंग सीखने की सलाह देता हूं ।
सही गुना

3
मुझे लगता है कि तत्काल मोड के उपयोग पर टिप्पणी पूरी तरह से अप्रासंगिक है। हां, किसी को इसका उपयोग नहीं करना चाहिए, लेकिन सवाल का बिंदु एक ही तरह का है, चाहे वह तत्काल मोड हो, वर्टेक्स एरे, वीबीओ, जेनेरिक एट्रीब, फिक्स्ड एट्रीब या टोस्ट के बिट्स।
मैक्सिमस मिनिमस

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

जवाबों:


30

के glNormalबीच कई बार कॉल glBegin/Endकरने से आप प्रति आदिम के बजाय एक सामान्य प्रति शीर्ष सेट कर सकते हैं।

glBegin(GL_TRIANGLES);
    glNormal3f(0,0,1);
    glVertex3f(0,0,0);
    glNormal3f(0,0,1);
    glVertex3f(1,0,0);
    glNormal3f(0,0,1);
    glVertex3f(0,1,0);
glEnd();

कई त्रिभुजों से मिलकर अधिक जटिल जाल के लिए आप चाहते हैं कि एक शीर्ष पर सामान्य आसपास के ज्यामिति के अन्य त्रिकोणों पर निर्भर हो और न केवल उस त्रिकोण के सामान्य पर निर्भर हो।

यहाँ उसी ज्यामिति का एक उदाहरण दिया गया है:

  • बाएं प्रति-शीर्ष मानदंड पर - इसलिए चेहरे के प्रत्येक शीर्ष पर एक अलग सामान्य स्थिति है (इस क्षेत्र के लिए इसका अर्थ है कि सभी मानदंड अपने केंद्र से बाहर की ओर इंगित करते हैं), और
  • सही प्रति-फेस मानदंड पर - प्रत्येक शीर्ष को एक ही सामान्य मान प्राप्त होता है (क्योंकि आप इसे केवल एक बार निर्दिष्ट करते हैं, या क्योंकि यह डिफ़ॉल्ट सामान्य मान का उपयोग करता है (0,0,1)):

बाईं ओर प्रति-शीर्ष मानदंड, दाईं ओर प्रति-प्रतिमान मानदंड

डिफ़ॉल्ट शेड मॉडल ( GL_SMOOTH) चेहरे के कोने के मानदंडों को पूरे चेहरे पर प्रक्षेपित करने का कारण बनता है। के लिए प्रति-शिखर normals एक चिकनी छायांकित क्षेत्र में इस परिणाम है, लेकिन के लिए प्रति-चेहरे normals आप विशेषता आयामी देखो के साथ खत्म होता है।


4

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

आपको सामान्य कोने खोजने और मानदंड की गणना करने के लिए एक मेष के "त्रिकोण सूप" को पूर्वप्रक्रमित करने की आवश्यकता है। गति के लिए खेल चलने से पहले यह किया जाना चाहिए।

वहाँ भी हार्ड किनारों की तरह मामले हैं जहां ज्यामितीय रूप से कोने में एक साझा शीर्ष है, लेकिन आप अलग-अलग मानदंड चाहते हैं ताकि यह सही ढंग से रोशनी हो। जीएल / डी 3 डी प्रतिपादन मॉडल में, आपको इसके लिए दो अलग-अलग कोने (एक ही स्थिति में) की आवश्यकता होती है, प्रत्येक एक अलग सामान्य के साथ।

आपको यूवी और टेक्सचर मैपिंग के लिए भी यह सब चाहिए होगा।


3

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

तो चलिए मान लेते हैं कि आप कुछ ऐसा कर रहे हैं जहाँ glNormal निर्दिष्ट करता है और इसे कुछ और देखता है।

glNormal को प्रति-आदिम या प्रति-शीर्ष निर्दिष्ट किया जा सकता है। प्रति-आदिम मानदंडों के साथ इसका मतलब यह है कि एक ही दिशा में आदिम चेहरे में प्रत्येक शीर्ष के लिए सभी मानदंड हैं। कभी-कभी यह वही होता है जो आप चाहते हैं लेकिन कभी-कभी ऐसा नहीं होता है - जहां प्रति-शीर्ष मानदंड उपयोगी होते हैं, यह है कि वे प्रत्येक शीर्ष को स्वयं सामना करने की अनुमति देते हैं।

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


2

न्यूनतम उदाहरण जो कि glNormalविसरित बिजली के साथ काम करने के कुछ विवरणों को दिखाता है ।

displayफ़ंक्शन की टिप्पणियां बताती हैं कि प्रत्येक त्रिकोण का क्या अर्थ है।

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

#include <stdlib.h>

#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>

/* Triangle on the x-y plane. */
static void draw_triangle() {
    glBegin(GL_TRIANGLES);
    glVertex3f( 0.0f,  1.0f, 0.0f);
    glVertex3f(-1.0f, -1.0f, 0.0f);
    glVertex3f( 1.0f, -1.0f, 0.0f);
    glEnd();
}

/* A triangle tilted 45 degrees manually. */
static void draw_triangle_45() {
    glBegin(GL_TRIANGLES);
    glVertex3f( 0.0f,  1.0f, -1.0f);
    glVertex3f(-1.0f, -1.0f,  0.0f);
    glVertex3f( 1.0f, -1.0f,  0.0f);
    glEnd();
}

static void display(void) {
    glColor3f(1.0f, 0.0f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    glPushMatrix();

    /*
    Triangle perpendicular to the light.
    0,0,1 also happens to be the default normal if we hadn't specified one.
    */
    glNormal3f(0.0f, 0.0f, 1.0f);
    draw_triangle();

    /*
    This triangle is as bright as the previous one.
    This is not photorealistic, where it should be less bright.
    */
    glTranslatef(2.0f, 0.0f, 0.0f);
    draw_triangle_45();

    /*
    Same as previous triangle, but with the normal set
    to the photorealistic value of 45, making it less bright.

    Note that the norm of this normal vector is not 1,
    but we are fine since we are using `glEnable(GL_NORMALIZE)`.
    */
    glTranslatef(2.0f, 0.0f, 0.0f);
    glNormal3f(0.0f, 1.0f, 1.0f);
    draw_triangle_45();

    /*
    This triangle is rotated 45 degrees with a glRotate.
    It should be as bright as the previous one,
    even though we set the normal to 0,0,1.
    So glRotate also affects the normal!
    */
    glTranslatef(2.0f, 0.0f, 0.0f);
    glNormal3f(0.0, 0.0, 1.0);
    glRotatef(45.0, -1.0, 0.0, 0.0);
    draw_triangle();

    glPopMatrix();
    glFlush();
}

static void init(void) {
    GLfloat light0_diffuse[] = {1.0, 1.0, 1.0, 1.0};
    /* Plane wave coming from +z infinity. */
    GLfloat light0_position[] = {0.0, 0.0, 1.0, 0.0};
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glShadeModel(GL_SMOOTH);
    glLightfv(GL_LIGHT0, GL_POSITION, light0_position);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glColorMaterial(GL_FRONT, GL_DIFFUSE);
    glEnable(GL_COLOR_MATERIAL);
    glEnable(GL_NORMALIZE);
}

static void reshape(int w, int h) {
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-1.0, 7.0, -1.0, 1.0, -1.5, 1.5);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

int main(int argc, char** argv) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
    glutInitWindowSize(800, 200);
    glutInitWindowPosition(100, 100);
    glutCreateWindow(argv[0]);
    init();
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutMainLoop();
    return EXIT_SUCCESS;
}

सिद्धांत

OpenGL में प्रत्येक वर्टेक्स का अपना संबद्ध सामान्य वेक्टर होता है।

सामान्य वेक्टर यह निर्धारित करता है कि शीर्ष कितना उज्ज्वल है, जो तब यह निर्धारित करने के लिए उपयोग किया जाता है कि त्रिकोण कितना उज्ज्वल है।

जब एक सतह प्रकाश के लंबवत होती है, तो यह एक समानांतर सतह की तुलना में उज्जवल होती है।

glNormal वर्तमान सामान्य वेक्टर सेट करता है, जिसका उपयोग निम्नलिखित सभी शीर्षों के लिए किया जाता है।

हम सभी glNormalसे पहले सामान्य के लिए प्रारंभिक मूल्य 0,0,1

सामान्य वैक्टर में मानक 1 होना चाहिए , अन्यथा रंग बदल जाते हैं! glScaleभी मानदंडों की लंबाई बदल देता है! glEnable(GL_NORMALIZE);OpenGL स्वचालित रूप से हमारे लिए अपना आदर्श 1 पर सेट करता है। यह GIF उस खूबसूरती से दिखाता है।

ग्रंथ सूची:


अच्छा जवाब है, लेकिन एक पुराने सवाल और एक पुरानी तकनीक पर ध्यान केंद्रित क्यों कर रहे हैं?
वेलांचर्ट

@AlexandreVaillancourt धन्यवाद! पुराना सवाल: क्यों नहीं :-) पुरानी तकनीक: आज बेहतर तरीका क्या है?
सिरो सेंटिल्ली 新疆 改造 iro i 事件 '

मुझे लगता है कि आधुनिक OpenGL बफर वस्तुओं का उपयोग करने के बजाय glNormal निर्दिष्ट करता है।
वेलांचोर्ट

1
वास्तव में, glNormal और glVertex और जैसे कि आधुनिक OpenGL में चले गए हैं, और इससे कुछ समय पहले पदावनत कर दिए गए थे ... वे वास्तव में तब भी पदावनत थे जब यह प्रश्न मूल रूप से पूछा गया था।

0

आपको कुछ विशेषताओं को कोडर-निर्भर करने के लिए glNormal की आवश्यकता है। उदाहरण के लिए आप मानक किनारों को बनाए रखने के लिए कठोर किनारों को संरक्षित कर सकते हैं।


4
शायद आप अपने उत्तर को थोड़ा सुधारना चाहते हैं।
बार्टेक बैनवाक्विज़

1
यदि आप चाहते हैं कि मैं अपने उत्तर को सुधारूं तो आपको कमजोर स्थानों को इंगित करना होगा। मैं हालांकि इस पर विस्तार से बता सकता हूं। जैसा कि xblax सोचता था, प्रत्येक सामान्य "उसी तरह" गणना की जानी चाहिए। यहां तक ​​कि प्रत्येक पिक्सेल बनाम प्रत्येक चेहरे के लिए प्रक्षेपित मानदंडों के बीच अंतर के बावजूद। आइए विषय में थोड़ा और विस्तार करें।
एबी।

1
कभी-कभी आप हार्ड एज को बनाए रखने और इसे और अधिक विशिष्ट बनाने की इच्छा कर सकते हैं। यहाँ कुछ नमूना चित्र दिए गए हैं: titan.cs.ukzn.ac.za/opengl/opengl-d5/trant.sgi.com/opengl/… PS। डबल पोस्टिंग के लिए क्षमा करें। मैं एसई इंटरफ़ेस के लिए नया हूं
एबी।

"संपादित करें" बटन है।
बार्टेक बानचेविच 15

1
आप 5 मिनट के बाद संपादित नहीं कर सकते
AB।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.