2014-09-13 2 views
2

C#에서 OpenTK를 통해 OpenGL을 사용하고 있으며 일반 비트 맵에서 텍스처를로드하려고합니다. 내 드라이버는 NPOT 텍스처를 지원하지 않으므로 GLTexImage2D와 함께 POT 텍스처를 할당하고 GL.TexSubImage2D를 통해 내 비트 맵을 채 웁니다. 그러나 그 텍스트를 그리는 동안 유물이 있습니다. 텍스처의 아래쪽과 오른쪽에 추가 픽셀을 그립니다. 비율에서 픽셀을 뺍니까 아니면 잘못된 것이 있습니까? 창작NPOT 텍스처에 OpenGL GL.TexSubImage2D를 사용하면 아티팩트가 발생합니다.

번호 : 드로잉

GL.BindTexture(TextureTarget.Texture2D, t.Name); 

GL.PixelStore(PixelStoreParameter.PackAlignment, 1); 
GL.PixelStore(PixelStoreParameter.UnpackAlignment, 1); 
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, texture.W2, texture.H2, 0, PixelFormat.Bgra, PixelType.UnsignedByte, IntPtr.Zero); 
GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, texture.DataSize.Width, texture.DataSize.Height, PixelFormat.Bgra, PixelType.UnsignedByte, data); 

GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.ClampToEdge); 
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToEdge); 
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear); 
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.LinearMipmapLinear); 
GL.Ext.GenerateMipmap(GenerateMipmapTarget.Texture2D); 

GL.BindTexture(TextureTarget.Texture2D, 0); 

번호 :

GL.BindTexture(TextureTarget.Texture2D, t.Name); 

float x1 = 0; 
float x2 = texture.WidthRatio; 
float y1 = 0; 
float y2 = texture.HeightRatio; 

float rx1 = rect.X; 
float rx2 = rect.X + rect.W; 
float ry1 = rect.Y; 
float ry2 = rect.Y + rect.H; 

GL.Begin(BeginMode.Quads); 

GL.TexCoord2(x1, y1); 
GL.Vertex3(rx1, ry1, rect.Z + CGraphics.ZOffset); 

GL.TexCoord2(x1, y2); 
GL.Vertex3(rx1, ry2, rect.Z + CGraphics.ZOffset); 

GL.TexCoord2(x2, y2); 
GL.Vertex3(rx2, ry2, rect.Z + CGraphics.ZOffset); 

GL.TexCoord2(x2, y1); 
GL.Vertex3(rx2, ry1, rect.Z + CGraphics.ZOffset); 

GL.End(); 

GL.Disable(EnableCap.Blend); 
GL.BindTexture(TextureTarget.Texture2D, 0); 

어디 texture.WidhtRatio = DataSize.Width/W2;

답변

1

이것은 모두 텍스처링의 엣지 케이스와 관련이 있습니다.

  1. 필터링 (무슨 일이 텍셀 사이에 발생)

    • 에게 가장 가까운는
    • 선형

    의 차이가있을 수 있습니다 : 먼저 GL의 질감을 볼 때, 대부분의 튜토리얼은 다음과 같은 소개 아래 이미지에서 볼 수 있습니다. (텍스처 경계 한 후 무엇을)

  2. 랩 모드

    주 텍스처 좌표는 (1)에 외부 -1하지 않더라도 색의 포장 - - 선형 필터링과 반복 포장 모드의 조합.

중요한 다른 말은 픽셀과 텍셀의 중간에 샘플이 놓여 있다는 것입니다. 그래서 gl_FragCoord.xy은 항상 분수가 .5입니다 (멀티/슈퍼 샘플링 등을 얻을 때까지). 이것은 아래 이미지에서 볼 수 있습니다. 나는 이것이 문제가있는 곳이라고 생각한다.주변 픽셀의 보간 (예 : x+0.5 ~ x+width-0.5)을 피하기 위해 텍스처의 인세 트를 샘플링하기 위해 텍스처 좌표를 조정할 수 있습니다.


밉맵

enter image description here

