How is the w component of the geometric coordinates computed in the example of perspective correction?

How is the w component of the geometric coordinates computed in the example of perspective correction?

Perspective-correction-interpolation demo
static float vertexClipCoords1[] =
{
25.0, 25.0, 150.0, 150.0,
-25.0, 25.0, 150.0, 150.0,
25.0, 25.0, -50.0, 50.0
};

https://github.com/kingchenbin/Perspective-correction-interpolation

#version 420

//vertex attribs
in vec4 model_postion;
in vec2 tex_coord_in;

//uniform variables
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;

//vs output
out vec4 eye_coord;
out vec4 clip_coord;
out vec2 tex_coord;
noperspective out vec2 tex_coord_NoCorrection;
flat out vec2 tex_coord_Flat;

void main(void) 
{
    tex_coord = tex_coord_in;
    tex_coord_NoCorrection = tex_coord_in;
    tex_coord_Flat = tex_coord_in;
    eye_coord = modelViewMatrix * model_postion;
    clip_coord = projectionMatrix * eye_coord;
    gl_Position = clip_coord;
}
#version 420

//ps input
in vec4 eye_coord;
in vec4 clip_coord;
in vec2 tex_coord;
noperspective in vec2 tex_coord_NoCorrection;
flat in vec2 tex_coord_Flat;

//uniform variables
uniform sampler2D tex;
uniform vec2 vertexWindowCoords[3];
uniform vec4 vertexClipCoords[3];
uniform vec2 vertexTexCoords[3];
uniform int interpolateMode;

//ps output
out vec4 color;

float calcLength(vec2 start, vec2 end)
{
    return sqrt(pow(start.x-end.x, 2) + pow(start.y-end.y,2));
}

float calcSquare(vec2 A, vec2 B, vec2 C)
{
    float lenA, lenB, lenC, p;
    lenA = calcLength(B, C);
    lenB = calcLength(A, C);
    lenC = calcLength(A, B);
    p = (lenA+lenB+lenC)/2.0;
    return sqrt(p*(p-lenA)*(p-lenB)*(p-lenC));
}

void main(void) 
{
    if (interpolateMode == 2)
    {
        color = texture(tex, tex_coord_NoCorrection);
    }
    else if (interpolateMode == 3 || interpolateMode == 4)
    {
        float a,b,c;
        float squareA,squareB,squareC,square;

        square = calcSquare(vertexWindowCoords[0], vertexWindowCoords[1], vertexWindowCoords[2]);
        squareA = calcSquare(gl_FragCoord.xy, vertexWindowCoords[1], vertexWindowCoords[2]);
        squareB = calcSquare(gl_FragCoord.xy, vertexWindowCoords[0], vertexWindowCoords[2]);
        squareC = calcSquare(gl_FragCoord.xy, vertexWindowCoords[0], vertexWindowCoords[1]);

        a = squareA/square;
        b = squareB/square;
        c = squareC/square;
        
        if (interpolateMode == 3)
        {
            vec2 texCoordCorrection;
            texCoordCorrection = a * vertexTexCoords[0] / vertexClipCoords[0].w + b * vertexTexCoords[1] / vertexClipCoords[1].w + c * vertexTexCoords[2] / vertexClipCoords[2].w;
            texCoordCorrection = texCoordCorrection / (a / vertexClipCoords[0].w + b / vertexClipCoords[1].w + c / vertexClipCoords[2].w);
            color = texture(tex, texCoordCorrection);
        }
        else
        {
            vec2 texCoordNoCorrection;
            texCoordNoCorrection = a * vertexTexCoords[0] + b * vertexTexCoords[1] + c * vertexTexCoords[2];
            color = texture(tex, tex_coord_NoCorrection);
        }
    }
    else
    {
        color = texture(tex, tex_coord);
    }
}
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <io.h>
#define GLEW_STATIC 1
#include <GL/glew.h>
#include <GL/glu.h>
#include <GL/glut.h>

