OpenGL API 之 glTexEnv

1. 简介

glTexEnv用来设置纹理的环境参数,纹理环境参数主要控制纹理如何与片元颜色进行计算的。

2. 函数原型

void glTexEnvf( GLenum target,
    GLenum pname,
    GLfloat param);

void glTexEnvi( GLenum target,
    GLenum pname,
    GLint param);

 void glTexEnvfv(   GLenum target,
    GLenum pname,
    const GLfloat * params);

void glTexEnviv(    GLenum target,
    GLenum pname,
    const GLint * params);

该函数是一个函数簇,根据具体的参数类型来决定使用哪个版本的函数。
参数描述:
1. target:设置操作的目标,可以设置为GL_TEXTURE_ENV, GL_TEXTURE_FILTER_CONTROL 或者GL_POINT_SPRITE
2. pname:设置项
3. param:对panme设置项的值

3. 详细描述

  1. 当纹理环境中的target设置为GL_TEXTURE_FILTER_CONTROL的时候,pname的值必须设置为 GL_TEXTURE_LOD_BIAS,当设置pname是GL_TEXTURE_LOD_BIAS的时候,它的值是用来设置MipMap纹理层级选择公式的一个参数,具体可以参考 OpenGL API 之glTexParameter

  2. 当纹理环境中target设置为GL_TEXTURE_ENV,panme设置为GL_TEXTURE_ENV_MODE时候,对应的param的取值包括:

param取值含义
GL_ADD处理方式是片段颜色加上纹理采样的颜色
GL_MODULATE片段颜色与纹理采样颜色相乘
GL_DECAL见下图中的表
GL_BLEND两者相混合,参考下图中的表
GL_REPLACE纹理颜色完全取代片段颜色
GL_COMBINE参考后面的论述

纹理的格式(参考OpenGL图像格式 )包括有以下几种

纹理的基本格式颜色成分 Cs Alpha成分 As
GL_ALPHA(0, 0, 0, 0) At
GL_LUMINANCE( Lt , Lt , Lt )1
GL_LUMINANCE_ALPHA( Lt , Lt , Lt ) At
GL_INTENSITY( It , It , It ) It
GL_RGB( Rt , Gt , Bt )1
GL_RGBA( Rt , Gt , Bt ) At

我们先用一个程序感性的了解一下这些参数对于程序表现的影响:

#pragma comment(lib, "glew32.lib")
#pragma comment(lib, "freeglut.lib")
#pragma comment(lib, "soil.lib")

#include <stdio.h>
#include <gl/glew.h>
#include <gl/glut.h>
#include <iostream>
#include <gl/soil.h>

int windowWidth = 0;
int windowHeight = 0;

bool leftMouseDown = false;
float mouseX, mouseY;
float cameraAngleX, cameraAngleY;
float xRot, yRot;

GLuint texID;

void drawCube()
{
    glBindTexture(GL_TEXTURE_2D, texID);

    glBegin(GL_QUADS);
    glColor3f(1, 0, 0);
    glTexCoord2d(0.0, 0.0);
    glVertex3f(-1.0f, -1.0f, 1.0f);
    glTexCoord2d(1.0, 0.0);
    glVertex3f(1.0f, -1.0f, 1.0f);
    glTexCoord2d(1.0, 1.0);
    glVertex3f(1.0f, 1.0f, 1.0f);
    glTexCoord2d(0.0, 1.0);
    glVertex3f(-1.0f, 1.0f, 1.0f);
    glEnd();
}


