質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
GLSL

GLSL (OpenGL Shading Language) はC言語をベースとしたシェーディング言語です。

GLSL ES

GLSL ESは、GLSLの派生規格で、 組み込み環境向けのOpenGL ES用のシェーダー言語です。

Q&A

2回答

1102閲覧

GLSLを用いたfftの可視化について、glsl150からglsl120への書き換え

santaro

総合スコア18

GLSL

GLSL (OpenGL Shading Language) はC言語をベースとしたシェーディング言語です。

GLSL ES

GLSL ESは、GLSLの派生規格で、 組み込み環境向けのOpenGL ES用のシェーダー言語です。

0グッド

1クリップ

投稿2018/04/20 13:56

編集2018/04/21 03:08

私はGLSLを使用してfftテクスチャを作成しようとしています。 しかし、現在のバージョン150で作成されたものの、バージョン120に書き直したいと思っていましたが、うまくいきません。下にソースコードを貼り付けますので、原因が分かっていれば教えてください。

glsl150.vert

#version 150 uniform mat4 modelViewProjectionMatrix; in vec4 position; in vec2 texcoord; out vec2 vTexCoord; void main(){ vTexCoord = texcoord; gl_Position = modelViewProjectionMatrix * position; }

glsl150.frag

#version 150 uniform sampler2DRect tex; uniform float rawFft[256]; in vec2 vTexCoord; out vec4 outputColor; void main(){ if (vTexCoord.y < 1.0) { int i = int(vTexCoord.x); outputColor.r = rawFft[i]; } else { vec2 st = vTexCoord; st.y -= 1.0; outputColor.r = texture(tex, st).r; } outputColor.a = 1.0; }

イメージ説明

glsl120.vert

#version 120 #extension GL_ARB_texture_rectangle : enable void main(){ gl_TexCoord[0] = gl_MultiTexCoord0; gl_Position = gl_Vertex; }

glsl120.frag

#version 120 #extension GL_ARB_texture_rectangle : enable uniform sampler2D tex; uniform float rawFft[256]; vec4 outputColor; void main(){ if (gl_TexCoord[0].y < 1.0) { int i = int(gl_TexCoord[0].x); outputColor.r = rawFft[i]; } else { vec2 st = gl_TexCoord[0].st; st.y -= 1.0; outputColor.r = texture2D(tex, st).r; } outputColor.a = 1.0; gl_FragColor = outputColor; }

イメージ説明

120に書き換えるとこのようになります。150と同じ結果を得るためにはどうしたら良いでしょうか?

[追記]
渡す頂点座標をgl_Position = gl_Vertex; からgl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;に変えてみたところ、全画面に色が出るようになりました、、
イメージ説明

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

[追記]
字数制限につき別回答で投稿しますが、ちょっと試してみた結果を追記します。下記のような方針でやってみました。

  • 画面サイズはとりあえず256×256とした
  • 前の描画結果をとっておくためのテクスチャを用意する
  • FFT結果はダミーデータで毎フレーム埋める(ご質問者さんの場合は実際のFFT結果を使えるかと思います)
  • 画面全体を覆う四角形を描画...端の一行はFFT結果を使い、残りは前の描画結果を一行ずらして描画する
  • 描画結果をテクスチャにコピーし、次回の描画に備える

ご質問者さんがGLSL 1.20版でうまくいかなかった可能性としては、描画結果を見ますに描画自体は行われているものの、やはり何か位置座標・テクスチャ座標周りで問題があったように思います。

MVP変換については、ご質問者さんのコードの場合どのような変換がかかっているか不確かでしたので、描画する四角形の頂点座標を最初から画面を覆う位置にして、MVP変換不要な状態にすることにしました。

テクスチャ座標についてハマりそうだと思ったのは、GL_TEXTURE_2Dを使うかGL_TEXTURE_RECTANGLEを使うかでテクスチャ座標が変わる点でしょうか。
GL_TEXTURE_2Dの場合は正規化座標...つまり0.0~1.0で指定しますが、GL_TEXTURE_RECTANGLEの場合は非正規化座標...つまり0.0~テクスチャ幅、0.0~テクスチャ高さで指定することになります。この辺の設定でおかしいところはなさそうでしょうか?

バーテックスシェーダー

GLSL

1#version 120 2#extension GL_ARB_texture_rectangle : enable 3 4void main() { 5 gl_TexCoord[0] = gl_MultiTexCoord0; 6 gl_Position = gl_Vertex; 7}

フラグメントシェーダー

GLSL

