2013-01-15 42 views
2

我在MonoTouch中使用OpenTK在iOS中渲染一些紋理,並且一些紋理出現破裂。這是iPad的屏幕截圖顯示一個正確呈現質感(最上面的一個),並低於二級破碎者的特寫:在iOS中破損的紋理

broken texture

我沒有做任何事情奇怪。我使用CGImage - >CGBitmapContext - >GL.TexImage2D從半透明PNG加載紋理。我使用兩個三角形渲染每個精靈,而我的片段着色器僅從texture2D()採樣器中讀取紋理元素,並將其乘以uniform vec4以爲紋理着色。

自己似乎是好這些文件,並使用單聲道的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); 

即三角形帶由出兩個三角形組成的質感,與頂點和紋理座標中設置的地方,我想表明我的精靈。 projectionMatrix是一個簡單的直接投影矩陣。

正如你所看到的,我並不想在這裏做任何事情。這是所有非常標準的代碼,它適用於某些紋理,所以我認爲通常代碼是可以的。我在Android的Mono中也做了幾乎相同的事情,並且它工作得很好,沒有任何紋理損壞。

損壞的顏色一樣,那味道像某處未初始化的變量,並看到它發生僅在透明部分使我相信,我有地方未初始化的alpha值。然而,GL.Clear(ClearBufferMask.ColorBufferBit)應清除我的alpha值,即使如此,背景紋理的alpha值爲1,並且當前BlendFunc應將這些像素的alpha設置爲1.之後,透明紋理的alpha值範圍爲0到1,所以他們應該適當地混合。我在任何地方都看不到未初始化的變量。

......或者......這是CGBitmapContext所有的過錯。也許通過做DrawImage,我不是blitting源圖像,而是使用混合繪製它,而垃圾數據來自AllocGlobal。這並不能解釋爲什麼它始終只有這兩個質地發生,但...(我這個標記爲核心的顯卡,所以也許石英人可以幫之一)

讓我知道如果你想看到一些更多的代碼。

+0

看到一些代碼可能會幫助人們告訴你/如果事情可能出錯。 – poupou

+0

@poupou我想我解釋什麼,怎麼我做的,我相信這是比較有用的不僅僅是複製粘貼一段代碼長列表,但肯定的是,我可以張貼一些代碼。 –

+0

我猜你正在用'CGBitmapContext'在正確的軌道上。它沒有被默認清除。我相信,你需要確保你在繪製精靈之前用透明黑色填充它。 – user1118321

回答

1

好吧,這只是我的預期。我Marshal.AllocHGlobal獲取內存未初始化到任何東西,只是CGBitmapContext.DrawImage呈現上的無論是在範圍內,這是垃圾頂部的圖像。

所以解決這個問題的方法是在撥打context.DrawImage()之前插入一個context.ClearRect()呼叫。

我不知道爲什麼它工作得很好與其他(較大)的紋理,但也許這是因爲在這種情況下,我要求一個大的內存塊,所以iOS版(或單)內存管理得到了新的零區塊,而對於較小的紋理,我重複使用先前釋放的內存,這些內存尚未歸零。

如果在使用調試堆時將內存分配給像0xBAADF00D這樣的內存會很好,就像在Windows API中使用LocalAlloc一樣。其他

兩個有點相關的東西要記住:

  1. 在我發佈的代碼,我不釋放與AllocHGlobal請求的內存。這是一個錯誤。 GL.TexImage2D將紋理複製到VRAM,因此在其中釋放它是安全的。

  2. context.DrawImage被繪製的圖像,進入新的情境(而不是讀取從圖像的原始像素),和核芯顯卡預乘阿爾法作品(我覺得這白癡)。所以如果我這樣做,加載的紋理將始終加載預乘alpha。這意味着我還必須將alpha混合函數更改爲GL.BlendFunc(BlendingFactorSrc.One, BlendingFactorDest.OneMinusSrcAlpha),並確保所有交叉淡入淡出代碼在整個RGBA上工作,而不僅僅是alpha值。

+1

取決於你如何解釋'0xbaadf00d',它可能是幾乎透明的,這將使難的問題被發現,但所有最眼尖的用戶。初始化爲'0xff0000ff'會更好:不透明的紅色或不透明的藍色,並且不可能錯過任何一種方式。 –

+1

這就是說,[Xcode中確實有一個選項,以打開塗鴉](http://developer.apple.com/library/ios/recipes/xcode_help-scheme_editor/Art/scheme_diagnostics.png),其使用'0xaa'( '0xaaAAaaAA'),這將是半透明的灰色或白色,但其他工作幾乎一樣。 –