#pragma comment(lib,"glew32s.lib")

//Shader类型
typedef enum {
    EVertexShader,
    EFragmentShader,
} EShaderType;

//窗口句柄
static GLint window;

GLuint prog = 0;                        //程序对象
GLuint progNoPersectiveCorrect  = 0;    //程序对象

//InterpolateMode
//1:no qualifier(perspective)
//2:noPerspective
//3:simulate perspective
//4:simulate noPerspective
GLuint InterpolateMode = 1;

static float vertexData[] =
{
    -50.0, -50.0, - 50.0, 1.0, 0.0, 0.0,
     50.0, -50.0, - 50.0, 1.0, 1.0, 0.0,
     50.0,  50.0, -150.0, 1.0, 1.0, 1.0,

     50.0,  50.0, -150.0, 1.0, 1.0, 1.0,
    -50.0,  50.0, -150.0, 1.0, 0.0, 1.0,
    -50.0, -50.0, - 50.0, 1.0, 0.0, 0.0
};

static float modelViewMat[] =
{
    1.0, 0.0, 0.0, 0.0,
    0.0, 1.0, 0.0, 0.0,
    0.0, 0.0, 1.0, 0.0,
    0.0, 0.0, 0.0, 1.0
};

//void Frustum( -100.0, 100.0, -100.0, 100.0, 50.0, 150.0);
static float projectionMat[] =
{
    0.5, 0.0, 0.0, 0.0,
    0.0, 0.5, 0.0, 0.0,
    0.0, 0.0, -2.0, -150.0,
    0.0, 0.0, -1.0, 0.0
};

static float vertexWindowCoords[] =
{
    200.5, 200.5,
    600.5, 200.5,
    466.5, 466.5
};

static float vertexClipCoords[] =
{
    -25.0, -25.0, -50.0,  50.0,
     25.0, -25.0, -50.0,  50.0,
     25.0,  25.0, 150.0, 150.0
};

static float vertexTexCoords[] =
{
    0.0, 0.0,
    1.0, 0.0,
    1.0, 1.0
};

static float vertexWindowCoords1[] =
{
    466.5, 466.5,
    333.5, 466.5,
    200.5, 200.5
};

static float vertexClipCoords1[] =
{
     25.0,  25.0, 150.0, 150.0,
    -25.0,  25.0, 150.0, 150.0,
     25.0,  25.0, -50.0,  50.0
};

static float vertexTexCoords1[] =
{
    1.0, 1.0,
    0.0, 1.0,
    0.0, 0.0
};

//用来检查OpenGL版本,需要GLSL 2.0支持
void getGlVersion( int *major, int *minor )
{
    const char* verstr = (const char*)glGetString( GL_VERSION );
    if( (verstr == NULL) || (sscanf( verstr, "%d.%d", major, minor ) != 2) )
    {
        *major = *minor = 0;
        fprintf( stderr, "Invalid GL_VERSION format!!!\n" );
    }
}