때문에 단순히 좌표가 작동하지 않습니다 변화, 더 큰 영역에서 색상을 포함합니다. GL_CLAMP_TO_EDGE의 동작을 다시 만들려면 실제로 하위 이미지 테두리를 수동으로 돌출시켜야합니다. 또는 업로드하기 전에 텍스처를 지우는 것이 훨씬 간단합니다. 내가 다음 하위 이미지와 원하는 국경 쿼드을 그립니다 서브 이미지를 업로드 할 것

glGenFramebuffers(1, &fbo); 
glBindFramebuffer(GL_FRAMEBUFFER, fbo); 
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); 
glClear(GL_COLOR_BUFFER_BIT); 
glBindFramebuffer(GL_FRAMEBUFFER, 0); 
//glDeleteFramebuffers(1, &fbo); 

한 단계 더 나아가 질감을 돌출하기 : 빠른 방법은 FBO 및 glClear에 질감을 연결하는 것입니다 . 프래그먼트 셰이더에서는 서브 이미지 내부의 픽셀을 버리고 문자 그대로 coord = clamp(coord, imageMin, imageMax)을 호출합니다. 더블 버퍼링을 피하려면 read while drawing. 여러 개의 하위 이미지가있는 경우 여기에 z 버퍼를 사용하고 쿼드 대신 사각 피라미드를 그릴 수 있으므로 깊이 테스트가 하위 이미지까지만 가능합니다 (drawing voronoi cells with cones)

+0

+1 정말 좋은 설명. 그러나 문제는 축소 된 텍스처 그리기를위한 밉맵입니다. 어떤 해결책이 있습니까? – Flamefire

+0

@Flamefire 텍스처의 내용에 달려 있다고 생각합니다. 알파 또는 배경색으로 먼저 지울 수 있습니다 (FBO + glClear로 빠름). 그렇지 않다면, RetoKoradi가 말했듯이 국경을 더하는 것이 더 나을 수도 있습니다. 처음 몇 개의 밉맵 레벨 만 사용하면 테두리가 작아 질 수 있습니다. 또한 속도를 높이기 위해 조각 쉐이더에서 생성 할 수도 있습니다. – jozxyqk

+0

이것을 달성하기 위해 FBO를 사용하는 방법에 대한 링크를 제공해 주시겠습니까? – Flamefire

1

바이 리니어 필터링을 사용하면 마지막 열과 행이 초기화되지 않은 텍스처 데이터 (따라서 아티팩트)로 보간됩니다.

bilinear 필터링을 사용하려는 경우 텍스처 데이터 텍스처의 마지막 행과 마지막 열을 복제하면됩니다. 즉, NPOT 텍스처가 800x600 인 경우 마지막 열/행이 복제 된 801x601 픽셀을 업로드하십시오.

이렇게하면 마지막 행/열에 대한 보간이 예상 결과를 반환하고 아티팩트가 사라집니다.

편집 : Reto Koradi가 제안했듯이 이것은 밉맵을 사용하지 않는 경우에만 작동합니다. 밉맵을 사용하고 있는데 특히 이방성 필터링을 사용하는 경우 빈 열의 모든 영역을 마지막 열/행으로 채워야합니다.

+0

나는 원래이 질문을 보았을 때 이것을 생각했다. 한 행/열을 복제하는 것으로는 충분하지 않다고 생각합니다. 가장 낮은 밉맵 만 사용되는 한이 기능이 작동합니다. 그러나 더 높은 밉맵 레벨에서는 더 많은 초기화되지 않은 텍스처 데이터가 사용됩니다. 모든 밉맵에 대해 깨끗한 샘플 값을 얻으려면 복제 된 데이터로 전체 텍스처를 채워야한다고 생각합니다. –

+0

맞습니다. GL.GenerateMipmap() 및/또는 이방성 필터링을 사용하는 경우 필요합니다. 나는 내 대답을 고칠 것이다. –

+0

당신 말이 맞아요. 문제는 밉맵에서 발생합니다. 그러나 다른 minFilters 정말 나쁜 그래서 정말 마지막 행/col 질감에 걸쳐 복제해야합니까? 조금 느릴 수 있습니다 (적어도 cols) ... – Flamefire

관련 문제