OpenGL.Shader: 4-GPU-Zwischensequenzen, Analyse paralleler Operationen

OpenGL.Shader: 4-GPU-Zwischensequenzen, Analyse paralleler Operationen

 

Dieser Artikel besteht aus zwei einfachen Beispielen, um die Shader-Codierungsspezifikation weiter zu lernen. Und das Konzept des Shader-Erweiterungs-Parallelbetriebs. Entsprechende Projektadresse: https://github.com/MrZhaozhirong/NativeCppApp 

Das Rendern des ersten Beispiels. Das gleiche basiert immer noch auf den Cube-Modelldaten des vorherigen Artikelinhalts. Der entsprechende Code wird nicht erstellt. Bedürftige Schüler können ihn auf Github herunterladen. Konzentrieren Sie sich nun darauf, den relevanten Code des Shader-Programms zu analysieren und zu lernen.


#include "GPUMixShaderProgram.h"
#include "ShaderHelper.h"

/**
 * 正方体动态渐变 着色器程序
 */
GPUMixShaderProgram::GPUMixShaderProgram()
{
    const char * vertexShaderResourceStr  = "uniform mat4    u_Matrix;\n\
                                             attribute vec4  a_Position;\n\
                                             attribute vec2  a_uv;\n\
                                             varying vec2    out_uv;\n\
                                             void main()\n\
                                             {\n\
                                                 out_uv      =   a_uv;\n\
                                                 gl_Position =   u_Matrix * a_Position;\n\
                                             }";
    const char * fragmentShaderResourceStr= "precision mediump float;\n\
                                             uniform sampler2D _texture0;\n\
                                             uniform sampler2D _texture1;\n\
                                             uniform float     _mix;\n\
                                             varying vec2      out_uv;\n\
                                             void main()\n\
                                             {\n\
                                                 vec4 color0    =  texture2D(_texture0, out_uv);\n\
                                                 vec4 color1    =  texture2D(_texture1, out_uv);\n\
                                                 vec4 dstColor  =  color0 * (1.0 - _mix)  + color1 * _mix;\n\
                                                 gl_FragColor   =  mix(color0, color1, _mix);\n\
                                             }";

    //                                           gl_FragColor   =   dstColor;
    programId = ShaderHelper::buildProgram(vertexShaderResourceStr, fragmentShaderResourceStr);

    uMatrixLocation     = glGetUniformLocation(programId, "u_Matrix");
    aPositionLocation   = glGetAttribLocation(programId, "a_Position");
    uMixLocation        = glGetUniformLocation(programId, "_mix");
    aTexUvLocation      = glGetAttribLocation(programId, "a_uv");
    uTextureUnit0       = glGetUniformLocation(programId, "_texture0");
    uTextureUnit1       = glGetUniformLocation(programId, "_texture1");
}

void GPUMixShaderProgram::setMVPUniforms(float* matrix){
    glUniformMatrix4fv(uMatrixLocation, 1, GL_FALSE, matrix);
}

void GPUMixShaderProgram::setMixUniform(double mix){
    glUniform1f(uMixLocation, static_cast<GLfloat>(mix));
}

Der aufrufende Prozess ist wie folgt:

void NativeGLRender::renderOnDraw(double elpasedInMilliSec)
{
    mWindowSurface->makeCurrent();
    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
    // GPUMixShaderProgram和GPUFlatSlidingProgram所需
    double _hasElasped = elpasedInMilliSec/1000 * 0.1f;
    if (_hasElasped > 1.0f)
    {
        _hasElasped = 1.0f;
    }
    gpuMixShaderProgram->ShaderProgram::userProgram();
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texture_0_id);
    glUniform1i(gpuMixShaderProgram->uTextureUnit0, 0);
    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, texture_1_id);
    glUniform1i(gpuMixShaderProgram->uTextureUnit1, 1);

    CELL::Matrix::multiplyMM(modelViewProjectionMatrix, viewProjectionMatrix, cube->modelMatrix);
    gpuMixShaderProgram->setMVPUniforms(modelViewProjectionMatrix);
    gpuMixShaderProgram->setMixUniform(_hasElasped); // 设置混合因子
    cube->bindData(gpuFlatSlidingProgram);
    cube->draw();
    mWindowSurface->swapBuffers();
}