static void display(void)
{
    GLuint loc;

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // Set up attrib values
    loc = glGetAttribLocation(progNoPersectiveCorrect, "model_postion");
    glVertexAttribPointer(loc, 4, GL_FLOAT, GL_FALSE, 24, (GLvoid *)0);
    glEnableVertexAttribArray(loc);
    loc = glGetAttribLocation(progNoPersectiveCorrect, "tex_coord_in");
    glVertexAttribPointer(loc, 2, GL_FLOAT, GL_FALSE, 24, (GLvoid *)16);
    glEnableVertexAttribArray(loc);

    // Set up initial uniform values
    glUniformMatrix4fv(glGetUniformLocation(progNoPersectiveCorrect, "modelViewMatrix"), 1, GL_TRUE, modelViewMat);
    glUniformMatrix4fv(glGetUniformLocation(progNoPersectiveCorrect, "projectionMatrix"), 1, GL_TRUE, projectionMat);
    glUniform1i(glGetUniformLocation(progNoPersectiveCorrect, "tex"), 0);
    glUniform2fv(glGetUniformLocation(progNoPersectiveCorrect, "vertexWindowCoords"), 3, vertexWindowCoords);
    glUniform4fv(glGetUniformLocation(progNoPersectiveCorrect, "vertexClipCoords"), 3, vertexClipCoords);
    glUniform2fv(glGetUniformLocation(progNoPersectiveCorrect, "vertexTexCoords"), 3, vertexTexCoords);
    glUniform1i(glGetUniformLocation(progNoPersectiveCorrect, "interpolateMode"), (int)InterpolateMode);

    glDrawArrays(GL_TRIANGLES, 0, 3);

    // Set up attrib values
    loc = glGetAttribLocation(progNoPersectiveCorrect, "model_postion");
    glVertexAttribPointer(loc, 4, GL_FLOAT, GL_FALSE, 24, (GLvoid *)72);
    glEnableVertexAttribArray(loc);
    loc = glGetAttribLocation(progNoPersectiveCorrect, "tex_coord_in");
    glVertexAttribPointer(loc, 2, GL_FLOAT, GL_FALSE, 24, (GLvoid *)88);
    glEnableVertexAttribArray(loc);

    // Set up initial uniform values
    glUniform2fv(glGetUniformLocation(progNoPersectiveCorrect, "vertexWindowCoords"), 3, vertexWindowCoords1);
    glUniform4fv(glGetUniformLocation(progNoPersectiveCorrect, "vertexClipCoords"), 3, vertexClipCoords1);
    glUniform2fv(glGetUniformLocation(progNoPersectiveCorrect, "vertexTexCoords"), 3, vertexTexCoords1);

    glDrawArrays(GL_TRIANGLES, 0, 3);

    glFlush();
    glutSwapBuffers();
}

static void reshape(int wid, int ht)
{
    return;
}


//Shader related functions
static int shaderSize(char *fileName, EShaderType shaderType)
{
    //返回顶点着色器或者片段着色器的大小
    char name[100];
    strcpy(name, fileName);

    switch (shaderType)
    {
    case EVertexShader:
        strcat(name, ".vert");
        break;
    case EFragmentShader:
        strcat(name, ".frag");
        break;
    default:
        printf("ERROR: unknown shader file type\n");
        exit(1);
        break;
    }

    int count = -1;
    // Open the file, seek to the end to find its length
    int fd = _open(name, _O_RDONLY);
    if (fd != -1)
    {
        count = _lseek(fd, 0, SEEK_END) + 1;
        _close(fd);
    }
    return count;
}


static int readShader(char *fileName, EShaderType shaderType, char *shaderText, int size)
{
    //
    // Reads a shader from the supplied file and returns the shader in the
    // arrays passed in. Returns 1 if successful, 0 if an error occurred.
    // The parameter size is an upper limit of the amount of bytes to read.
    // It is ok for it to be too big.
    //
    FILE *fh;
    char name[100];
    int count;

    strcpy(name, fileName);

    switch (shaderType) 
    {
    case EVertexShader:
        strcat(name, ".vert");
        break;
    case EFragmentShader:
        strcat(name, ".frag");
        break;
    default:
        printf("ERROR: unknown shader file type\n");
        exit(1);
        break;
    }

    // Open the file
    fh = fopen(name, "r");
    if (!fh)
        return -1;

    // Get the shader from a file.
    fseek(fh, 0, SEEK_SET);
    count = (int) fread(shaderText, 1, size, fh);
    shaderText[count] = '\0';

    if (ferror(fh))
        count = 0;

    fclose(fh);
    return count;
}