1#version 120 2#extension GL_ARB_texture_rectangle : enable 3 4// もしGL_ARB_texture_rectangleを使わずにやるとすると、テクスチャは 5// GL_TEXTURE_2Dを使い、UV座標は0.0~1.0で設定し、サンプラー型は 6// sampler2D、サンプリング関数はtexture2Dに変えて、受け取ったUV座標は 7// 適宜256倍してy判定・i算出し、stずらし量は1.0 / 256.0にして...といった 8// 修正を加えることになるでしょう 9 10uniform sampler2DRect tex; // sampler2DRectを使用 11uniform float rawFft[256]; 12 13void main() { 14 vec4 outputColor; 15 16 if (gl_TexCoord[0].y < 1.0) { 17 int i = int(gl_TexCoord[0].x); 18 outputColor.r = rawFft[i]; 19 } else { 20 vec2 st = gl_TexCoord[0].st; 21 st.y -= 1.0; 22 outputColor.r = texture2DRect(tex, st).r; // texture2DRectを使用 23 } 24 outputColor.a = 1.0; 25 26 gl_FragColor = outputColor; 27} 28 29// 上記のコードでは、フレーム毎のFFT結果が下からせり上がってくるかと思います 30// 上から降りてくる方がお好みでしたら、一例としてはy位置判定の際のyを上下反転し、 31// さらにテクスチャサンプリング位置ずらし方向を上下反転する手があるでしょう 32/* 33void main() { 34 vec4 outputColor; 35 float yInverted = 256.0 - gl_TexCoord[0].y; 36 37 if (yInverted < 1.0) { 38 int i = int(gl_TexCoord[0].x); 39 outputColor.r = rawFft[i]; 40 } else { 41 vec2 st = gl_TexCoord[0].st; 42 st.y += 1.0; 43 outputColor.r = texture2DRect(tex, st).r; 44 } 45 outputColor.a = 1.0; 46 47 gl_FragColor = outputColor; 48} 49*/

メインコード

C++

1#include "stdafx.h" 2#include <gl/glew.h> 3#include <GLFW/glfw3.h> 4#include "Renderer.h" 5 6int main(int argc, char ** argv) { 7 // コンソールウィンドウが邪魔なので移動 8 SetWindowPos(GetConsoleWindow(), 0, 640, 0, 0, 0, SWP_NOZORDER | SWP_NOSIZE); 9 10 if (!glfwInit()) { 11 return -1; 12 } 13 // OpenGL 2.1までダウングレードしたかったのですが、私の環境では3.0までが限界のようでした 14 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 15 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); 16 GLFWwindow* mainWindow = glfwCreateWindow(256, 256, "OpenGL Test", NULL, NULL); 17 if (!mainWindow) { 18 glfwTerminate(); 19 return -1; 20 } 21 glfwMakeContextCurrent(mainWindow); 22 23 // 描画ループ 24 Renderer* renderer = new Renderer(); 25 while (!glfwWindowShouldClose(mainWindow)) { 26 // 動作確認をやりやすくするため、スペースキー押下時のみレンダリングするようにしました 27 if (glfwGetKey(mainWindow, GLFW_KEY_SPACE)) { 28 renderer->Render(); 29 glfwSwapBuffers(mainWindow); 30 } 31 glfwPollEvents(); 32 } 33 delete renderer; 34 35 glfwTerminate(); 36 return 0; 37}

Rendererヘッダ

C++

1#pragma once 2#include <gl/glew.h> 3#include <GLFW/glfw3.h> 4#include "Shader.h" 5 6class Renderer { 7private: 8 static const int kBufferSize = 256; 9 10 Shader* m_shader; // 描画に使うシェーダー 11 double m_angle; // ダミーデータ生成に使う 12 GLfloat m_fftBuffer[kBufferSize]; // FFTデータの代替物...これを毎フレーム新しいデータで埋める 13 GLuint m_texLoc; // シェーダー上のtexのuniformロケーション 14 GLuint m_rawFftLoc; // シェーダー上のrawFftのuniformロケーション 15 GLuint m_quadVbo; // ビューポートを覆う四角形の頂点データのVBO...各頂点は位置座標としてfloat×2、テクスチャ座標としてfloat×2を持つ 16 GLuint m_prevFrameTex; // 前回レンダリング時の結果を保管するテクスチャ 17 18 static void CheckGLErrors(); // OpenGLエラーをチェック、エラーがあればエラー出力に表示する 19 static const GLchar* GetShaderSource(WORD resourceId); // リソースとして仕込んだシェーダーファイルからコードを文字列として取り出す 20 21 void Init(); // コンストラクタ内で呼ばれる、レンダリングに先立って一回だけ行う諸々の処理 22 void UpdateFftBuffer(); // Render内の先頭で実行し、m_fftBufferを新しいダミーデータで埋める 23public: 24 Renderer(); 25 ~Renderer(); 26 27 void Render(); // フレームをレンダリングする 28};

