Тени через карты теней и другие текстуры - как их объединить? OpenGL - PullRequest
0 голосов
/ 27 ноября 2009

Добрый день. Я рисую сцену с тенями, используя метод карты теней (когда мы визуализируем сцену с легкой точки зрения, чтобы получить буфер глубины, создаем текстуру тени и проецируем ее на сцену, визуализированную с точки зрения камеры) Поскольку я использую текстуру карты теней, все другие текстурированные объекты, конечно, теряют свое текстурирование. Но я действительно хочу текстурированную сцену с тенями :) Я читал о мультитекстурировании, я действительно пытался применить его, но не получилось. Что именно я должен делать? (Я взял код из OpenGL Superbible) Вот основной код процедуры установки. Я пометил новые строки (для мультитекстурирования) с помощью // <==== </p>

    void SetupRC()
{

        ambientShadowAvailable = GL_TRUE;


        npotTexturesAvailable = GL_TRUE;



    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize);

    fprintf(stdout, "Controls:\n");
    fprintf(stdout, "\tRight-click for menu\n\n");
    fprintf(stdout, "\tx/X\t\tMove +/- in x direction\n");
    fprintf(stdout, "\ty/Y\t\tMove +/- in y direction\n");
    fprintf(stdout, "\tz/Z\t\tMove +/- in z direction\n\n");
    fprintf(stdout, "\tf/F\t\tChange polygon offset factor +/-\n\n");
    fprintf(stdout, "\tq\t\tExit demo\n\n");

    // Black background
    glClearColor(0.32f, 0.44f, 0.85f, 0.5f );

    // Hidden surface removal
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);
    glPolygonOffset(factor, 0.0f);

    // Set up some lighting state that never changes
    glShadeModel(GL_SMOOTH);
    glEnable(GL_LIGHTING);
    glEnable(GL_COLOR_MATERIAL);
    glEnable(GL_NORMALIZE);
    glEnable(GL_LIGHT0);

    // Set up some texture state that never changes
    glActiveTexture(GL_TEXTURE1); //<=====

    glGenTextures(1, &shadowTextureID);
    glBindTexture(GL_TEXTURE_2D, shadowTextureID);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY);
   // if (ambientShadowAvailable)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FAIL_VALUE_ARB, 
                        0.5f);
    glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
    glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
    glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
    glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
    ::scene->fog->init();
    RegenerateShadowMap();
}

Вот процедура генерации карты теней:

        void RegenerateShadowMap(void)
    {
        GLfloat lightToSceneDistance, nearPlane, fieldOfView;
        GLfloat lightModelview[16], lightProjection[16];
        GLfloat sceneBoundingRadius = 200.0f; // based on objects in scene

        // Save the depth precision for where it's useful
        lightToSceneDistance = sqrt(lightPos[0] * lightPos[0] + 
                                    lightPos[1] * lightPos[1] + 
                                    lightPos[2] * lightPos[2]);
        nearPlane = lightToSceneDistance - sceneBoundingRadius;
        // Keep the scene filling the depth texture
        fieldOfView = (GLfloat)m3dRadToDeg(2.0f * atan(sceneBoundingRadius / lightToSceneDistance));

        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluPerspective(fieldOfView, 1.0f, nearPlane, nearPlane + (2.0f * sceneBoundingRadius));
        glGetFloatv(GL_PROJECTION_MATRIX, lightProjection);
        // Switch to light's point of view
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        gluLookAt(lightPos[0], lightPos[1], lightPos[2], 
                  0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);
        glGetFloatv(GL_MODELVIEW_MATRIX, lightModelview);
        glViewport(0, 0, shadowWidth, shadowHeight);

        // Clear the depth buffer only
        glClear(GL_DEPTH_BUFFER_BIT);

        // All we care about here is resulting depth values
        glShadeModel(GL_FLAT);
        glDisable(GL_LIGHTING);
        glDisable(GL_COLOR_MATERIAL);
        glDisable(GL_NORMALIZE);
        glActiveTexture(GL_TEXTURE0); //<=====
        glDisable(GL_TEXTURE_2D);
        glActiveTexture(GL_TEXTURE1); //<=====
        glColorMask(0, 0, 0, 0);

        // Overcome imprecision
        glEnable(GL_POLYGON_OFFSET_FILL);

        // Draw objects in the scene except base plane
        // which never shadows anything
        DrawModels(GL_FALSE);

        // Copy depth values into depth texture
        glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 
                         0, 0, shadowWidth, shadowHeight, 0);

        // Restore normal drawing state
        glShadeModel(GL_SMOOTH);
        glEnable(GL_LIGHTING);
        glEnable(GL_COLOR_MATERIAL);
        glEnable(GL_NORMALIZE);
        glActiveTexture(GL_TEXTURE0); //<=====
        glEnable(GL_TEXTURE_2D);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
        glColorMask(1, 1, 1, 1);
        glDisable(GL_POLYGON_OFFSET_FILL);

        // Set up texture matrix for shadow map projection,
        // which will be rolled into the eye linear
        // texture coordinate generation plane equations
        M3DMatrix44f tempMatrix;
        m3dLoadIdentity44(tempMatrix);
        m3dTranslateMatrix44(tempMatrix, 0.5f, 0.5f, 0.5f);
        m3dScaleMatrix44(tempMatrix, 0.5f, 0.5f, 0.5f);
        m3dMatrixMultiply44(textureMatrix, tempMatrix, lightProjection);
        m3dMatrixMultiply44(tempMatrix, textureMatrix, lightModelview);
        // transpose to get the s, t, r, and q rows for plane equations
        m3dTransposeMatrix44(textureMatrix, tempMatrix);

    }