Die funktionale Verarbeitung des Shader-Programms konzentriert sich diesmal auf den Fragment-Shader. Der Vertex-Shader überträgt die relevanten Daten einfach transparent an den Fragment-Shader. Tatsächlich besteht der Effekt darin, allmählich vom ersten Bild zum zweiten Zielbild zu wechseln. Der Mischfaktor _mix wird im Laufe der Zeit über OpenGL.API an das Shader-Programm übergeben.

Präzision Mediump Float;
Uniform Sampler2D _texture0;
Uniform Sampler2D _texture1;
Uniform Float _Mix;
Variieren von vec2 out_uv;
void main ()
{     vec4 color0 = Textur2D (_texture0, out_uv); // Extrahieren Sie den Farbwert des Farbpunkts entsprechend Textur 1     vec4 color1 = Textur2D (_texture1, out_uv); // Extrahiere den Farbwert     vec4 des Farbpunkts entsprechend Textur 2 dstColor = color0 * (1.0-_mix) + color1 * _mix; // Berechne mathematisch das     Mischen von gl_FragColor = mix (color0, color1, _mix) ; // Verwenden Sie die systemeigene Mischfunktion zum Mischen von Berechnungen }




Zweitens habe ich den Quellcode der Mix-Funktion selbst geschrieben. Dies ist die dritte Codezeile in der Hauptkernfunktion. Ich scheine hier ein bisschen zu verstehen, aber ich scheine nicht alles zu verstehen. Was ich hinzufügen möchte, ist, dass die eingebaute Funktion textur2D linear gemäß der Texturkoordinate out_uv abgetastet wird. Obwohl es nur vier Texturkoordinatenpunkte gibt, entsprechen die Abtastpunkte nach der Rasterung tatsächlich der Anzahl der Schattierungspunkte. Dieses Beispiel kann diesen Satz möglicherweise nicht erklären. Es spielt keine Rolle, ob Sie ihn nicht verstehen. Schauen wir uns weiterhin das zweite Beispiel an.

 

        Das zweite Beispiel-Rendering entspricht dem Shader-Programm

#include "GPUFlatSlidingProgram.h"
#include "ShaderHelper.h"

GPUFlatSlidingProgram::GPUFlatSlidingProgram()
{
    const char * vertexShaderResourceStr  = "uniform mat4    u_Matrix;\n\
                                             attribute vec4  a_Position;\n\
                                             attribute vec2  a_uv;\n\
                                             varying vec2    out_uv;\n\
                                             void main()\n\
                                             {\n\
                                                 out_uv      =   a_uv;\n\
                                                 gl_Position =   u_Matrix * a_Position;\n\
                                             }";

    const char * fragmentShaderResourceStr= "precision mediump float;\n\
                                             uniform sampler2D _texture0;\n\
                                             uniform sampler2D _texture1;\n\
                                             uniform float     offset;\n\
                                             varying vec2      out_uv;\n\
                                             void main()\n\
                                             {\n\
                                                 vec4 color = vec4(0,0,0,1);\n\
                                                 if(out_uv.x <= offset )\n\
                                                    color = texture2D(_texture1, vec2(out_uv.x + (1.0 - offset), out_uv.y));\n\
                                                 else\n\
                                                    color = texture2D(_texture0, vec2(out_uv.x - offset, out_uv.y));\n\
                                                 gl_FragColor   =  color; \n\
                                             }";

    programId = ShaderHelper::buildProgram(vertexShaderResourceStr, fragmentShaderResourceStr);

    uMatrixLocation     = glGetUniformLocation(programId, "u_Matrix");
    aPositionLocation   = glGetAttribLocation(programId,  "a_Position");
    aTexUvLocation      = glGetAttribLocation(programId,  "a_uv");
    uOffset             = glGetUniformLocation(programId, "offset");
    uTextureUnit0       = glGetUniformLocation(programId, "_texture0");
    uTextureUnit1       = glGetUniformLocation(programId, "_texture1");
}

void GPUFlatSlidingProgram::setMVPUniforms(float* matrix){
    glUniformMatrix4fv(uMatrixLocation, 1, GL_FALSE, matrix);
}

void GPUFlatSlidingProgram::setOffsetUniform(double offset){
    glUniform1f(uOffset, static_cast<GLfloat>(offset));
}

Der Aufrufvorgang ist der gleiche wie oben, außer dass der Mischfaktor _mix nicht mehr eingestellt ist, diesmal ist es der Zeitversatzversatz. Konzentrieren Sie sich weiterhin auf die Analyse des Fragment-Shaders.

Präzisions-Mediump-Schwimmer;
einheitlicher Sampler2D _texture0;
einheitlicher Sampler2D _texture1;
gleichmäßiger Schwimmerversatz;
variierendes vec2 out_uv;
void main ()
{     vec4 color = vec4 (0,0,0,1);     if (out_uv.x <= Offset) {        Farbe = Textur2D (_texture1, vec2 (out_uv.x + (1.0 - Offset), out_uv.y));     } else {        color = texture2D (_texture0, vec2 (out_uv.x - offset, out_uv.y));     }     gl_FragColor = color; }}