/*public*/
int readShaderSource(char *fileName, GLchar **vertexShader, GLchar **fragmentShader)
{
    int vSize, fSize;

    //
    // Allocate memory to hold the source of our shaders.
    //
    vSize = shaderSize(fileName, EVertexShader);
    fSize = shaderSize(fileName, EFragmentShader);

    if ((vSize == -1) || (fSize == -1))
    {
        printf("Cannot determine size of the shader %s\n", fileName);
        return 0;
    }

    *vertexShader = (GLchar *) malloc(vSize);
    *fragmentShader = (GLchar *) malloc(fSize);

    //
    // Read the source code
    //
    if (!readShader(fileName, EVertexShader, *vertexShader, vSize))
    {
        printf("Cannot read the file %s.vert\n", fileName);
        return 0;
    }

    if (!readShader(fileName, EFragmentShader, *fragmentShader, fSize))
    {
        printf("Cannot read the file %s.frag\n", fileName);
        return 0;
    }

    return 1;
}


/*public*/
int installShaders(const GLchar *Vertex,
                   const GLchar *Fragment,
                   GLuint *Program)
{
    GLuint VertexShaderObject   = 0;    //顶点着色器对象
    GLuint FragmentShaderObject = 0;    //片段着色器对象
    GLint vertCompiled, fragCompiled;   //status values
    GLint linked;

    // Create a vertex shader object and a fragment shader object

    VertexShaderObject = glCreateShader(GL_VERTEX_SHADER);
    FragmentShaderObject = glCreateShader(GL_FRAGMENT_SHADER);

    // Load source code strings into shaders

    glShaderSource(VertexShaderObject, 1, &Vertex, NULL);
    glShaderSource(FragmentShaderObject, 1, &Fragment, NULL);

    // Compile the brick vertex shader, and print out
    // the compiler log file.

    glCompileShader(VertexShaderObject);
    glGetShaderiv(VertexShaderObject, GL_COMPILE_STATUS, &vertCompiled);

    // Compile the brick vertex shader, and print out
    // the compiler log file.

    glCompileShader(FragmentShaderObject);
    glGetShaderiv(FragmentShaderObject, GL_COMPILE_STATUS, &fragCompiled);

    char fragLog[1024];
    glGetShaderInfoLog(FragmentShaderObject, 1024, NULL, fragLog);

    if (!vertCompiled || !fragCompiled)
        return 0;

    // Create a program object and attach the two compiled shaders

    *Program = glCreateProgram();
    glAttachShader(*Program, VertexShaderObject);
    glAttachShader(*Program, FragmentShaderObject);

    // Link the program object and print out the info log

    glLinkProgram(*Program);
    glGetProgramiv(*Program, GL_LINK_STATUS, &linked);

    if (!linked)
        return 0;

    return 1;
}