Процедура рендеринга сцены:

    void RenderScene(void)
{
    // Track camera angle
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    if (windowWidth > windowHeight)
    {
        GLdouble ar = (GLdouble)windowWidth / (GLdouble)windowHeight;
        glFrustum(-ar * cameraZoom, ar * cameraZoom, -cameraZoom, cameraZoom, 1.0, 1000.0);
    }
    else
    {
        GLdouble ar = (GLdouble)windowHeight / (GLdouble)windowWidth;
        glFrustum(-cameraZoom, cameraZoom, -ar * cameraZoom, ar * cameraZoom, 1.0, 1000.0);
    }

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(cameraPos[0], cameraPos[1], cameraPos[2], 
              0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);

    glViewport(0, 0, windowWidth, windowHeight);

    // Track light position
    glLightfv(GL_LIGHT0, GL_POSITION, lightPos);

    // Clear the window with current clearing color
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    if (showShadowMap)
    {
        // Display shadow map for educational purposes
        glActiveTexture(GL_TEXTURE1); //<=====
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glMatrixMode(GL_TEXTURE);
        glPushMatrix();
        glLoadIdentity();
        glEnable(GL_TEXTURE_2D);
        glDisable(GL_LIGHTING);
        glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
        // Show the shadowMap at its actual size relative to window
        glBegin(GL_QUADS);
            glTexCoord2f(0.0f, 0.0f);
            glVertex2f(-1.0f, -1.0f);
            glTexCoord2f(1.0f, 0.0f);
            glVertex2f(((GLfloat)shadowWidth/(GLfloat)windowWidth)*2.0f-1.0f, 
                       -1.0f);
            glTexCoord2f(1.0f, 1.0f);
            glVertex2f(((GLfloat)shadowWidth/(GLfloat)windowWidth)*2.0f-1.0f, 
                       ((GLfloat)shadowHeight/(GLfloat)windowHeight)*2.0f-1.0f);
            glTexCoord2f(0.0f, 1.0f);
            glVertex2f(-1.0f, 
                       ((GLfloat)shadowHeight/(GLfloat)windowHeight)*2.0f-1.0f);
        glEnd();
        glDisable(GL_TEXTURE_2D);
        glEnable(GL_LIGHTING);
        glPopMatrix();
        glMatrixMode(GL_PROJECTION);
        gluPerspective(45.0f, 1.0f, 1.0f, 1000.0f);
        glMatrixMode(GL_MODELVIEW);
    }
    else if (noShadows)
    {
        // Set up some simple lighting
        glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight);
        glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight);

        // Draw objects in the scene including base plane
        DrawModels(GL_TRUE);
    }
    else
    {
        if (!ambientShadowAvailable)
        {
            GLfloat lowAmbient[4] = {0.1f, 0.1f, 0.1f, 1.0f};
            GLfloat lowDiffuse[4] = {0.35f, 0.35f, 0.35f, 1.0f};

            // Because there is no support for an "ambient"
            // shadow compare fail value, we'll have to
            // draw an ambient pass first...
            glLightfv(GL_LIGHT0, GL_AMBIENT, lowAmbient);
            glLightfv(GL_LIGHT0, GL_DIFFUSE, lowDiffuse);

            // Draw objects in the scene, including base plane
            DrawModels(GL_TRUE);

            // Enable alpha test so that shadowed fragments are discarded
            glAlphaFunc(GL_GREATER, 0.9f);
            glEnable(GL_ALPHA_TEST);
        }
        glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight);
        glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight);

        // Set up shadow comparison
        glActiveTexture(GL_TEXTURE1); //<=====
        glEnable(GL_TEXTURE_2D);
        glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, 
                        GL_COMPARE_R_TO_TEXTURE);

        // Set up the eye plane for projecting the shadow map on the scene
        glEnable(GL_TEXTURE_GEN_S);
        glEnable(GL_TEXTURE_GEN_T);
        glEnable(GL_TEXTURE_GEN_R);
        glEnable(GL_TEXTURE_GEN_Q);
        glTexGenfv(GL_S, GL_EYE_PLANE, &textureMatrix[0]);
        glTexGenfv(GL_T, GL_EYE_PLANE, &textureMatrix[4]);
        glTexGenfv(GL_R, GL_EYE_PLANE, &textureMatrix[8]);
        glTexGenfv(GL_Q, GL_EYE_PLANE, &textureMatrix[12]);

        // Draw objects in the scene, including base plane
        DrawModels(GL_TRUE);
        //glPushMatrix();
        //glScalef(1, -1, 1);
        //DrawModels(GL_TRUE);
        //glPopMatrix();
        glDisable(GL_ALPHA_TEST);
        glDisable(GL_TEXTURE_2D);
        glDisable(GL_TEXTURE_GEN_S);
        glDisable(GL_TEXTURE_GEN_T);
        glDisable(GL_TEXTURE_GEN_R);
        glDisable(GL_TEXTURE_GEN_Q);
    }

    if (glGetError() != GL_NO_ERROR)
        fprintf(stderr, "GL Error!\n");
    //glBindTexture
    // Flush drawing commands
    glutSwapBuffers();
    //RegenerateShadowMap();

}