Der Versatz ändert sich allmählich von 0 auf 1, und die Abszisse der Textur wird zur Beurteilung verwendet. Im Anzeigebereich links vom Versatz extrahieren wir den Bereich 0 ~ out_uv.x + (1,0-Versatz) von Textur1 für die Abtastung rechts vom Versatz Zeigen Sie Platz an, extrahieren Sie den 0 ~ out_uv.x-Offset-Bereich von texture0 für die Abtastung. Es spielt keine Rolle, ob Sie ihn nicht verstehen. Schauen Sie sich einfach die einfache Abbildung unten an.

Wenn Offset = 0,4, schauen Sie zuerst in den rechten Bereich der Anzeige. Alle Texturkoordinaten größer als 0,4 (0,5 ~ 6 ~ 7 ~ 8 ~ 9 ~ 1,0) subtrahieren zuerst den Wert von Offset = (0,1 ~ 2 ~ 3 ~ 4 ~ 5) Probieren Sie dann die Farbpunkte der Texturtextur0 aus. Wenn der Versatz = 0,5 ist, werden die Texturkoordinaten um eine Ziffer (0,1 ~ 2 ~ 3 ~ 0,4) reduziert, und der Anzeigebereich der Textur0 wird nach links verkleinert, und der visuelle Effekt wird nach rechts verschoben.

Wenn der Versatz = 0,4 ist, werden im linken Bereich der Anzeige (uv.x <= Versatz) alle Texturkoordinaten unter 0,4 (0 ~ 0,1 ~ 0,2 ~ 0,3 ~ 0,4) über den Texturbereich eines Bildes +1 und ändern sich Es wird (1 ~ 1,1 ~ 1,2 ~ 1,3 ~ 1,4), subtrahiert dann 0,4 = (0,6 ~ 7 ~ 8 ~ 9 ~ 1,0) und tastet schließlich den Farbwert von Textur1 mit diesem Satz von Koordinaten ab. Wenn Offset = 0,5, addieren Sie eine weitere Ziffer zu den Texturkoordinaten (0 ~ 0,1 ~ 0,2 ~ 0,3 ~ 0,4 ~ 0,5) => (1 ~ 1,1 ~ 1,2 ~ 1,3 ~ 1,4 ~ 1,5) => (0,5 ~ 6 ~ 7 ~ 8) ~ 9 ~ 1,0). Die Textur1 hat die Grenze als Referenz und wird weiter nach links erweitert.

Wenn in diesem Beispiel den Klassenkameraden noch nicht schwindelig ist, herzlichen Glückwunsch zur Beherrschung der Grundkonzepte des parallelen Rechnens und es handelt sich um eine zweistufige Parallelität. Da der Fragment-Shader in Einheiten von Schattierungspunkten ausgeführt wird und das GPU-Rendering der Hardware nicht einzeln schattiert werden kann, erfordert das Schreiben des Fragment-Shaders im CUDA-Parallel von NIVIDA grundsätzlich paralleles Denken Die wichtigsten Kernelfunktionen in der Arithmetikbibliothek entsprechen tatsächlich dem Fragment-Shader-Programm. Interessierte Studenten können ihren Horizont auf Baidu CUDA erweitern.

Anhand von zwei Beispielen lernte ich die Codierungsstandards des Fragmentfarbprogramms und einige Anwendungsfähigkeiten und leitete einige Konzepte ab, die gut verstanden wurden.

Ich denke du magst

Origin blog.csdn.net/a360940265a/article/details/89083798
Empfohlen
Rangfolge