bool init()
{
    GLchar *VertexShaderSource, *FragmentShaderSource;
    bool success = true;
    GLuint vb = 0, tex = 0;
    GLint loc = 0;

    glGenBuffers(1, &vb);
    glBindBuffer(GL_ARRAY_BUFFER, vb);
    glBufferData(GL_ARRAY_BUFFER, 144, vertexData, GL_STATIC_DRAW);

    glGenTextures(1, &tex);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, tex);

    int texSize = 1024;
    int blockSize = 64;
    int rowPitch = texSize * 4;
    unsigned char* texData = new unsigned char[texSize*texSize*4];
    for (int i = 0; i < texSize/blockSize; ++i)
    {
        for (int j = 0; j < texSize/blockSize; ++j)
        {
            int startX = i*blockSize;
            int startY = j*blockSize;
            bool white = (bool)(i%2 ^ j%2);

            for (int m = startX; m < startX + blockSize; ++m)
            {
                for (int n = startY; n < startY + blockSize; ++n)
                {
                    texData[n * rowPitch + m * 4 + 0] = white ? 255 : 0;
                    texData[n * rowPitch + m * 4 + 1] = white ? 255 : 0;
                    texData[n * rowPitch + m * 4 + 2] = white ? 255 : 0;
                    texData[n * rowPitch + m * 4 + 3] = 255;
                }
            }
        }
    }

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, texSize, texSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, texData);
    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_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_WRAP_R,GL_CLAMP_TO_EDGE);

    /*
    readShaderSource("perspective", &VertexShaderSource, &FragmentShaderSource);
    success = (bool)installShaders(VertexShaderSource, FragmentShaderSource, &prog);
    if (!success) goto Exit;

    // Install program object as part of current state
    glUseProgram(prog);

    // Set up attrib values
    loc = glGetAttribLocation(prog, "model_postion");
    glVertexAttribPointer(loc, 4, GL_FLOAT, GL_FALSE, 24, (GLvoid *)0);
    glEnableVertexAttribArray(loc);
    loc = glGetAttribLocation(prog, "tex_coord_in");
    glVertexAttribPointer(loc, 2, GL_FLOAT, GL_FALSE, 24, (GLvoid *)16);
    glEnableVertexAttribArray(loc);

    // Set up initial uniform values
    glUniformMatrix4fv(glGetUniformLocation(prog, "modelViewMatrix"), 1, GL_TRUE, modelViewMat);
    glUniformMatrix4fv(glGetUniformLocation(prog, "projectionMatrix"), 1, GL_TRUE, projectionMat);
    glUniform1i(glGetUniformLocation(prog, "tex"), 0);
    */

    readShaderSource("noPersectiveCorrect", &VertexShaderSource, &FragmentShaderSource);
    success = (bool)installShaders(VertexShaderSource, FragmentShaderSource, &progNoPersectiveCorrect);
    if (!success) goto Exit;

    // Install program object as part of current state
    glUseProgram(progNoPersectiveCorrect);

    glViewport(0,0,800,800);
    glClearColor(0.2,0.2,0.2,1.0);
    glClearDepth(0.0);
    glDisable(GL_DEPTH_TEST);

Exit:
    return success;
}

void keyboard(unsigned char key, int x, int y)
{
    switch (key) {
      case '1':
          InterpolateMode = 1;
          glUniform1i(glGetUniformLocation(progNoPersectiveCorrect, "interpolateMode"), (int)InterpolateMode);
          glutPostRedisplay();
          break;
      case '2':
          InterpolateMode = 2;
          glUniform1i(glGetUniformLocation(progNoPersectiveCorrect, "interpolateMode"), (int)InterpolateMode);
          glutPostRedisplay();
          break;
      case '3':
          InterpolateMode = 3;
          glUniform1i(glGetUniformLocation(progNoPersectiveCorrect, "interpolateMode"), (int)InterpolateMode);
          glutPostRedisplay();
          break;
      case '4':
          InterpolateMode = 4;
          glUniform1i(glGetUniformLocation(progNoPersectiveCorrect, "interpolateMode"), (int)InterpolateMode);
          glutPostRedisplay();
          break;
      case 'q':
          exit(0);
          break;
      default:
          break;
    }
}

/******************************************************************************/
/*
/* Main
/*
/******************************************************************************/
int main( int argc, char **argv )
{
    int success = 0;
    int gl_major, gl_minor;

    glutInit( &argc, argv );
    glutInitDisplayMode( GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE);
    glutInitWindowSize(800, 800);
    window = glutCreateWindow( "Perspective Correction");

    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutKeyboardFunc(keyboard);

    // Initialize the "OpenGL Extension Wrangler" library
    glewInit();

    // Make sure that OpenGL 2.0 is supported by the driver
    getGlVersion(&gl_major, &gl_minor);
    printf("GL_VERSION major=%d minor=%d\n", gl_major, gl_minor);

    if (gl_major < 2)
    {
        printf("GL_VERSION major=%d minor=%d\n", gl_major, gl_minor);
        printf("Support for OpenGL 2.0 is required for this demo...exiting\n");
        exit(1);
    }

    success = init();

    if (success)
        glutMainLoop();

    return 0;
}

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.