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

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

新規登録して質問してみよう
ただいま回答率
86.02%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

OpenGL

OpenGLは、プラットフォームから独立した、デスクトップやワークステーション、モバイルサービスで使用可能な映像処理用のAPIです。

Q&A

解決済

OpenTKを使用したシャドウマッピングの実装が上手く動かない

Rei_312
Nauclhlt

総合スコア24

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

OpenGL

OpenGLは、プラットフォームから独立した、デスクトップやワークステーション、モバイルサービスで使用可能な映像処理用のAPIです。

1回答

0グッド

0クリップ

882閲覧

投稿2022/04/10 07:35

前提

OpenTKとC#を使用してOpenGLの勉強をしています。
こちらのサイト(https://learnopengl.com/Advanced-Lighting/Shadows/Shadow-Mapping)を参考にしながらシャドウマッピングを実装しようとしているのですが、このサイトでは、C/C++を使用して説明されているので、C#とOpenTKの仕様に合わせて書き換える必要があると思います。
自分で以下のコードを書いたのですが、うまく動きません。
どなたか間違えている箇所を指摘していただきたいです。

該当のソースコード

C#

1 2private int _depthMapFramebuffer = -1; 3private int _depthMapTexture = -1; 4void ShadowMap( Vector3 lightPosition, Vector3 lightTarget, Action drawFunction, Action<ShaderProgram> shaderSetting ) 5{ 6 const int shadowWidth = 1024; 7 const int shadowHeight = 1024; 8 9 //フレームバッファが生成されていなかったら生成する 10 if ( _depthMapFramebuffer == -1 ) 11 { 12 _depthMapFramebuffer = GL.GenFramebuffer(); 13 } 14 15 //テクスチャが生成されていなかったら生成してフレームバッファに設定 16 if ( _depthMapTexture == -1 ) 17 { 18 _depthMapTexture = GL.GenTexture(); 19 GL.BindTexture( TextureTarget.Texture2D, _depthMapTexture ); 20 GL.TexImage2D( TextureTarget.Texture2D, 0, PixelInternalFormat.DepthComponent, shadowWidth, shadowHeight, 0, PixelFormat.DepthComponent, PixelType.Float, IntPtr.Zero ); 21 GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest); 22 GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Nearest); 23 GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat); 24 GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat); 25 26 GL.BindFramebuffer( FramebufferTarget.Framebuffer, _depthMapFramebuffer ); 27 GL.FramebufferTexture2D( FramebufferTarget.Framebuffer, FramebufferAttachment.DepthAttachment, TextureTarget.Texture2D, _depthMapTexture, 0 ); 28 GL.DrawBuffer(DrawBufferMode.None); 29 GL.ReadBuffer(ReadBufferMode.None); 30 GL.BindFramebuffer( FramebufferTarget.Framebuffer, 0 ); 31 GL.BindTexture( TextureTarget.Texture2D, 0 ); 32 } 33 34 //フレームバッファをバインドしてビューポートを深度マップのサイズに変更 35 GL.BindFramebuffer( FramebufferTarget.Framebuffer, _depthMapFramebuffer ); 36 GL.Viewport( 0, 0, shadowWidth, shadowHeight ); 37 //深度バッファをクリア 38 GL.Clear( ClearBufferMask.DepthBufferBit ); 39 40 //正射影の射影行列を作成 41 float near = 0.5f, far = 1200f; 42 Matrix4 projection = Matrix4.CreateOrthographicOffCenter( -Window.Width / 2, Window.Width / 2, -Window.Height / 2, Window.Height / 2, near, far ); 43 //ビュー行列を作成 44 Matrix4 view = Matrix4.LookAt( lightPosition, lightTarget, new Vector3( 0, 1, 0 ) ); 45 46 47 depthMapShader.Use(); 48 //行列を転置してシェーダーに渡す 49 depthMapShader.SetUniform( "lightView", true, view ); 50 depthMapShader.SetUniform( "lightProj", true, projection ); 51 52 //深度マップに描画 53 drawFunction(); 54 55 //フレームバッファのバインドを解除してビューポートをもとに戻す 56 GL.BindFramebuffer( FramebufferTarget.Framebuffer, 0 ); 57 GL.Viewport( 0, 0, Window.Width, Window.Height ); 58 59 shadowLightingShader.Use(); 60 //行列を転置してシェーダーに渡す 61 shadowLightingShader.SetUniform( "lightView", true, view ); 62 shadowLightingShader.SetUniform( "lightProj", true, projection ); 63 64 //通常の行列をシェーダーにわたす 65 SendMatricesToShader(); 66 67 //深度マップをバインド 68 GL.ActiveTexture( TextureUnit.Texture1 ); 69 GL.BindTexture( TextureTarget.Texture2D, _depthMapTexture ); 70 71 //テクスチャの位置を渡す 72 shadowLightingShader.SetUniform( "shadowMap", 1 ); 73 74 //シェーダーの設定をする関数を呼び出す 75 shaderSetting( shadowLightingShader ); 76 77 //描画 78 drawFunction(); 79 80 //テクスチャのバインドを解除 81 GL.BindTexture(TextureTarget.Texture2D, 0); 82 GL.ActiveTexture(TextureUnit.Texture0); 83}

深度マップに書き込むシェーダー(depthMapShader):

バーテックスシェーダー:

GLSL

1#version 430 2 3layout ( location = 0 ) uniform mat4 modelMatrix; 4layout ( location = 1 ) uniform mat4 viewMatrix; 5layout ( location = 2 ) uniform mat4 projMatrix; 6layout ( location = 3 ) uniform mat4 lightView; 7layout ( location = 4 ) uniform mat4 lightProj; 8 9layout ( location = 0 ) in vec3 position; 10 11void main() 12{ 13 //行列の乗算の順序を反転 14 gl_Position = vec4(position, 1.0) * modelMatrix * lightView * lightProj; 15}

フラグメントシェーダー:

GLSL

1#version 430 2 3void main() 4{ 5 //何も書かなくて良い 6}

ライティングと影の処理をするシェーダー(shadowLightingShader):
バーテックスシェーダー:

GLSL

1#version 430 2precision mediump float; 3 4layout ( location = 0 ) uniform mat4 modelMatrix; 5layout ( location = 1 ) uniform mat4 viewMatrix; 6layout ( location = 2 ) uniform mat4 projMatrix; 7layout ( location = 3 ) uniform mat4 lightView; 8layout ( location = 4 ) uniform mat4 lightProj; 9 10layout ( location = 0 ) in vec3 position; 11layout ( location = 1 ) in vec4 color; 12layout ( location = 2 ) in vec3 normal; 13layout ( location = 3 ) in vec2 texCoord; 14 15out vec4 vColor; 16out vec3 vFragPosition; 17out vec3 vNormal; 18out vec2 vTexCoord; 19out vec4 vFragPosLightSpace; 20 21void main() 22{ 23 vFragPosition = vec3(vec4(position, 1.0) * modelMatrix); 24 //ライトから見た位置 25 vFragPosLightSpace = vec4(position, 1.0) * modelMatrix * lightView * lightProj; 26 vColor = color; 27 vNormal = normal; 28 vTexCoord = texCoord; 29 gl_Position = vec4(position, 1.0) * modelMatrix * viewMatrix * projMatrix; 30}

フラグメントシェーダー:

GLSL

1#version 430 2precision mediump float; 3 4in vec4 vColor; 5in vec3 vFragPosition; 6in vec3 vNormal; 7in vec2 vTexCoord; 8in vec4 vFragPosLightSpace; 9 10//ライティングに関する設定 11#define MAX_LIGHTS 32; 12uniform int lightCount = MAX_LIGHTS; 13uniform vec3 lightPositions[32]; 14uniform float lightPowers[32]; 15uniform vec3 lightColors[32]; 16uniform float lightRadius[32]; 17uniform float ambientPower; 18uniform vec3 objectColor; 19uniform vec3 ambientColor; 20uniform vec3 emissiveColor; 21uniform vec3 viewPos; 22uniform vec3 directionalColor; 23uniform vec3 directionalDir; 24uniform vec3 directionalPower; 25 26uniform sampler2D shadowMap; //深度マップ 27 28out vec4 fragColor; 29 30//影を計算する関数 31float GetShadow() 32{ 33 vec3 projCoords = vFragPosLightSpace.xyz / vFragPosLightSpace.w; 34 projCoords = projCoords * 0.5 + 0.5; 35 float closestDepth = texture(shadowMap, projCoords.xy).r; 36 float currentDepth = projCoords.z; 37 vec3 normal = normalize(vNormal); 38 float bias = 0.05f; 39 float shadow = 0.0; 40 vec2 texelSize = 1.0 / textureSize(shadowMap, 0); 41 for(int x = -1; x <= 1; ++x) 42 { 43 for(int y = -1; y <= 1; ++y) 44 { 45 float pcfDepth = texture(shadowMap, projCoords.xy + vec2(x, y) * texelSize).r; 46 shadow += currentDepth - bias > pcfDepth ? 1.0 : 0.0; 47 } 48 } 49 shadow /= 9.0; 50 if(projCoords.z > 1.0) 51 shadow = 0.0; 52 53 return shadow; 54} 55 56void main() 57{ 58 //ライティング 59 vec3 ambient = ambientPower * ambientColor; 60 61 vec3 totalDiffuse = vec3(0); 62 63 vec3 norm = normalize(vNormal); 64 for ( int i = 0; i < lightCount; i++ ) 65 { 66 float radius = lightRadius[i]; 67 float dist = distance(vFragPosition, lightPositions[i]); 68 float att = clamp(1.0 - dist/radius, 0.0, 1.0); 69 att *= att; 70 float diffuseStrength = lightPowers[i]; 71 vec3 lightDirection = normalize(lightPositions[i] - vFragPosition); 72 float diff = max(dot(norm, lightDirection), 0.0); 73 vec3 diffuse = att * (diffuseStrength * diff) * lightColors[i]; 74 totalDiffuse += diffuse; 75 } 76 77 vec3 didir = normalize(directionalDir); 78 float d = max(dot(norm, didir), 0.0); 79 totalDiffuse += (directionalPower * d) * directionalColor; 80 81 //影を考慮した結果を計算 82 float shadow = GetShadow(); 83 vec3 result = (ambient + (1.0 - shadow) * totalDiffuse) * vColor.rgb + emissiveColor; 84 fragColor = vec4(result, vColor.a); 85}

ShadowMapメソッドの呼び出し:

C#

1//描画ループの中 2 3Action draw = () =>{ 4 //四角形を2つ描画する 5 float[] va = new float[] 6 { 7 -512, 0, -512, 8 -512, 0, -512 + 1024, 9 -512 + 1024, 0, -512, 10 -512 + 1024, 0, -512 + 1024 11 }; 12 13 float[] ca = new float[] 14 { 15 1f, 0f, 0f, 1f, 16 1f, 0f, 0f, 1f, 17 1f, 0f, 0f, 1f, 18 1f, 0f, 0f, 1f, 19 }; 20 21 float[] na = new float[] 22 { 23 0f, 1f, 0f, 24 0f, 1f, 0f, 25 0f, 1f, 0f, 26 0f, 1f, 0f 27 }; 28 29 30 GL.EnableVertexAttribArray(0); 31 GL.EnableVertexAttribArray(1); 32 GL.EnableVertexAttribArray(2); 33 34 GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, 0, va); 35 GL.VertexAttribPointer(1, 4, VertexAttribPointerType.Float, false, 0, ca); 36 GL.VertexAttribPointer(2, 3, VertexAttribPointerType.Float, false, 0, na); 37 38 GL.DrawArrays(PrimitiveType.TriangleStrip, 0, 4); 39 40 GL.DisableVertexAttribArray(0); 41 GL.DisableVertexAttribArray(1); 42 GL.DisableVertexAttribArray(2); 43 44 va = new float[] 45 { 46 x, y, z, 47 x, y - height, z, 48 x + width, y, z, 49 x + width, y - height, z 50 }; 51 52 ca = new float[] 53 { 54 1f, 1f, 1f, 1f, 55 1f, 1f, 1f, 1f, 56 1f, 1f, 1f, 1f, 57 1f, 1f, 1f, 1f, 58 }; 59 60 na = new float[] 61 { 62 0f, 0f, 1f, 63 0f, 0f, 1f, 64 0f, 0f, 1f, 65 0f, 0f, 1f, 66 }; 67 68 GL.EnableVertexAttribArray(0); 69 GL.EnableVertexAttribArray(1); 70 GL.EnableVertexAttribArray(2); 71 72 GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, 0, va); 73 GL.VertexAttribPointer(1, 4, VertexAttribPointerType.Float, false, 0, ca); 74 GL.VertexAttribPointer(2, 3, VertexAttribPointerType.Float, false, 0, na); 75 76 GL.DrawArrays(PrimitiveType.TriangleStrip, 0, 4); 77 78 GL.DisableVertexAttribArray(0); 79 GL.DisableVertexAttribArray(1); 80 GL.DisableVertexAttribArray(2); 81 82}; 83ShadowMap( _cameraPosition, new Vector3( 0, 0, 0 ), draw, () => {} );

試したこと

参考にしたサイトにあった方法で、深度マップを画面に描画してみたところ、正しい結果が得られているようでした。
イメージ1
イメージ2

以下のような質問にはグッドを送りましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

グッドが多くついた質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

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

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

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

下記のような質問は推奨されていません。

  • 間違っている
  • 質問になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

適切な質問に修正を依頼しましょう。

回答1

0

自己解決

行列の計算部分にGlmSharpライブラリを使用して行い、uniform変数に設定する際の転置をfalseにすると解決しました。

投稿2022/04/12 08:00

Rei_312

総合スコア24

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

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

ただいまの回答率
86.02%

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

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

質問する

関連した質問

同じタグがついた質問を見る

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

OpenGL

OpenGLは、プラットフォームから独立した、デスクトップやワークステーション、モバイルサービスで使用可能な映像処理用のAPIです。