OpenGL.Shader:4-GPUカットシーン、並列操作の分析
この記事は、シェーダーコーディング仕様の学習を続けるための2つの簡単な例で構成されています。そして、シェーダー拡張並列操作の概念。対応するプロジェクトアドレス:https://github.com/MrZhaozhirong/NativeCppApp
最初の例のレンダリング。同じことが前の記事のコンテンツのキューブモデルデータに基づいています。関連するコードは表示されません。必要な学生はgithubで入手できます。次に、シェーダープログラムの関連コードの分析と学習に焦点を当てます。
#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));
}
呼び出しプロセスは次のとおりです。
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();
}
今回のシェーダープログラムの機能処理は、フラグメントシェーダーに焦点を当てています。頂点シェーダーは、関連データをフラグメントシェーダーに透過的に送信するだけです。実際、効果は最初の画像から2番目のターゲット画像に徐々に変化することです。ミキシングファクター_mixは、OpenGL.APIを介して時間の経過とともにシェーダープログラムに渡されます。
精度mediumpfloat;
ユニフォームサンプラー2D_texture0;
ユニフォームサンプラー2D_texture1;
ユニフォームフロート_mix;
可変vec2out_uv;
void main()
{ vec4 color0 = texture2D(_texture0、out_uv); //テクスチャ1に対応するカラーポイントのカラー値を抽出 vec4color1 = texture2D (_texture1、out_uv); //テクスチャ2に対応するカラーリングポイントのカラー値 vec4を抽出しますdstColor = color0 *(1.0-_mix)+ color1 * _mix; // 混合の数学計算を行いますgl_FragColor = mix(color0、color1、_mix) ; //混合計算にシステム独自の混合関数を使用する}
次に、ミックス関数のソースコードを自分で作成しました。これは、メインカーネル関数の3行目のコードです。ここでは少し理解しているようですが、すべてを理解しているわけではないようです。追加したいのは、組み込み関数texture2Dがテクスチャ座標out_uvに従って線形にサンプリングされることです。テクスチャ座標ポイントは4つしかありませんが、ラスター化後のサンプリングポイントは、実際にはシェーディングポイントの数と同じです。この例では、この文を説明できない場合があります。理解していなくてもかまいません。引き続き2番目の例を見てみましょう。
シェーダープログラムに対応する2番目のレンダリング例
#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));
}
呼び出しプロセスは上記と同じですが、ミキシングファクター_mixが設定されていない点が異なります。今回は、タイムオフセットオフセットです。フラグメントシェーダーの分析に引き続き焦点を当てます。
精密ミディアムフロート;
均一なsampler2D_texture0;
均一なsampler2D_texture1;
均一なフロートオフセット。
さまざまなvec2out_uv;
void main()
{ vec4 color = vec4(0,0,0,1); if(out_uv.x <=オフセット){ color = texture2D(_texture1、vec2(out_uv.x +(1.0-オフセット)、out_uv.y)); } else { color = texture2D(_texture0、vec2(out_uv.x-オフセット、out_uv.y)); } gl_FragColor = color; }
オフセットは0から1に徐々に変化し、テクスチャの横軸が判断に使用されます。オフセットの左側の表示スペースで、サンプリング用にtexture1の0〜out_uv.x +(1.0-オフセット)領域を抽出します。オフセットの右側にあります。スペースを表示し、サンプリングのためにtexture0の0〜out_uv.xオフセット領域を抽出します。理解していなくても構いません。下の簡単な図をご覧ください。
offset = 0.4の場合、最初にディスプレイの右側の領域を見てください。0.4(0.5〜6〜7〜8〜9〜1.0)より大きいすべてのテクスチャ座標は、最初にoffset =(0.1〜2〜3〜4〜の値を差し引きます。 5)次に、テクスチャtexture0のカラーポイントをサンプリングします。offset= 0.5の場合、テクスチャ座標は1桁(0.1〜2〜3〜0.4)減少し、texture0の表示領域は左に縮小し、視覚効果は右にシフトします。
オフセット= 0.4の場合、ディスプレイの左側の領域(uv.x <= offset)で、0.4未満のすべてのテクスチャ座標(0〜0.1〜0.2〜0.3〜0.4)は、画像のテクスチャ範囲全体ですべて+1になり、変化します(1〜1.1〜1.2〜1.3〜1.4)になり、0.4 =(0.6〜7〜8〜9〜1.0)を引いて、最後にこの座標のセットでtexture1のカラー値をサンプリングします。offset = 0.5の場合、テクスチャ座標にもう1桁追加します(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)。Texture1は境界を基準としており、左に向かって連続的に拡大します。
この例を通して、クラスメートがまだ目がくらんでいない場合は、並列コンピューティングの基本概念を習得したことを祝福します。これは2レベルの並列処理です。フラグメントシェーダーはシェーディングポイントの単位で実行され、ハードウェアのGPUレンダリングを1つずつシェーディングできないため、フラグメントシェーダーの書き込みには、基本的に、NIVIDAのCUDAパラレルでのパラレル思考が必要です。算術ライブラリの主要なカーネル関数は、実際にはフラグメントシェーダープログラムと同等です。興味のある学生は、BaiduCUDAで視野を広げることができます。
2つの例を通して、フラグメントカラーリングプログラムのコーディング標準といくつかのアプリケーションスキルを学び、よく理解されているいくつかの概念を導き出しました。