Renderer実装

C++

1#include "stdafx.h" 2#include "Renderer.h" 3#include "resource.h" 4#include <iostream> 5 6static const double kPi = 3.141592653589793116; 7static const double kAngularSpeed = 1.0 / 64; 8static const double kWaveScale = 1.0; 9 10Renderer::Renderer() { 11 std::cout << "Hello!" << std::endl; 12 this->Init(); 13} 14 15Renderer::~Renderer() { 16 // 終了前に一応OpenGLオブジェクト類を削除 17 delete m_shader; 18 glDeleteBuffers(1, &m_quadVbo); 19 glDeleteTextures(1, &m_prevFrameTex); 20 std::cout << "Bye!" << std::endl; 21} 22 23void Renderer::Init() { 24 m_angle = 0.0; 25 std::fill_n(m_fftBuffer, std::size(m_fftBuffer), 0.0f); 26 27 // GLEWの初期化 28 GLenum glewError = glewInit(); 29 if (glewError) { 30 std::cerr << "GLEW error: " << glewGetErrorString(glewError) << std::endl; 31 } 32 std::cout 33 << glGetString(GL_VERSION) << std::endl 34 << glGetString(GL_RENDERER) << std::endl 35 << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl; 36 CheckGLErrors(); 37 38 // シェーダーを作成・使用、tex・rawFftのロケーションを取得 39 const GLchar* vertSource = GetShaderSource(IDR_GLSL120VERT); 40 const GLchar* fragSource = GetShaderSource(IDR_GLSL120FRAG); 41 m_shader = new Shader(vertSource, fragSource); 42 m_shader->Use(); 43 m_texLoc = m_shader->GetUniformLoc("tex"); 44 m_rawFftLoc = m_shader->GetUniformLoc("rawFft[0]"); 45 CheckGLErrors(); 46 47 // 頂点データを作成 48 // GLSL 1.50版コードではuniform変数としてMVP行列が渡されていましたが 49 // どのような変換がかかっているか不確かだったため、MVP行列を使わずに 50 // 生の頂点座標で画面全体を覆えるようにしました 51 // テクスチャ座標はtexture2DRectを使う前提の非正規化座標です 52 const int kVertexElementCount = 2 + 2; // 位置座標2要素、テクスチャ座標2要素 53 const GLsizei kVertexSize = kVertexElementCount * sizeof(GLfloat); // 一頂点のデータサイズ 54 GLfloat quadData[4 * kVertexElementCount] = { 55 -1.0f, 1.0f, 0.0f, 256.0f, // 左上隅 56 -1.0f, -1.0f, 0.0f, 0.0f, // 左下隅 57 1.0f, 1.0f, 256.0f, 256.0f, // 右上隅 58 1.0f, -1.0f, 256.0f, 0.0f // 右下隅 59 }; 60 glGenBuffers(1, &m_quadVbo); 61 glBindBuffer(GL_ARRAY_BUFFER, m_quadVbo); 62 glBufferData(GL_ARRAY_BUFFER, sizeof(quadData), quadData, GL_STATIC_DRAW); 63 glEnableClientState(GL_VERTEX_ARRAY); 64 glVertexPointer(2, GL_FLOAT, kVertexSize, reinterpret_cast<const void*>(0)); // 位置座標属性を設定 65 glEnableClientState(GL_TEXTURE_COORD_ARRAY); 66 glTexCoordPointer(2, GL_FLOAT, kVertexSize, reinterpret_cast<const void*>(2 * sizeof(GLfloat))); // テクスチャ座標属性を設定 67 // リファレンスによると、VBOがバインドされている場合は、これら属性設定関数の最後の引数はVBO先頭からのオフセットと解釈されるらしい 68 CheckGLErrors(); 69 70 // テクスチャを作成、メモリ確保は行うがデータ投入は不要 71 glGenTextures(1, &m_prevFrameTex); 72 glBindTexture(GL_TEXTURE_RECTANGLE, m_prevFrameTex); 73 glTexImage2D(GL_TEXTURE_RECTANGLE, 0, GL_RGB8, kBufferSize, kBufferSize, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); 74 // glUniform1i(m_texLoc, 0); // texが参照するテクスチャユニットをGL_TEXTURE0...つまりm_prevFrameTexに設定 75 // texはデフォルトで0になっているはずなので、今回のケースでは上記設定は必須ではない 76 CheckGLErrors(); 77 78 // その他諸々の最初に一度だけ設定すれば十分な事項を設定 79 glViewport(0, 0, kBufferSize, kBufferSize); 80 glClearColor(0.0f, 0.0f, 0.0f, 1.0f); 81 // 画面をクリア、その状態で描画結果をテクスチャにコピーし、テクスチャをまっさらにする 82 glClear(GL_COLOR_BUFFER_BIT); 83 glCopyTexSubImage2D(GL_TEXTURE_RECTANGLE, 0, 0, 0, 0, 0, kBufferSize, kBufferSize); 84 CheckGLErrors(); 85} 86 87void Renderer::Render() { 88 // m_fftBufferを更新、rawFftにデータを投入 89 this->UpdateFftBuffer(); 90 glUniform1fv(m_rawFftLoc, kBufferSize, m_fftBuffer); 91 92 // 領域全体を覆う四角形を描画 93 // glClear(GL_COLOR_BUFFER_BIT); // 画面全体が描き換わるので、画面クリアは必須ではない 94 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 95 96 // 描画結果をバインド中のテクスチャ...つまりm_prevFrameTexにコピー 97 glCopyTexSubImage2D(GL_TEXTURE_RECTANGLE, 0, 0, 0, 0, 0, kBufferSize, kBufferSize); 98} 99 100void Renderer::UpdateFftBuffer() { 101 // m_fftBufferをダミーのデータで満たす 102 // とりあえず時間とともに位相が回るサイン波を用意 103 // 描画結果として斜めの縞模様が描かれることを期待する 104 double phase = (m_angle += kAngularSpeed); 105 float* fftElement = m_fftBuffer; 106 for (int i = 0; i < kBufferSize; i++) { 107 fftElement[i] = static_cast<float>(sin(phase + (2.0 * kPi * i * kWaveScale) / kBufferSize) * 0.5 + 0.5); 108 } 109} 110 111void Renderer::CheckGLErrors() { 112 GLenum error = glGetError(); 113 if (error != GL_NO_ERROR) { 114 std::cerr << gluErrorString(error) << std::endl; 115 } 116} 117 118const GLchar* Renderer::GetShaderSource(WORD resourceId) { 119 return static_cast<const GLchar*>(LockResource(LoadResource(NULL, FindResourceA(NULL, MAKEINTRESOURCEA(resourceId), "GLSL")))); 120}

