2

私はMonoTouchのOpenTKを使用してiOSでいくつかのテクスチャをレンダリングしていますが、いくつかのテクスチャが壊れています。これはiPadのスクリーンショットのクローズアップで、正しくレンダリングされた1つのテクスチャ(上のテクスチャ)と下の2つの壊れたテクスチャを示しています。

壊れたテクスチャ

私は変なことは何もしていません。CGImage-> CGBitmapContext->を使用して、半透明のPNGからテクスチャをロードしていGL.TexImage2Dます。各スプライトを2つの三角形でレンダリングしています。フラグメントシェーダーは、サンプラーからテクセルを読み取り、texture2D()それをaで乗算してuniform vec4、テクスチャに色を付けます。

ファイル自体は問題ないようで、Mono for Androidを使用する同じアプリケーションのAndroidポート、およびまったく同じバイナリリソースがファイルを完全にレンダリングします。ご覧のとおり、他の透明なテクスチャは問題なく機能します。

それが役に立ったら、シミュレータでプログラムを実行すると、ほとんどすべてのテクスチャが壊れます。また、プログラムを再構築してもこの問題は解決しません。

この問題の原因を突き止める方法について何かアイデアはありますか?

これが私の頂点シェーダーです:

attribute vec4 spritePosition;
attribute vec2 textureCoords;
uniform mat4 projectionMatrix;
uniform vec4 color;

varying vec4 colorVarying;
varying vec2 textureVarying;

void main()
{
    gl_Position = projectionMatrix * spritePosition;
    textureVarying = textureCoords;

    colorVarying = color;
}

これが私のフラグメントシェーダーです:

varying lowp vec4 colorVarying;
varying lowp vec2 textureVarying;
uniform sampler2D spriteTexture;

void main()
{
    gl_FragColor = texture2D(spriteTexture, textureVarying) * colorVarying;
}

私はこのように画像をロードしています:

using (var bitmap = UIImage.FromFile(resourcePath).CGImage)
{
    IntPtr pixels = Marshal.AllocHGlobal(bitmap.Width * bitmap.Height * 4);
    using (var context = new CGBitmapContext(pixels, bitmap.Width, bitmap.Height, 8, bitmap.Width * 4, bitmap.ColorSpace, CGImageAlphaInfo.PremultipliedLast))
    {
        context.DrawImage(new RectangleF(0, 0, bitmap.Width, bitmap.Height), bitmap);
        int[] textureNames = new int[1];
        GL.GenTextures(1, textureNames);
        GL.BindTexture(TextureTarget.Texture2D, textureNames[0]);
        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear);
        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear);
        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)All.ClampToEdge);
        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)All.ClampToEdge);
        GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, bitmap.Width, bitmap.Height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, pixels);
        CurrentResources.Add(resourceID, new ResourceData(resourcePath, resourceType, 0, new TextureEntry(textureNames[0], bitmap.Width, bitmap.Height)));
    }
}

私のonRenderFrameには、次のものがあります。

GL.ClearColor(1.0f, 1.0f, 1.0f, 1.0f);
GL.Clear(ClearBufferMask.ColorBufferBit);
GL.Enable(EnableCap.Blend);
GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
GL.UseProgram(RenderingProgram);
GL.VertexAttribPointer((int)ShaderAttributes.SpritePosition, 2, VertexAttribPointerType.Float, false, 0, squareVertices);
GL.VertexAttribPointer((int)ShaderAttributes.TextureCoords, 2, VertexAttribPointerType.Float, false, 0, squareTextureCoords);
GL.EnableVertexAttribArray((int)ShaderAttributes.SpritePosition);
GL.EnableVertexAttribArray((int)ShaderAttributes.TextureCoords);
//...
GL.ActiveTexture(TextureUnit.Texture0);
GL.BindTexture(TextureTarget.Texture2D, textureEntry.TextureID);
GL.Uniform1(Uniforms[(int)ShaderUniforms.Texture], 0);
// ...    
GL.DrawArrays(BeginMode.TriangleStrip, 0, 4);

その三角ストリップは、テクスチャを構成する2つの三角形で構成されており、頂点とテクスチャの座標がスプライトを表示する場所に設定されています。projectionMatrixは単純なオルトグラフィック射影行列です。

ご覧のとおり、私はここで特別なことをしようとはしていません。これはすべてかなり標準的なコードであり、一部のテクスチャでも機能するので、一般的にコードは問題ないと思います。私はMonoforAndroidでもほぼ同じことを行っており、テクスチャが破損することなく非常にうまく機能します。

そのような破損した色は、どこかで初期化されていない変数のようなにおいがします。それが透明な部分でのみ発生するのを見ると、どこかに初期化されていないアルファ値があると思います。ただし、GL.Clear(ClearBufferMask.ColorBufferBit)アルファ値をクリアする必要があります。それでも、背景テクスチャのアルファ値は1であり、現在のBlendFunc場合、これらのピクセルのアルファを1に設定する必要があります。その後、透明テクスチャのアルファ値は0から1の範囲になります。 、適切にブレンドする必要があります。初期化されていない変数はどこにも見当たりません。

...または...これはすべてのせいですCGBitmapContext。たぶん、を実行することDrawImageで、ソースイメージをブリット化するのではなく、代わりにブレンディングで描画します。ガベージデータは、作成したときのものですAllocGlobal。これは、なぜこれら2つのテクスチャだけで一貫して発生するのかを説明していません...(私はこれをコアグラフィックとしてタグ付けしているので、クォーツの人の1人が助けることができます)

さらにコードを見たい場合はお知らせください。

4

1 に答える 1

1

さて、それは私が期待した通りです。私が取得したメモリMarshal.AllocHGlobalは何にも初期化されておらずCGBitmapContext.DrawImage、コンテキスト内にあるものの上に画像をレンダリングするだけです。これはゴミです。

context.ClearRect()したがって、これを修正する方法は、を呼び出す前に呼び出しを挿入することcontext.DrawImage()です。

他の(より大きな)テクスチャでうまく機能した理由はわかりませんが、その場合は、メモリの大きなブロックを要求しているため、iOS(またはモノラル)メモリマネージャが新しいゼロ化されたブロックを取得します。小さいテクスチャの場合は、以前に解放された、ゼロ化されていないメモリを再利用しています。

Windows APIの場合のよう0xBAADF00Dに、デバッグヒープを使用する場合のように、メモリが割り当てられていると便利です。LocalAlloc

覚えておくべき他の2つのやや関連すること:

  1. 私が投稿したコードでは、で要求されたメモリを解放していませんAllocHGlobal。これはバグです。GL.TexImage2DテクスチャをVRAMにコピーするので、その場で安全に解放できます。

  2. context.DrawImageは(画像から生のピクセルを読み取るのではなく)新しいコンテキストに画像を描画し、Core Graphicsは事前に乗算されたアルファ(私はばかげていると思います)でのみ機能します。したがって、この方法で行うと、ロードされたテクスチャは常に事前に乗算されたアルファでロードされます。つまり、アルファブレンディング関数もに変更しGL.BlendFunc(BlendingFactorSrc.One, BlendingFactorDest.OneMinusSrcAlpha)、すべてのクロスフェードコードがアルファ値だけでなくRGBA全体で機能することを確認する必要があります。

于 2013-01-19T08:33:11.227 に答える