И пример рисования текстурированного объекта:

   CTeapot::CTeapot(std::string fn, float s, float iX, float iY, float iZ)
{
    this->setCoords(iX, iY, iZ);
    this->size = s;
    glActiveTexture(GL_TEXTURE0); //<=====
    try
    {
    this->texture = new C2DTexture(fn);
    }
    catch(ERR::CError err)
    {
        throw err;
    }   
    glActiveTexture(GL_TEXTURE1); //<=====
}

void CTeapot::draw()
{
    glPushMatrix();
    glTranslatef(this->coords[0], this->coords[1], this->coords[2]);
    if(this->angle[0] != 0.0f)
        glRotatef(this->angle[0], 1.0f, 0.0f, 0.0f);
    if(this->angle[1] != 0.0f)
        glRotatef(this->angle[1], 0.0f, 1.0f, 0.0f);
    if(this->angle[2] != 0.0f)
        glRotatef(this->angle[2], 0.0f, 0.0f, 1.0f);
    glScalef(this->size, this->size, this->size);
    glActiveTexture(GL_TEXTURE0); //<=====
    //glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, this->texture->getGLTexture());
    glutSolidTeapot(this->size);
    glPopMatrix();
    glActiveTexture(GL_TEXTURE1); //<=====
    //glEnable(GL_TEXTURE_2D);
}

C2D Текстура генерации proc:

C2DTexture::C2DTexture(std::string fn)
{
    this->filename = fn;
    this->imgTexture = auxDIBImageLoad(this->filename.c_str());
    if(this->imgTexture == NULL)
        throw ERR::CError(ERR::ERR_NOSUCHFILE, ERR::ERR_NOSUCHFILETEXT + this->filename);
    // Creating a texture
    glGenTextures(1, &this->glTexture);
    glBindTexture(GL_TEXTURE_2D, this->glTexture);
    // Setting filters
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 0, 3, this->imgTexture->sizeX, this->imgTexture->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, this->imgTexture->data);
}

1 Ответ

3 голосов
/ 27 ноября 2009

Вы пытались применить мультитекстурирование? Это не отображается в вашем коде. Вы должны использовать это. Один текстурный блок для теневой текстуры, другой для вашей диффузной карты. Если вы пытались, вы должны показать код с мультитекстурированием.

Мульти-текстурирование обрабатывается с помощью glActiveTexture (и для фиксированной функции, которую вы, похоже, используете, glClientActiveTexture для обработки спецификаций координат текстуры).

Несколько советов:

  • легче понять, что именно вы делаете, если используете шейдеры.
  • Вы хотите отобразить текстуру глубины на текстурный блок 1: настройке текстурного блока для отображения теней должен предшествовать glActiveTexture(GL_TEXTURE1) - BindTexture, TexGen и текстурирование, связанные с Enable / Disable. Конечно, вам нужно вернуться к текстурному блоку 0 для остальных.
  • вам не нужно текстурирование при рисовании на карту глубины.
  • Быстрее рисовать непосредственно на текстуру с расширением framebuffer_object, чем копировать в нее

Надеюсь, это поможет.

Редактировать: Поскольку вы немного изменили свой вопрос, позвольте мне добавить несколько советов и ответов к вашим комментариям:

Одна единица текстуры всегда будет извлекать из одного объекта текстуры. Вы используете glActiveTexture, а затем glBindTexture, чтобы указать, какая текстура будет извлечена из этого текстурного блока. Обратите внимание, что для того, чтобы получить какое-либо текстурирование на этом блоке, вам все равно нужно позвонить glEnable(GL_TEXTURE_2D) для этого блока.

Что применять в первую очередь ... Хорошо, именно здесь использование шейдеров значительно упрощает обсуждение. В общем, порядок применения полностью зависит от того, какой фрагмент математики вы хотите получить. Поставим следующую номенклатуру:

  • T_0 результат первой выборки текстуры,
  • T_1 результат второй выборки текстуры.
  • C_f Цвет ввода, который OpenGL вычислил и растеризовал для этого фрагмента (Вы используете фиксированную функцию освещения, это то, о чем я говорю)
  • C_o Окончательный цвет фрагмента
  • T_s результат выборки текстуры тени,
  • T_d результат выборки диффузной текстуры.

Результат, с двумя включенными текстурными единицами, будет примерно таким:

C_o = TexEnv1(TexEnv0(C_f,T_0), T_1)

Результат Вы хотите, скорее всего

C_o = C_f * T_s * T_d

Что это говорит нам?

  • чтобы реализовать умножения, вы хотите модулировать в качестве TexEnv как для блока текстуры 0, так и для блока текстуры 1
  • порядок в данном случае не имеет значения (это потому, что умножение -aka модуляция- коммутативно)
  • то, что я показал, это в значительной степени шейдерный код. Намного легче читать, чем настройки TexEnv.

Теперь вернемся к вашей проблеме ... На данный момент, я надеюсь, вы понимаете, что OpenGL заявляет, что вы должны настало время розыгрыша. Однако попытка точно узнать, в каком состоянии вы находитесь на самом деле, читая ваш код, в лучшем случае является опасным упражнением. Если вы серьезно относитесь к использованию OpenGL, я рекомендую одно из следующего:

  • использовать отладчик OpenGL. Существует целый ряд инструментов, которые показывают точное состояние при конкретном вызове отрисовки.
  • создание собственного отслеживания состояния отладки
  • сбросить состояние интереса OpenGL во время розыгрыша. OpenGL предоставляет методы получения для каждого бита его состояния (или почти, я не буду вдаваться в самые грязные подробности здесь), вы хотите делать это только в целях отладки, Getters не гарантированно эффективны вообще).
...