Shaderヘッダ

C++

1#pragma once 2#include <gl/glew.h> 3#include <GLFW/glfw3.h> 4 5class Shader { 6private: 7 GLuint m_programName; // シェーダープログラム名 8public: 9 Shader(const GLchar* vertSource, const GLchar* fragSource); 10 ~Shader(); 11 12 void Use(); // このシェーダープログラムを使用する 13 GLuint GetUniformLoc(const GLchar* name); // uniform変数名からロケーションを得る 14};

実行結果
プレビュー

C++を使用してみたものの、不慣れでしてコード的にいまいちな部分が多いかと思います。あくまでも描画プロセスの参考程度と言うことでお願いします...

投稿2018/04/22 22:19

Bongo

総合スコア10807

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

動作実験はしていないのですが、GLSL 1.20なら頂点データの受け取りはattribute変数、バーテックス・フラグメントシェーダー間の値の伝達はvarying変数を使った記法となるのではないでしょうか?

GLSL 1.50版では頂点データ供給にVAOやVBOを使用し、MVP行列も自前で計算してuniform変数に投入していたかと思いますが、これらはGLSL 1.50版と同じままにして、シェーダーコードを下記のようにしてみるとどうでしょうか。

バーテックスシェーダー

GLSL

1#version 120 2#extension GL_ARB_texture_rectangle : enable 3 4uniform mat4 modelViewProjectionMatrix; 5 6attribute vec4 position; 7attribute vec2 texcoord; 8 9varying vec2 vTexCoord; 10 11void main(){ 12 vTexCoord = texcoord; 13 gl_Position = modelViewProjectionMatrix * position; 14}

フラグメントシェーダー

GLSL

