1

OpenGL と Cg シェーダー言語を使用して環境マッピングを実装するプログラムを作成します。しかし、結果はあまり正しくありません。モデルの色を計算するときに、反射をデカール テクスチャとブレンドします。反射率と呼ばれる均一なパラメーターにより、アプリケーションはマテリアルの反射率を制御します。

まず、フラグメント Cg コードをリストします。

void main_f(float2 texCoord : TEXCOORD0,
    float3 R : TEXCOORD1,

    out float4 color : COLOR,

    uniform float reflectivity,
    uniform sampler2D decalMap,
    uniform samplerCUBE environmentMap)
{
//fetch reflected environment color
float3 reflectedColor = texCUBE(environmentMap,R);

//fetch the decal base coloe
float3 decalColor = tex2D(decalMap,texCoord);
color.xyz = lerp(reflectedColor,decalColor,reflectivity);//change !!!!!!!!
color.w = 1;
}

均一パラメータの反射率を 0.6 に設定しました。結果は次のとおりです。 ここに画像の説明を入力

ご覧のとおり、デカール テクスチャからの色情報は失われています。環境キューブ テクスチャからの色情報しかありません。また、反射率を 0 に設定すると、モデルは暗くなります。しかし、フラグメント cg コードの color.xyz を次のように変更すると:

color.xyz = decalColor;

私は正しい結果を得ることができます(デカールテクスチャからの色のみがあります): ここに画像の説明を入力

そして、フラグメント cg コードの color.xyz を次のように変更すると:

color.xyz = reflectedColor;

私も正しい結果を得ることができます(環境キューブテクスチャからの色のみがあります): ここに画像の説明を入力

そして、私の質問は次のとおりです。デカール テクスチャの色情報を Cg 関数lerpを使用して環境キューブ テクスチャの色情報とブレンドすると、なぜ機能しないのですか?

最後に、cg 頂点シェーダーと cpp ファイルをリストします: vertex.cg:

void main_v(float4 position : POSITION,
                float2 texCoord : TEXCOORD0,//decal texture
                float3 normal : NORMAL,

                out float4 oPosition : POSITION,
                out float2 oTexCoord : TEXCOORD0,//out decal texture
                out float3 R : TEXCOORD1,//reflective vector

                uniform float3 eyePositionW,//eye position in world space
                uniform float4x4 modelViewProj,
                uniform float4x4 modelToWorld
                )
{
        modelViewProj = glstate.matrix.mvp;
        oPosition = mul(modelViewProj,position);        
        oTexCoord = texCoord;

        float3 positionW = mul(modelToWorld,position).xyz;
        float3 N = mul((float3x3)modelToWorld,normal);
        N = normalize(N);

        float3 I = positionW - eyePositionW;//incident vector
        R = reflect(I,N);
}

main.cpp:

#pragma comment(lib,"glew32.lib")
#pragma comment(lib,"GLAUX.LIB")
#pragma comment(lib,"cg.lib")
#pragma comment(lib,"cgGL.lib")

#include <GL/glew.h>
#include <GL/glut.h>
#include <GL/glaux.h>
#include <CG/cg.h>
#include <CG/cgGL.h>
#include "MonkeyHead.h"
#include <iostream>
#include <cmath>

using namespace std;

int loop;
/* Use enum to assign unique symbolic OpenGL texture names. */
enum {
    TO_BOGUS = 0,
    TO_DECAL,
    TO_ENVIRONMENT,
};
const double myPi = 3.14159;
//for Cg shader
static CGcontext myCgContext;
static CGprofile myCgVertexProfile,myCgFragmentProfile;
static CGprogram myCgVertexProgram,myCgFragmentProgram;
static const char *myProgramName = "CgTest18CubeMapReflective",
                        *myVertexProgramFileName = "vertex.cg",
                        *myVertexProgramName = "main_v",
                        *myFragmentProgramFileName = "fragment.cg",
                        *myFragmentProgramName = "main_f";
static CGparameter myCgVertexParam_modelToWorld;

