【问题标题】:Shadows via shadowmaps and other textures - how to combine? OpenGL通过阴影贴图和其他纹理的阴影 - 如何组合? OpenGL
【发布时间】:2009-11-27 18:11:10
【问题描述】:

美好的一天。 我使用阴影贴图方法绘制带有阴影的场景(当我们从光的角度渲染场景以检索深度缓冲区,制作阴影纹理并将其投影到场景上,从相机的角度渲染时) 当我使用阴影贴图纹理时,所有其他纹理对象当然会失去它们的纹理。 但我真的想要有阴影的纹理场景:) 我读到了多纹理,我实际上尝试应用它,但失败了。 我究竟应该怎么做? (我从 OpenGl 的超棒中获取了代码) 这是主要设置过程的代码。我用 // 标记了新字符串(用于多重纹理的字符串)

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

【问题讨论】:

    标签: opengl shadows multitexturing texturing


    【解决方案1】:

    您尝试应用多重纹理?它没有显示在您的代码中。你确实需要使用它。一个用于阴影纹理的纹理单元,一个用于您的漫反射贴图。如果你尝试过,你应该用多纹理显示代码。

    多纹理通过glActiveTexture 处理(对于您似乎正在使用的固定功能,glClientActiveTexture 来处理纹理坐标规范)。

    一些建议:

    • 如果您使用着色器,更容易准确理解您在做什么。
    • 您想要将深度纹理映射到纹理单元 1:阴影映射的纹理单元的设置需要在前面加上 glActiveTexture(GL_TEXTURE1) -- BindTexture、TexGen 和纹理相关的启用/禁用。当然,剩下的就需要切换回纹理单元 0 了。
    • 绘制深度图时不需要任何纹理。
    • 使用 framebuffer_object 扩展名直接绘制到纹理比复制到它更快

    希望这会有所帮助。

    编辑:既然你已经改变了很多你的问题,让我为你的 cmets 添加一些建议和答案:

    单个纹理单元将始终从单个纹理对象中获取。您使用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
    

    这告诉我们什么?

    • 要实现乘法,您需要调制为纹理单元 0 和纹理单元 1 的 TexEnv
    • 顺序在这种情况下并不重要(这是因为乘法 - 也就是调制 - 是可交换的)
    • 我展示的几乎是着色器代码。比 TexEnv 设置更容易阅读。

    现在回到您的问题... 在这一点上,我希望您了解您应该在绘制时间时应该什么 OpenGL 状态。然而,试图通过阅读代码来确切地了解您实际拥有的状态充其量是一项危险的练习。如果您对使用 OpenGL 很认真,我建议您使用以下任一方法:

    • 使用 OpenGL 调试器。有许多工具可以显示特定绘图调用的确切状态。
    • 构建您自己的调试状态跟踪
    • 在绘制时转储感兴趣的 OpenGL 状态。 OpenGL 为其状态的每一个比特都提供了 getter 方法(或者几乎,我不会在这里讨论最肮脏的细节),您只想出于调试目的这样做,根本不能保证 Getter 是有效的)。

    【讨论】:

    • >>您尝试应用多重纹理?它没有显示在您的代码中。是的,我试过了,我失败了,我删除了它:) 我必须知道:>>你想将深度纹理映射到纹理单元 1:阴影映射的纹理单元的设置需要在 glActiveTexture 之前(GL_TEXTURE1) -- BindTexture、TexGen 和纹理相关的启用/禁用。当然,剩下的你需要切换回纹理单元 0 我会根据你的建议再试一次,然后告诉它是否有效:)
    • >>直接绘制到带有 framebuffer_object 扩展名的纹理比复制到它要快 谢谢!我会试试的
    • 我还有一个问题:一个纹理单元对应一个纹理吗?或者我可以像往常一样在一个当前图层中绑定更多纹理?
    • 我应该先应用什么 - 阴影纹理还是我的纹理?
    • 我尝试制作多重纹理。阴影正在起作用,但我的纹理没有出现。我用 //
    猜你喜欢
    • 2013-04-21
    • 1970-01-01
    • 2018-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多