void SetupRC()
{
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_TEXTURE_2D);

    int imageWidth, imageHeight;
    int channels;

    glGenTextures(1, &texID);
    glBindTexture(GL_TEXTURE_2D, texID);

    unsigned char* imageDataA = SOIL_load_image("../Data/a.png", &imageWidth, &imageHeight,
        &channels, SOIL_LOAD_AUTO);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, imageWidth, imageHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageDataA);

    unsigned char* imageDataB = SOIL_load_image("../Data/b.png", &imageWidth, &imageHeight,
        &channels, SOIL_LOAD_AUTO);
    glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, imageWidth, imageHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageDataB);

    unsigned char* imageDataC = SOIL_load_image("../Data/c.png", &imageWidth, &imageHeight,
        &channels, SOIL_LOAD_AUTO);
    glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA8, imageWidth, imageHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageDataC);

    unsigned char* imageDataD = SOIL_load_image("../Data/d.png", &imageWidth, &imageHeight,
        &channels, SOIL_LOAD_AUTO);
    glTexImage2D(GL_TEXTURE_2D, 3, GL_RGBA8, imageWidth, imageHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageDataD);

    unsigned char* imageDataE = SOIL_load_image("../Data/e.png", &imageWidth, &imageHeight,
        &channels, SOIL_LOAD_AUTO);
    glTexImage2D(GL_TEXTURE_2D, 4, GL_RGBA8, imageWidth, imageHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageDataE);

    //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 4);
    //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1);

    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 4);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 1);

    //如果注释掉这行代码,会导致纹理失败,这主要是因为GL_TEXTURE_MIN_FILTER使用的默认值是
    //GL_NEAREST_MIPMAP_LINEAR,但是代码中却没有设置MipMap,对于GL_TEXTURE_MAG_FILTER是否设置并不重要
    //因为GL_TEXTURE_MAG_FILTER默认的取值就是GL_LINEAR
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);


    ///
    ///测试glTexEnv函数的表现
    //GL_TEXTURE_ENV_MODE 取值:
    //1. GL_REPLACE
    //glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
    //2. GL_MODULATE(默认取值)
    //glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
    //3. GL_ADD
    //glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD);
    //4. GL_DECAL 
    //glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
    //5. GL_BLEND
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND);

    //设置与片段颜色进行混合的颜色
    //GLfloat blendColor[] = { 0.8, 0.5, 0.7, 0.5 };
    //glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, blendColor);

    SOIL_free_image_data(imageDataA);
    SOIL_free_image_data(imageDataB);
    SOIL_free_image_data(imageDataC);
    SOIL_free_image_data(imageDataD);
    SOIL_free_image_data(imageDataE);

    glBindTexture(GL_TEXTURE_2D, 0);
}

void RenderScene(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glLoadIdentity();
    glTranslated(0, 0, -5);
    glRotated(cameraAngleY*0.5, 1, 0, 0);
    glRotated(cameraAngleX*0.5, 0, 1, 0);
    drawCube();

    glutSwapBuffers();
}


void ChangeSize(int w, int h)
{
    windowWidth = w;
    windowHeight = h;

    if (h == 0)
        h = 1;
    glViewport(0, 0, w, h);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45.0, w*1.0 / h, 0.01, 1000.0f);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}


void MouseFuncCB(int button, int state, int x, int y)
{
    mouseX = x;
    mouseY = y;

    if (button == GLUT_LEFT_BUTTON)
    {
        if (state == GLUT_DOWN)
        {
            leftMouseDown = true;
        }
        else if (state == GLUT_UP)
        {
            leftMouseDown = false;
        }
    }

}

void MouseMotionFuncCB(int x, int y)
{
    if (leftMouseDown)
    {
        cameraAngleX += (x - mouseX);
        cameraAngleY += (y - mouseY);

        mouseX = x;
        mouseY = y;
    }

    glutPostRedisplay();
}


int main(int argc, char* argv[])
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
    glutInitWindowSize(800, 600);
    glutCreateWindow("OpenGL");
    glutReshapeFunc(ChangeSize);
    glutDisplayFunc(RenderScene);
    glutMouseFunc(MouseFuncCB);
    glutMotionFunc(MouseMotionFuncCB);

    GLenum err = glewInit();
    if (GLEW_OK != err) {
        fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
        return 1;
    }

    SetupRC();

    glutMainLoop();
    return 0;
}