//bmp files for cube map
const char *bmpFile[6] = {"Data/1.bmp","Data/2.bmp","Data/3.bmp",
                                        "Data/4.bmp","Data/5.bmp","Data/6.bmp"};
const char *decalBmpFile = "Data/decal.bmp";
static float eyeAngle = 0.53;
static float eyeHeight = 0.0f;
static float headSpain = 0.0f;
static const GLfloat vertex[4*6][3] = {
    /* Positive X face. */
    { 1, -1, -1 },  { 1, 1, -1 },  { 1, 1, 1 },  { 1, -1, 1 },
    /* Negative X face. */
    { -1, -1, -1 },  { -1, 1, -1 },  { -1, 1, 1 },  { -1, -1, 1 },
    /* Positive Y face. */
    { -1, 1, -1 },  { 1, 1, -1 },  { 1, 1, 1 },  { -1, 1, 1 },
    /* Negative Y face. */
    { -1, -1, -1 },  { 1, -1, -1 },  { 1, -1, 1 },  { -1, -1, 1 },
    /* Positive Z face. */
    { -1, -1, 1 },  { 1, -1, 1 },  { 1, 1, 1 },  { -1, 1, 1 },
    /* Negative Z face. */
    { -1, -1, -1 },  { 1, -1, -1 },  { 1, 1, -1 },  { -1, 1, -1 },
};
static float reflectivity = 0.6;
GLuint decalTexture;
bool animating = false;//enable animating or not

static void drawMonkeyHead()
{
    static GLfloat *texCoords = NULL;
    const int numVertices = sizeof(MonkeyHead_vertices)
        / (3 * sizeof(MonkeyHead_vertices[0]));
    const float scaleFactor = 1.5;
    //generate texcoords
    texCoords = (GLfloat*)malloc(2 * numVertices * sizeof(GLfloat));
    if (!texCoords)
    {
        cerr << "ERROR : Monkey head texcoords memory malloc failed !" << endl;
        exit(1);
    }
    for (loop = 0;loop < numVertices;++loop)
    {
        texCoords[loop * 2] = scaleFactor * MonkeyHead_vertices[3 * loop];
        texCoords[loop * 2 + 1] = scaleFactor * MonkeyHead_vertices[3 * loop + 1];
    }

    //use vertex array
    //enable array
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_NORMAL_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    //assign array data
    glVertexPointer(3,GL_FLOAT,3 * sizeof(GLfloat),MonkeyHead_vertices);
    glNormalPointer(GL_FLOAT,3 * sizeof(GLfloat),MonkeyHead_normals);
    glTexCoordPointer(2,GL_FLOAT,2 * sizeof(GLfloat),texCoords);

    glDrawElements(GL_TRIANGLES,3 * MonkeyHead_num_of_triangles,
        GL_UNSIGNED_SHORT,MonkeyHead_triangles);
}


//read bmp image file
AUX_RGBImageRec *LoadBMP(const char *FileName)
{
    FILE *File = NULL;
    if(!FileName)
        return NULL;
    File = fopen(FileName,"r");
    if (File)
    {
        fclose(File);
        return auxDIBImageLoad(FileName);
    }
    return NULL;
}

//load decal texture from a bmp file
int loadDecalTexture()
{
    int status = 1;
    AUX_RGBImageRec *TextureImage = NULL;
    if ((TextureImage = LoadBMP(decalBmpFile)))
    {
        glGenTextures(1,&decalTexture);
        glBindTexture(GL_TEXTURE_2D,decalTexture);
        glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,TextureImage->sizeX,
            TextureImage->sizeY,0,GL_RGB,GL_UNSIGNED_BYTE,
            TextureImage->data);//指定纹理
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);//指定过滤模式
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    }
    else
        status = 0;
    if (TextureImage)
    {
        if (TextureImage->data)
            free(TextureImage->data);
        free(TextureImage);
    }

    return status;
}

