Сенки чрез карти на сенки и други текстури - как да комбинирате? OpenGL

Добър ден. Рисувам сцена със сенки, като използвам метода на картите на сенките (когато изобразяваме сцена от гледна точка на светлината, за да извлечем буфер за дълбочина, създавайки текстура на сянка и я проектирам върху сцената, изобразена от гледна точка на камерата) Тъй като използвам текстура на карта на сенките , всички други текстурирани обекти, разбира се, губят своята текстура. Но аз наистина искам текстурирана сцена със сенки:) Четох за мултитекстуриране, всъщност се опитах да го приложа, но не успях. Какво точно трябва да направя? (Взех код от OpenGl superbible) Ето кода на основната процедура за настройка. Маркирах нови низове (тези за мултитекстуриране) с //‹====

    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);
}

Процедура за генериране на текстура C2DTexture:

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);
}

person Irene    schedule 27.11.2009    source източник


Отговори (1)


Опитахте ли да приложите мултитекстуриране? Не се показва във вашия код. Трябва да го използвате. Една текстурна единица за текстурата на сянка, една за вашата дифузна карта. Ако сте опитали, трябва да покажете кода с мулти-текстуриране.

Мултитекстурирането се обработва чрез 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 резултатът от извличането на дифузна текстура.

Резултатът, който ще получите с активирани 2 текстурни единици, е нещо подобно

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

Резултатът, който вие искате, е вероятно

C_o = C_f * T_s * T_d

Какво ни казва това?

  • за да приложите умноженията, искате да модулирате като вашия TexEnv както за текстурна единица 0, така и за текстурна единица 1
  • редът няма значение в този случай (това е така, защото умножението -известно още като модулация- е комутативно)
  • това, което показах, е почти шейдър код. Много по-лесно за четене от настройките на TexEnv.

Сега да се върна към вашия проблем... На този етап се надявам да разберете кое състояние на OpenGL трябваше да изтеглите. Опитът да разберете какво точно състояние всъщност имате от четенето на вашия код обаче е опасно упражнение в най-добрия случай. Ако сте сериозни относно използването на OpenGL, препоръчвам едно от следните:

  • използвайте OpenGL дебъгер. Има редица инструменти, които ще покажат точното състояние при конкретен разговор за теглене.
  • изградете свое собствено проследяване на състоянието на отстраняване на грешки
  • изхвърлете интересуващото състояние на OpenGL към момента на тегленето. OpenGL предоставя getter методи за всяка частица от своето състояние (или почти, няма да навлизам в най-мръсните подробности тук), Вие искате да направите това само за целите на отстраняването на грешки, Getters не е гарантирано, че са ефективни изобщо).
person Bahbar    schedule 27.11.2009
comment
››Опитахте ли да приложите мултитекстуриране? Не се показва във вашия код. Да, опитах, не успях и го премахнах:) Трябваше да знам това: ››искате да картографирате текстурата на дълбочина към текстурния модул 1: настройката на текстурния модул за картографиране на сенки трябва да бъде предшествана от glActiveTexture (GL_TEXTURE1) -- BindTexture, TexGen и свързаното с текстурирането Enable/Disable. Разбира се, трябва да превключите обратно към текстурна единица 0, за останалото ще опитам отново, използвайки вашия съвет, и след това ще кажа дали работи :) - person Irene; 27.11.2009
comment
››По-бързо е да рисувате директно върху текстурата с разширението framebuffer_object, отколкото да копирате към нея Благодаря! ще опитам - person Irene; 27.11.2009
comment
И имам още един въпрос: една текстурна единица за една текстура ли е? Или мога да обвържа повече текстури, както винаги, в рамките на един текущ слой? - person Irene; 27.11.2009
comment
И какво трябва да нанеса първо - текстура на сенките или моята текстура? - person Irene; 27.11.2009
comment
Опитах се да направя мултитекстуриране. Сенките работят, но текстурата ми не се появи. Маркирах нови низове (тези за мултитекстуриране) с //‹==== PS: И сега моите сплайн повърхности не работят:( glGetError връща GL_INVALID_OPERATION след gluEndSurface. - person Irene; 28.11.2009
comment
Благодаря ти, Бахбар! Активирах текстурирането за unit0 във функцията RenderScene и добавих там glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); низ, но все още не работи. Страхувам се, че не мога да копая толкова дълбоко като програмиране на шейдъри, имам ограничено време за този проект и той всъщност почти изчезна:(( Това е университетски проект, но нямам планове да бъда OpenGL програмист, след като дипломиран. Може би има друго решение? Освен шейдъри - person Irene; 29.11.2009
comment
Стартирайте OpenGL дебъгер. Това ще ви каже точно в какво състояние е GL и ако разберете какво трябва да имате, ще знаете какво точно сте пропуснали. - person Bahbar; 29.11.2009
comment
Можете ли да посъветвате някакъв OpenGL дебъгер? - person Irene; 29.11.2009
comment
Чувал съм добри неща за gDEBugger. Има 7-дневен пробен период. - person Bahbar; 30.11.2009