Чтобы определить, что я пытаюсь сделать: я хочу иметь возможность взять произвольное изображение «спрайта» из PNG размером ^ 2x ^ 2 и отображать только пиксели, представляющие интерес для данной позиции x / y на экран.
Мои результаты - проблема - серьезное искажение - это выглядит ужасно! (Обратите внимание, что эти SS в iPhone Sim, но на реальном устройстве сетчатки они выглядят так же, как джанк). Вот скриншот исходного PNG в «превью» - , который выглядит замечательно (любые варианты рендеринга, которые я описываю в этом вопросе, выглядят почти так же, как и старомодные)
Ранее я задавал вопрос об отображении текстуры не-степени-2 в виде спрайта с использованием OpenGL ES 2.0 (хотя это относится к любому OpenGL). Я близко, но у меня есть некоторые проблемы, которые я не могу решить. Я думаю, что, возможно, есть несколько ошибок - я думаю, что есть какая-то ошибка, в которой я в основном налагаю псевдоним на то, что отображаю, рендерингом большой, а затем сжатие x2 или наоборот, но я не вижу этого. Кроме того, есть одна ошибка, и я не могу справиться с ними. Я не могу визуально идентифицировать их происходящие, но я точно знаю, что они там.
Я работаю в 960 x 640 альбомной (на дисплее сетчатки iPhone4). Так что я ожидаю 0-> 959 движений слева направо, 0-> 639 движений снизу вверх. (И я думаю, что вижу противоположность этому - но вопрос не в этом)
Чтобы упростить задачу, я пытаюсь достичь в этом тестовом примере ПОЛНОГО ЭКРАНА 960x640 с отображением файла PNG. Просто один из них. Сначала я отображаю красный фон, чтобы было ясно, закрываю я экран или нет.
Обновление: Я понял, что 'glViewport' внутри вызова setFramebuffer устанавливает мою ширину и высоту в обратном направлении. Я заметил это, потому что, когда я установил свою геометрию для рисования от 0,0 до 100,100, он рисовал прямоугольник, а не квадрат. Когда я поменял их местами, этот колл нарисовал квадрат. Однако, используя тот же самый вызов, весь мой экран заполняется вершинным диапазоном 0,0 -> 480 320 (половина «разрешения») .. не понимаю этого. Тем не менее, независимо от того, к чему я стремлюсь, я все равно не получаю хорошего результата
Вот мой вершинный шейдер:
attribute vec4 a_position;
attribute vec2 a_texCoord;
varying vec2 v_texCoord;
// Gives 'landscape' full screen..
mat4 projectionMatrix = mat4( 2.0/640.0, 0.0, 0.0, -1.0,
0.0, 2.0/960.0, 0.0, -1.0,
0.0, 0.0, -1.0, 0.0,
0.0, 0.0, 0.0, 1.0);
// Gives a 1/4 of screen.. (not doing 2.0/.. was suggested in previous SO Q)
/*mat4 projectionMatrix = mat4( 1.0/640.0, 0.0, 0.0, -1.0,
0.0, 1.0/960.0, 0.0, -1.0,
0.0, 0.0, -1.0, 0.0,
0.0, 0.0, 0.0, 1.0); */
// Apply the projection matrix to the position and pass the texCoord
void main()
{
gl_Position = a_position;
gl_Position *= projectionMatrix;
v_texCoord = a_texCoord;
}
Вот мой фрагментный шейдер:
precision mediump float;
varying vec2 v_texCoord;
uniform sampler2D s_texture;
void main()
{
gl_FragColor = texture2D(s_texture, v_texCoord);
}
Вот мой код розыгрыша:
#define MYWIDTH 960.0f
#define MYHEIGHT 640.0f
// I have to refer to 'X' as height although I'd assume I use 'Y' here..
// I think my X and Y throughout this whole block of code is screwed up
// But, I have experimented flipping them all and verifying that if they
// Are taken from the way they're set now to swapping X and Y that things
// end up being turned the wrong way. So this is a mess, but unlikely my problem
#define BG_X_ORIGIN 0.0f
// ALSO NOTE HERE: I have to put my 'dest' at 640.0f.. --- see note [1] below
#define BG_X_DEST 640.0f
#define BG_Y_ORIGIN 0.0f
// --- see note [1] below
#define BG_Y_DEST 960.0f
// These are texturing coordinates, I texture starting at '0' px and then
// I calculate a percentage of the texture to use based on how many pixels I use
// divided by the actual size of the image (1024x1024)
#define BG_X_ZERO 0.0f
#define BG_Y_USEPERCENTAGE BG_X_DEST / 1023.0f
#define BG_Y_ZERO 0.0f
#define BG_X_USEPERCENTAGE BG_Y_DEST / 1023.0f
// glViewport(0, 0, MYWIDTH, MYHEIGHT);
// See note 2.. it sets glViewport basically, provided by Xcode project template
[(EAGLView *)self.view setFramebuffer];
// Big hack just to get things going - like I said before, these could be backwards
// w/respect to X and Y
static const GLfloat backgroundVertices[] = {
BG_X_ORIGIN, BG_Y_ORIGIN,
BG_X_DEST, BG_Y_ORIGIN,
BG_X_ORIGIN, BG_Y_DEST,
BG_X_DEST, BG_Y_DEST
};
static const GLfloat backgroundTexCoords[] = {
BG_X_ZERO, BG_Y_USEPERCENTAGE,
BG_X_USEPERCENTAGE, BG_Y_USEPERCENTAGE,
BG_X_ZERO, BG_Y_ZERO,
BG_X_USEPERCENTAGE, BG_Y_ZERO
};
// Turn on texturing
glEnable(GL_TEXTURE_2D);
// Clear to RED so that it's obvious when I'm not drawing my sprite on screen
glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// Texturing parameters - these make sense.. don't think they are the issue
glActiveTexture(GL_TEXTURE0);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);//GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);//GL_LINEAR);
// Update attribute values.
glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, backgroundVertices);
glEnableVertexAttribArray(ATTRIB_VERTEX);
glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, 0, 0, backgroundTexCoords);
glEnableVertexAttribArray(ATTRIB_TEXCOORD);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, background->textureId);
// I don't understand what this uniform does in the texture2D call in shader.
glUniform1f(uniforms[UNIFORM_SAMPLERLOC], 0);
// Draw the geometry...
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
// present the framebuffer see note [3]
[(EAGLView *)self.view presentFramebuffer];
Примечание [1] :
Если я установлю BG_X_DEST на 639.0f, я не получу полное покрытие 640 пикселей, я получаю красный, просвечивающий справа. Но это не имеет смысла для меня - я стремлюсь к идеальному пикселю, и мне нужно нарисовать геометрию спрайта от 0 до 640, что составляет 641 пиксель, когда у меня только 640 !!! красная линия с 639f вместо 640f
И если я установлю BG_Y_DEST на 959.0f, я не получу показ красной линии через throug.
Ошибка в верхней строке красной линии с 958f вместо 960 или 959f
Это может быть хорошей подсказкой относительно того, какие ошибки у меня есть.
Примечание: [2] - включено в платформу OpenGL ES 2 Xcode
- (void)setFramebuffer
{
if (context)
{
[EAGLContext setCurrentContext:context];
if (!defaultFramebuffer)
[self createFramebuffer];
glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebuffer);
glViewport(0, 0, framebufferWidth, framebufferHeight);
}
}
Примечание [3]: - включено в платформу OpenGL ES 2 Xcode
- (BOOL)presentFramebuffer
{
BOOL success = FALSE;
if (context)
{
[EAGLContext setCurrentContext:context];
glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer);
success = [context presentRenderbuffer:GL_RENDERBUFFER];
}
return success;
}
Примечание [4] - соответствующий код загрузки изображения (я использовал PNG с альфа-каналом и без него, и на самом деле это не имеет никакого значения ... Я также пытался изменить свой код до ARGB вместо RGBA, и это неправильно - поскольку A = 1.0 везде, я получаю очень КРАСНОЕ изображение, которое заставляет меня думать, что RGBA действительно действителен, и этот код верен.): update: Я переключил эту загрузку текстуры на совершенно другую настройку, используя вызовы CG / ImageIO, и она выглядит идентично этому, поэтому я предполагаю, что это не какой-то псевдоним или сжатие цветов, выполняемое библиотеками изображений (если они оба не обращаются к одним и тем же фундаментальным вызовам, что возможно ..)
// Otherwise it isn't already loaded
glEnable(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE0);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);//GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);//GL_LINEAR);
// TODO Next 2 can prob go later on..
glGenTextures(1, &(newTexture->textureId)); // generate Texture
// Use this before 'drawing' the texture to the memory...
glBindTexture(GL_TEXTURE_2D, newTexture->textureId);
NSString *path = [[NSBundle mainBundle]
pathForResource:[NSString stringWithUTF8String:newTexture->filename.c_str()] ofType:@"png"];
NSData *texData = [[NSData alloc] initWithContentsOfFile:path];
UIImage *image = [[UIImage alloc] initWithData:texData];
if (image == nil)
NSLog(@"Do real error checking here");
newTexture->width = CGImageGetWidth(image.CGImage);
newTexture->height = CGImageGetHeight(image.CGImage);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
void *imageData = malloc(newTexture->height * newTexture->width * 4 );
CGContextRef myContext = CGBitmapContextCreate
(imageData, newTexture->width, newTexture->height, 8, 4 * newTexture->width, colorSpace,
kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big );
CGColorSpaceRelease(colorSpace);
CGContextClearRect(myContext, CGRectMake(0, 0, newTexture->width, newTexture->height));
CGContextDrawImage(myContext, CGRectMake(0, 0, newTexture->width, newTexture->height), image.CGImage);
// Texture is created!
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, newTexture->width, newTexture->height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, imageData);
CGContextRelease(myContext);
free(imageData);
[image release];
[texData release];