//load cube map from 6 bmp files
int loadCubeMap()
{
    int status = 1;
    AUX_RGBImageRec *TextureImage[6] = {NULL,NULL,NULL,NULL,NULL,NULL};
    for (loop = 0;loop < 6;++loop)
    {
        if (!(TextureImage[loop] = LoadBMP(bmpFile[loop])))
        {
            cout << "ERROR :load bmp file " << loop << " failed !" << endl;
            status = 0;
        }
    }

    glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGB, TextureImage[0] ->sizeX, TextureImage[0] ->sizeY,
        0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0] ->data);
    glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GL_RGB, TextureImage[1] ->sizeX, TextureImage[1] ->sizeY,
        0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[1] ->data);
    glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GL_RGB, TextureImage[2] ->sizeX, TextureImage[2] ->sizeY,
        0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[2] ->data);
    glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_RGB, TextureImage[3] ->sizeX, TextureImage[3] ->sizeY,
        0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[3] ->data);
    glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GL_RGB, TextureImage[4] ->sizeX, TextureImage[4] ->sizeY,
        0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[4] ->data);
    glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GL_RGB, TextureImage[5] ->sizeX, TextureImage[5] ->sizeY,
        0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[5] ->data);

    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    //free memory
    for (loop = 0;loop < 6;++loop)
    {
        if (TextureImage[loop])
        {
            if (TextureImage[loop] ->data)
            {
                free(TextureImage[loop] ->data);
            }
            free(TextureImage[loop]);
        }
    }

    return status;
}

//draw th surroundings as a cube with each face of 
//the cube environment map applied.
void drawSurroundings(const GLfloat *eyePosition)
{
    const float surroundingsDistance = 8;

    glLoadIdentity();
    gluLookAt(eyePosition[0],eyePosition[1],eyePosition[2],
        0,0,0,0,1,0);
    glScalef(surroundingsDistance,
        surroundingsDistance,
        surroundingsDistance);

    glEnable(GL_TEXTURE_CUBE_MAP);
    glBindTexture(GL_TEXTURE_CUBE_MAP,TO_ENVIRONMENT);
    glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE);

    glBegin(GL_QUADS);
        for (loop = 0;loop < 4 * 6;++loop)
        {
            glTexCoord3fv(vertex[loop]);
            glVertex3fv(vertex[loop]);
        }
    glEnd();
}

static void checkForCgError(const char *situation)
{
    CGerror error;
    const char *string = cgGetLastErrorString(&error);

    if (error != CG_NO_ERROR) {
        cout << "ERROR : " << myProgramName << situation << string << endl;
        if (error == CG_COMPILER_ERROR) {
            cout << cgGetLastListing(myCgContext) << endl;
        }
        exit(1);
    }
}

//init Cg shaders
void initCg()
{
    myCgContext = cgCreateContext();

    myCgVertexProfile = cgGLGetLatestProfile(CG_GL_VERTEX);
    cgGLSetOptimalOptions(myCgVertexProfile);
    checkForCgError("selecting vertex profile");

    myCgVertexProgram = cgCreateProgramFromFile(
        myCgContext,
        CG_SOURCE,
        myVertexProgramFileName,
        myCgVertexProfile,
        myVertexProgramName,
        NULL);
    checkForCgError("Creating vertex Cg program from file");

    cgGLLoadProgram(myCgVertexProgram);
    checkForCgError("loading vertex program");

    myCgFragmentProfile = cgGLGetLatestProfile(CG_GL_FRAGMENT);
    cgGLSetOptimalOptions(myCgFragmentProfile);
    checkForCgError("selecting fragment profile");

    myCgFragmentProgram = cgCreateProgramFromFile(
        myCgContext,
        CG_SOURCE,
        myFragmentProgramFileName,
        myCgFragmentProfile,
        myFragmentProgramName,
        NULL);
    checkForCgError("Creating fragment Cg program from file");

    cgGLLoadProgram(myCgFragmentProgram);
    checkForCgError("loading fragment program");
}