1#version 120 2#extension GL_ARB_texture_rectangle : enable 3 4uniform sampler2DRect tex; 5uniform float rawFft[256]; 6 7varying vec2 vTexCoord; 8 9void main(){ 10 vec4 outputColor; 11 12 if (vTexCoord.y < 1.0) { 13 int i = int(vTexCoord.x); 14 outputColor.r = rawFft[i]; 15 } else { 16 vec2 st = vTexCoord.st; 17 st.y -= 1.0; 18 outputColor.r = texture2DRect(tex, st).r; 19 } 20 outputColor.a = 1.0; 21 22 gl_FragColor = outputColor; 23}

参考:The OpenGL® Shading Language Language Version: 1.20 Document Revision: 8 07-Sept-2006

[追記]
後で気付いたのですが、ご提示のGLSL 1.20版コードではMVP変換を行っていない頂点座標を後段に送っているようですね。この違いが原因だとすると、渡す頂点座標をgl_Position = gl_Vertex;からgl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;に変えてみるというのも試す価値がありそうです。
なにぶん生のOpenGLをいじるのはご無沙汰でして、他にも見落としがあるかもしれません。もし「この部分も怪しそうだがどう思うか」などお気付きの点があればぜひご指摘ください。

投稿2018/04/20 21:32

編集2018/04/20 23:45
Bongo

総合スコア10807

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

santaro

2018/04/21 03:09 編集

参考にさせていただき、実装してみましたが、動きませんでした、、、 さきほど元質問に追記しましたが、画像のように右下ではなく全画面に色がつくようにはなりました、
Bongo

2018/04/21 03:58

異常動作の原因として他にありそうなのは、元コードのglsl120.fragでoutputColorをグローバルスコープで宣言し、しかもそれをmain内で書き換えようとしている点かもしれません。 「vec4 outputColor;」の位置を「void main(){」と「if (gl_TexCoord[0].y < 1.0) {」の間の行に移動して、outputColorをローカル変数にしてみるとどうなるでしょうか。 もしこれでもダメな場合、次に気になるのはCPU側のコード(glDraw~などの描画コマンドや、行列をOpenGLに渡す処理を記述している方のコード)ですね。こちらはGLSL 1.50の場合と1.20の場合で何か書き換えをしているでしょうか? もし書き換えている場合は、それら1.50用コードと1.20用コードも見てみたいです。1.50用コードをそれと同等な1.20用コードに書き換える際に、何かミスをしてしまったという可能性はないでしょうか?
santaro

2018/04/21 04:57

教えていただいた通りoutputColorをローカル変数にしてみましたが同じく変わりませんでした。 CPU側で変更したのは、シェーダーの参照先(パス)と使うOpenGLを2.1に変更しただけなので、、何回も見直しましたがミスはないはずです、、
Bongo

2018/04/21 07:19

うーん、今はちょっとプログラミングできる環境が手元にないのですが、後で私もOpenGL 2.1の範囲内のコードを書いてみて実験してみたいと思います。実際にやってみれば問題点の手がかりがつかめるかもしれません。 なるべくご質問者さんと近い条件でやってみたいので確認したいのですが、そのGLSL 1.20用のCPU側コードでは「glBeginやglEndを使っている箇所はない」、「glMatrixModeやglLoadIdentity、glPushMatrix、glTranslatedなど行列操作系関数を使っている箇所もない」、「glGenBuffers、glBindBuffer、glBufferDataやglVertexAttribPointerを使っている箇所がある」ということでいいでしょうか?
Bongo

2018/04/21 07:27

もう一つ確認しますが、 #version 120 #extension GL_ARB_texture_rectangle : enable uniform mat4 modelViewProjectionMatrix; void main(){ gl_TexCoord[0] = gl_MultiTexCoord0; gl_Position = modelViewProjectionMatrix * gl_Vertex; } という風に、1.50版と同じようにMVP行列をuniform変数として渡すというパターンはすでに試されたでしょうか。もしCPU側コードで行列操作系関数を使っていないのであれば、これも原因の可能性として怪しく思えてきました。
santaro

2018/04/21 07:34

ありがとうございます! そうです、行列操作系の関数は使用しておらず、「glGenBuffers、glBindBuffer、glBufferDataやglVertexAttribPointer」は使用しています。 MVP行列をuniform変数として渡すパターンもすでに試していますが、効果なしでした、、!
Bongo

2018/04/22 22:24

試した結果を別回答に書きました。ご質問者さんの場合と比べてみて、怪しそうな所を見つける手がかりになりますでしょうか? コードはC++を選びましたが、すみませんがC++の知識不足で変なコードになっている可能性が高いです。ご容赦ください...
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問