سؤال

لدي برنامج OpenGL قيد التشغيل، وهو يعرض الأشكال الهندسية، ولكنها كلها "مسطحة"، بلون رمادي واحد، بدون تظليل منتشر أو انعكاس مرآوي:

Tori with no shading

في الصورة ثلاثة توري، كل منها مصنوع من شرائح رباعية.يجب أن نرى التظليل، لكننا لا نفعل ذلك.ما الخطأ الذي افعله؟

هذا هو الكود الذي قمت بتعيين القمم والأعراف فيه (draw_torus() يتم استدعاؤه لإنشاء قائمة عرض):

/* WrapTorus, adapted from
    http://www.math.ucsd.edu/~sbuss/MathCG/OpenGLsoft/WrapTorus/WrapTorus.html
    by Sam Buss */

/*
 * Issue vertex command for segment number j of wrap number i.
 * Normal added by Lars Huttar.
 * slices1 = numWraps; slices2 = numPerWrap.
 */
void putVert(float i, float j, float slices1, float slices2, float majR, float minR) {
    float wrapFrac = j / slices2;
    /* phi is rotation about the circle of revolution */
    float phi = PI2 * wrapFrac;
    /* theta is rotation about the origin, in the xz plane. */
    float theta = PI2 * (i + wrapFrac) / slices1;
    float y = minR * (float)sin(phi);
    float r = majR + minR * (float)cos(phi);
    float x = (float)sin(theta) * r;
    float z = (float)cos(theta) * r;
    /* normal vector points to (x,y,z) from: */
    float xb = (float)sin(theta) * majR;
    float zb = (float)cos(theta) * majR;
    glNormal3f(x - xb, y, z - zb);
    glVertex3f(x, y, z);
}

static void draw_torus(int numPerWrap, int numWraps, float majR, float minR) {
    int i, j;
    glBegin( GL_QUAD_STRIP );
    for (i=0; i < numWraps; i++ ) {
        for (j=0; j < numPerWrap; j++) {
            putVert((float)i, (float)j, (float)numWraps, (float)numPerWrap, majR, minR);
            putVert((float)(i + 1), (float)j, (float)numWraps, (float)numPerWrap, majR, minR);
        }
    }
    putVert(0.0, 0.0, (float)numWraps, (float)numPerWrap, majR, minR);
    putVert(1.0, 0.0, (float)numWraps, (float)numPerWrap, majR, minR);
    glEnd();
}

هل هناك خطأ في ترتيب القمم؟

فيما يلي جزء من وظيفة init حيث تم إنشاء قائمة العرض:

GLfloat white[4] = { 1.0, 1.0, 1.0, 1.0 };
    GLfloat color[4] = { 0.5, 0.6, 0.7, 1.0 };
    ...

glShadeModel(GL_SMOOTH);

torusDL = glGenLists (1);
glNewList(torusDL, GL_COMPILE);
setMaterial(color, white, 100);
draw_torus(8, 45, 1.0, 0.05);
glEndList();

حيث يقوم setMaterial() فقط بما يلي:

static void setMaterial(const GLfloat color[3], const GLfloat hlite[3], int shininess) {
    glColor3fv(color);
    glMaterialfv(GL_FRONT, GL_SPECULAR, hlite);
    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color);
    glMateriali(GL_FRONT, GL_SHININESS, shininess); /* [0,128] */
}

إليك الإضاءة التي يتم إجراؤها أيضًا أثناء التهيئة:

  GLfloat pos[4] = {0.4, 0.2, 0.4, 0.0};
  GLfloat amb[4] = {0.2, 0.2, 0.2, 1.0};
  GLfloat dif[4] = {1.0, 1.0, 1.0, 1.0};
  GLfloat spc[4] = {1.0, 1.0, 1.0, 1.0};
  GLfloat color[4] = {0.20, 0.20, 0.20, 1.00};
  GLfloat spec[4]  = {0.30, 0.30, 0.30, 1.00};
  GLfloat shiny    = 8.0;

  glEnable(GL_LIGHTING);
  glEnable(GL_LIGHT0);
  glEnable(GL_DEPTH_TEST);
  glEnable(GL_CULL_FACE);

  glLightfv(GL_LIGHT0, GL_POSITION, pos);
  glLightfv(GL_LIGHT0, GL_AMBIENT,  amb);
  glLightfv(GL_LIGHT0, GL_DIFFUSE,  dif);
  glLightfv(GL_LIGHT0, GL_SPECULAR, spc);

  glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
  glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR,            spec);
  glMaterialf  (GL_FRONT_AND_BACK, GL_SHININESS,           shiny);

هنا يتم استدعاء قائمة العرض، في وظيفة السحب:

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glPushMatrix();
glLoadIdentity();       

glScalef(3.5, 3.5, 3.5);

for (i = 0; i < ac->nrings; i++) {
    glScalef(0.8, 0.8, 0.8);
    glRotatef(...);
    glCallList(torusDL);
}

glFlush();
glPopMatrix();
glXSwapBuffers(dpy, window);

الملف المصدر .c الكامل لهذا "glx hack" هو هنا.في حالة حدوث فرق، هذا الرمز موجود في سياق xscreensaver.

هل كانت مفيدة؟

المحلول

لارس، كما رأيت، glEnable(GL_NORMALIZE) يقوم بتطبيع (مفاجأة) المتجهات العادية قبل التحويلات المستخدمة في حسابات الإضاءة (في خطوط الأنابيب ذات الوظيفة الثابتة).تعتمد هذه الحسابات على معايير طول الوحدة للحصول على النتائج الصحيحة.

تجدر الإشارة إلى أن التحويلات المطبقة على المتجهات العادية هي لا نفس التحويلات المطبقة على هندسة الرأس.تصف مواصفات OpenGL 2.1 التحويل، كما يفعل الكثير آخر موارد.باعتباره متجهًا، يكون للطبيعي تمثيل متجانس: [nx, ny, nz, 0] - نقطة عند "اللانهاية"، وطريقة أنيقة رياضيًا لتوحيد عمليات المصفوفة والمتجهات الأربعة في خط أنابيب GL.

بالطبع، يمكنك إجراء هذه التسوية بنفسك، وقد يكون القيام بذلك أكثر كفاءة، حيث يتم إنشاء هندسة الحيد الخاصة بك مرة واحدة فقط لقائمة العرض المترجمة مسبقًا:

nx = x - b, ny = y, nz = z - zb;
nl = 1.0f / sqrtf(nx * nx + ny * ny + nz * nz);
glNormal3f(nx * nl, ny * nl, nz * nl);

تأكد من (nl) للقسمة على صفر (أو بعض إبسيلون)، إذا كان هذا احتمالًا.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top