GL_MODULATE(默认取值)
Modulate
GL_REPLACE
Replace
GL_ADD
ADD
GL_BLEND
BLEND
这些最终表现的颜色是怎么计算的呢?实际上计算的公式参考下表:
表中:【公式参数的简要说明:后缀是v表示最终输出的颜色(也就是我们上面看到的图片颜色),后缀是p表示是片段颜色(尚未应用纹理计算previous texture stage),后缀是s表示纹理图片的颜色(texture source color), 后缀是c表示我们需要通过GL_TEXTURE_ENV_COLOR设置的颜色, C表示颜色成分(RGB),A表示Alpha成分】

纹理格式最终颜色和Alpha成分结果GL_REPLACEGL_MODULATEGL_DECALGL_BLENDGL_ADD
GL_ALPHA Cv = Cp Cp 未定义 Cp Cp
Av = As As * Ap 未定义 As * Ap As * Ap
GL_LUMINANCE(或者1) Cv = Cs Cp * Cs 未定义 Cp(1Cs)+CcCs Cp+Cs
Av = Ap Ap 未定义 Ap Ap
GL_LUMINANCE_ALPHA(或者2) Cv = Cs Cp * Cs 未定义 Cp(1Cs)+CcCs Cp+Cs
Av = As As * Ap 未定义 As * Ap As * Ap
GL_INTENSITY Cv = Cs Cp * Cs 未定义 Cp(1Cs)+CcCs Cp+Cs
Av = As As * Ap 未定义 Ap(1As)+AcAs Ap+As
GL_RGB(或者3) Cv = Cs CpCs Cs Cp(1Cs)+CcCs Cp+Cs
Av = Ap Ap Ap Ap Ap
GL_RGBA(或者4) Cv = Cs CpCs Cp(1As)+CsAs Cp(1Cs)+CcCs C_p+C_s
Av = As ApAs Ap ApAs ApAs

除了上述对纹理进行的操作外,OpenGL还支持更加复杂的纹理颜色操作方式,这种操作方式成为 纹理组合器。具体的方式如下:

为了使用纹理组合器,需要调用:

glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);

接下来选择对颜色成分还是Alpha成分进行计算的算法选择,可以设置:

glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
或者是Alpha的操作:
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);

各种不同参数的含义
TCB

参数中的Arg0、Arg1和Arg2需要使用下面的方式来设置:
GL_SOURCEx_RGB,GL_SOURCEx_Alpha(x代表0,1,2),这些参数的取值如下:

取值含义
GL_TEXTURE当前活动的纹理单元
GL_TEXTUREx第x号纹理单元
GL_CONSTANT使用GL_TEXTURE_ENV_COLOR设置的颜色值
GL_PRIMARY_COLOR几何体片段的颜色
GL_PREVIOUS来自上一个纹理单元最后计算出的颜色

例如我们需要设置公式中Arg0代表的是第0号纹理,那么需要调用:

glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE0);

除此之外,还可以对操作数做一些修改,使用GL_OPERANDx_RGB和GL_OPERANDx_ALPHA(x是0,1,2)来修改操作数,修改的方式包括:

操作数修改方式含义
GL_SRC_COLOR颜色原RGB值
GL_ONE_MINUS_SRC_COLOR1减去颜色原RGB值
GL_SRC_ALPHA颜色原Alpha值
GL_ONE_MINUS_SRC_ALPHA1减去颜色原Alpha值

通过上面的组合,模拟 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD); 的效果:

    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
    glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_ADD);
    glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PRIMARY_COLOR);
    glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE);
    glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
    glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);

    glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
    glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PRIMARY_COLOR);
    glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE);
    glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
    glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);

上面这些内容简单点说就是通过设置一个等式的各个参数和操作符
glTex

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值