//compute rotate transformation matrix
void makeRotateMatrix(float angle,
                      float ax,float ay,float az,
                      float m[16])
{
    float radians, sine, cosine, ab, bc, ca, tx, ty, tz;
    float axis[3];
    float mag;

    axis[0] = ax;
    axis[1] = ay;
    axis[2] = az;
    mag = sqrt(axis[0]*axis[0] + axis[1]*axis[1] + axis[2]*axis[2]);
    if (mag) {
        axis[0] /= mag;
        axis[1] /= mag;
        axis[2] /= mag;
    }

    radians = angle * myPi / 180.0;
    sine = sin(radians);
    cosine = cos(radians);
    ab = axis[0] * axis[1] * (1 - cosine);
    bc = axis[1] * axis[2] * (1 - cosine);
    ca = axis[2] * axis[0] * (1 - cosine);
    tx = axis[0] * axis[0];
    ty = axis[1] * axis[1];
    tz = axis[2] * axis[2];

    m[0]  = tx + cosine * (1 - tx);
    m[1]  = ab + axis[2] * sine;
    m[2]  = ca - axis[1] * sine;
    m[3]  = 0.0f;
    m[4]  = ab - axis[2] * sine;
    m[5]  = ty + cosine * (1 - ty);
    m[6]  = bc + axis[0] * sine;
    m[7]  = 0.0f;
    m[8]  = ca + axis[1] * sine;
    m[9]  = bc - axis[0] * sine;
    m[10] = tz + cosine * (1 - tz);
    m[11] = 0;
    m[12] = 0;
    m[13] = 0;
    m[14] = 0;
    m[15] = 1;
}

//compute translation transformation matrix
static void makeTranslateMatrix(float x, float y, float z, float m[16])
{
    m[0]  = 1;  m[1]  = 0;  m[2]  = 0;  m[3]  = x;
    m[4]  = 0;  m[5]  = 1;  m[6]  = 0;  m[7]  = y;
    m[8]  = 0;  m[9]  = 0;  m[10] = 1;  m[11] = z;
    m[12] = 0;  m[13] = 0;  m[14] = 0;  m[15] = 1;
}

//multiply a floar4x4 matrix by another float4x4 matrix
static void multMatrix(float dst[16],const float src1[16],const float src2[16])
{
    for (int i = 0;i < 4;++i)
    {
        for (int j = 0;j < 4;++j)
        {
            dst[i * 4 + j] = src1[i * 4 + 0] * src2[0 * 4 + j] +
                                    src1[i * 4 + 1] * src2[1 * 4 + j] +
                                    src1[i * 4 + 2] * src2[2 * 4 + j] +
                                    src1[i * 4 + 3] * src2[3 * 4 + j];
        }
    }
}

void init()
{
    glewInit();
    glClearColor(0.0,0.0,0.0,1.0);
    glShadeModel(GL_SMOOTH);
    glEnable(GL_DEPTH_TEST);

    if (!loadDecalTexture())
    {
        cout << "ERROR : load decal texture from bmp file failed !" << endl;
        exit(1);
    }

    glBindTexture(GL_TEXTURE_CUBE_MAP,TO_ENVIRONMENT);
    if (!loadCubeMap())
    {
        cout << "ERROR : load cube map from bmp file failed !" << endl;
        exit(1);
    }


    initCg();
}

void display()
{
    const GLfloat eyePosition[4] = {6 * sin(eyeAngle),
                                                eyeHeight,
                                                6 * cos(eyeAngle),
                                                1};
    float tranlateMatrix[16],rotateMatrix[16],modelMatrix[16];
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    cgGLEnableProfile(myCgVertexProfile);
    checkForCgError("enabling vertex profile");

    cgGLEnableProfile(myCgFragmentProfile);
    checkForCgError("enabling fragment profile");

    cgGLBindProgram(myCgVertexProgram);
    checkForCgError("binding vertex program");

    cgGLBindProgram(myCgFragmentProgram);
    checkForCgError("binding fragment program");

    glLoadIdentity();
    glTranslatef(0.0,0.0,-5.0);
    glRotatef(headSpain,0,1,0);

    //set some uniform parameters in Cg shader
    cgGLSetParameter3fv(
        cgGetNamedParameter(myCgVertexProgram,"eyePositionW"),
        eyePosition);
    checkForCgError("setting eyePositionW parameter");

    makeRotateMatrix(headSpain,0,1,0,rotateMatrix);
    makeTranslateMatrix(0.0,0.0,-5.0,tranlateMatrix);
    multMatrix(modelMatrix,tranlateMatrix,rotateMatrix);
    //set the Cg matrix parameter : modelToWorld 
    cgSetMatrixParameterfr(
        cgGetNamedParameter(myCgVertexProgram,"modelToWorld"),
        modelMatrix);
    checkForCgError("setting modelToWorld parameter");
    cgGLSetParameter1f(
        cgGetNamedParameter(myCgFragmentProgram,"reflectivity"),
        reflectivity);
    checkForCgError("setting reflectivity parameter");

    cgGLSetTextureParameter(
        cgGetNamedParameter(myCgFragmentProgram,"decalMap"),
        decalTexture);
    checkForCgError("setting decalTexture parameter");
    cgGLSetTextureParameter(
        cgGetNamedParameter(myCgFragmentProgram,"environmentMap"),
        TO_ENVIRONMENT);
    checkForCgError("setting environmentMap parameter");

    drawMonkeyHead();

    cgGLDisableProfile(myCgVertexProfile);
    checkForCgError("disabling vertex profile");

    cgGLDisableProfile(myCgFragmentProfile);
    checkForCgError("disabling fragment profile");


    drawSurroundings(eyePosition);

    glutSwapBuffers();
}

static void idle()
{
    headSpain += 0.5;
    if (headSpain > 360)
    {
        headSpain -= 360;
    }
    glutPostRedisplay();
}

static void keyboard(unsigned char key,int x,int y)
{
    switch(key)
    {
    case ' ':
        animating = !animating;
        if (animating)
        {
            glutIdleFunc(idle);
        }
        else
            glutIdleFunc(NULL);
        break;
    case 'r':
        reflectivity += 0.1;
        if (reflectivity > 1.0)
        {
            reflectivity = 1.0;
        }
        cout << "reflectivity : " << reflectivity << endl;
        glutPostRedisplay();
        break;
    case 'R':
        reflectivity -= 0.1;
        if (reflectivity < 0.0)
        {
            reflectivity = 0.0;
        }
        cout << "reflectivity : " << reflectivity << endl;
        glutPostRedisplay();
        break;
    case 27:
        cgDestroyProgram(myCgVertexProgram);
        cgDestroyContext(myCgContext);
        exit(0);
        break;
    }
}

void reshape(int w,int h)
{
    glViewport(0,0,(GLsizei)w,(GLsizei)h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(60.0,1,1.0,20.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

int main(int argc,char** argv)
{
    glutInit(&argc,argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowPosition(0,0);
    glutInitWindowSize(600,600);
    glutCreateWindow("CubeMapReflection");
    init();
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutKeyboardFunc(keyboard);

    glutMainLoop();

    return 0;
}
4

1 に答える 1

0

私が最初に目にするのは、lerpステートメントの値を逆にする必要があるということです。

color.xyz = lerp(reflectedColor,decalColor,reflectivity);//change !!!!!!!!

する必要があります

color.xyz = lerp(decalColor, reflectedColor, reflectivity);

lerpのドキュメントには次のように書かれているためです。

lerp(a、b、w)は、w = 0の場合はaを返し、w = 1の場合はbを返します。反射率=0の場合は完全なデカールが必要であり、反射率=1の場合は完全に反射されます。

あなたが達成しようとしている効果はGL_MODULATEに似ているようです。値の間でlerpするのではなく、値を一緒に乗算する必要があります。これを試してみてください、それはうまくいくはずで、あなたが望む効果を与えるでしょう。

color.xyz = (reflectedColor.xyz * reflectivity) * decalColor;
于 2012-05-15T16:15:43.760 に答える