Содержимое высокого разрешения для приложения рисования Использование OpenGL ES на устройстве iPad - PullRequest
1 голос
/ 13 марта 2012

Я работаю над приложением рисования [по ссылке из приложения GLPaint] для iPhone и iPad. В этом приложении я заполняю цвета в рисованных изображениях линиями рисунков на экране в зависимости от того, где пользователь касается. Приложение работает правильно для iPhone. В iPad без масштабирования линии в режиме рисования являются правильными [без искажения пикселей], но после увеличения строк в PaintView имеют искаженные пиксели, т.е. содержимое OpenGL ES не имеет высокого разрешения.

Я использую следующий код для инициализации вида краски:

-(id)initWithCoder:(NSCoder*)coder {
   CGImageRef      brushImage;
   CGContextRef    brushContext;
   GLubyte         *brushData;
   size_t          width, height;
   CGFloat         components[3];

   if ((self = [super initWithCoder:coder])) {
      CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
      eaglLayer.opaque = NO;
      eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];
      context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];

      if (!context || ![EAGLContext setCurrentContext:context]) {
         return nil;
      }

      if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
      {
         brushImage = [UIImage imageNamed:@"circle 64.png"].CGImage;
      }
      else {
         brushImage = [UIImage imageNamed:@"flower 128.png"].CGImage;
      }

      // Get the width and height of the image
      width = CGImageGetWidth(brushImage)   ;
      height = CGImageGetHeight(brushImage) ;

      if(brushImage) {
         // Allocate  memory needed for the bitmap context
         brushData = (GLubyte *) calloc(width * height * 4, sizeof(GLubyte));

         // Use  the bitmatp creation function provided by the Core Graphics framework. 
         brushContext = CGBitmapContextCreate(brushData, width, height, 8, width * 4, CGImageGetColorSpace(brushImage), kCGImageAlphaPremultipliedLast);

         // After you create the context, you can draw the  image to the context.
         CGContextDrawImage(brushContext, CGRectMake(0.0, 0.0, (CGFloat)width, (CGFloat)height), brushImage);

         // You don't need the context at this point, so you need to release it to avoid memory leaks.
         CGContextRelease(brushContext);

         // Use OpenGL ES to generate a name for the texture.
         glGenTextures(1, &brushTexture);

         // Bind the texture name. 
         glBindTexture(GL_TEXTURE_2D, brushTexture);

         // Set the texture parameters to use a minifying filter and a linear filer (weighted average)
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

         // Specify a 2D texture image, providing the a pointer to the image data in memory
         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, brushData);

         // Release  the image data; it's no longer needed
         free(brushData);
      }

      CGFloat scale;


      if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
      {
         NSLog(@"IPAd");
         self.contentScaleFactor=1.0;
         scale = self.contentScaleFactor;
      }

      else {
         // NSLog(@"IPHone");
         self.contentScaleFactor=2.0;
      }

      //scale = 2.000000;

      // Setup OpenGL states
      glMatrixMode(GL_PROJECTION);
      CGRect frame = self.bounds;
      NSLog(@"Scale %f", scale);
      glOrthof(0, (frame.size.width) * scale, 0, (frame.size.height) * scale, -1, 1);
      glViewport(0, 0, (frame.size.width) * scale, (frame.size.height) * scale);
      glMatrixMode(GL_MODELVIEW);
      glDisable(GL_DITHER);
      glEnable(GL_BLEND);
      glEnable(GL_TEXTURE_2D);
      glEnableClientState(GL_VERTEX_ARRAY);
      glEnable(GL_BLEND);

      // Set a blending function appropriate for premultiplied alpha pixel data
      glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
      glEnable(GL_POINT_SPRITE_OES);
      glTexEnvf(GL_POINT_SPRITE_OES, GL_COORD_REPLACE_OES, GL_TRUE);
      glPointSize(width / kBrushScale);

      // Make sure to start with a cleared buffer
      needsErase = YES;

      // Define a starting color 
      HSL2RGB((CGFloat) 0.0 / (CGFloat)kPaletteSize, kSaturation, kLuminosity, &components[0], &components[1], &components[2]);
      [self setBrushColorWithRed:245.0f green:245.0f blue:0.0f];
      boolEraser=NO;
   }

   return self;
}

СОЗДАТЬ БУФЕР КАДРА

-(BOOL)createFramebuffer {
   // Generate IDs for a framebuffer object and a color renderbuffer
   glGenFramebuffersOES(1, &viewFramebuffer);
   glGenRenderbuffersOES(1, &viewRenderbuffer);

   glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
   glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);

   // This call associates the storage for the current render buffer with the EAGLDrawable (our CAEAGLLayer)
   // allowing us to draw into a buffer that will later be rendered to screen wherever the layer is (which corresponds with our view).
   [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(id<EAGLDrawable>)self.layer];
   glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer);

   // Get the size of the backing CAEAGLLayer
   glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
   glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);

   // For this sample, we also need a depth buffer, so we'll create and attach one via another renderbuffer.
   glGenRenderbuffersOES(1, &depthRenderbuffer);
   glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer);
   glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, backingWidth, backingHeight);
   glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer);

   if (glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES)
   {
      NSLog(@"failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES));
      return NO;
   }

   return YES;
}

Линия, нарисованная с использованием следующего кода

-(void)renderLineFromPoint:(CGPoint)start toPoint:(CGPoint)end {
   static GLfloat*     vertexBuffer = NULL;
   static NSUInteger   vertexMax = 64;
   NSUInteger          vertexCount = 0,
                       count,
                       i;

   [EAGLContext setCurrentContext:context];
   glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);

   // Convert locations from Points to Pixels
   //CGFloat scale = self.contentScaleFactor;
   CGFloat scale;
   scale=self.contentScaleFactor;
   NSLog(@"Scale %f",scale);

   start.x *= scale;
   start.y *= scale;
   end.x *= scale;
   end.y *= scale;

   float dx = end.x - start.x;
   float dy = end.y - start.y;
   float dist = (sqrtf(dx * dx + dy * dy)/ kBrushPixelStep);

   // Allocate vertex array buffer
   if(vertexBuffer == NULL)
      //  vertexBuffer = malloc(vertexMax * 2 * sizeof(GLfloat));
      vertexBuffer = malloc(vertexMax * 2 * sizeof(GLfloat));
      count = MAX(ceilf(dist), 1);

      //NSLog(@"count %d",count);

      for(i = 0; i < count; ++i) {
         if (vertexCount == vertexMax) {
            vertexMax = 2 * vertexMax;
            vertexBuffer = realloc(vertexBuffer, vertexMax * 2 * sizeof(GLfloat));
            //  NSLog(@"if loop");
         }

         vertexBuffer[2 * vertexCount + 0] = start.x + (dx) * ((GLfloat)i / (GLfloat)count);
         vertexBuffer[2 * vertexCount + 1] = start.y + (dy) * ((GLfloat)i / (GLfloat)count);

         vertexCount += 1;
      }

   // Render the vertex array
   glVertexPointer(2, GL_FLOAT, 0, vertexBuffer);
   glDrawArrays(GL_POINTS, 0, vertexCount);
   glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
   [context presentRenderbuffer:GL_RENDERBUFFER_OES];
}

Для устройства ipad содержимое вида краски является правильным - высокое разрешение для обычного вида, но после увеличения я не получаю Высокое разрешение содержимого вида краски - пиксель линий выглядит искаженным.

Я пытался изменить ContentScaleFactor, а также параметр масштаба вышеприведенного кода, чтобы увидеть разницу, но ничего не получилось, как ожидалось. IPad поддерживает contentScaleFactor 1.0 и 1.5, когда я устанавливаю contentScaleFactor = 2, представление Paint не может отображать линии, оно показывает странные пунктирные линии.

Есть ли способ сделать содержимое OpenGL высокого разрешения?

Ответы [ 2 ]

1 голос
/ 13 марта 2012

Короткий ответ: ДА , вы можете иметь контент с высоким разрешением.

Но вам придется четко понять проблему, прежде чем ее решить. Это длинный ответ:

Используемые кисти имеют определенный размер (64 или 128). Как только ваша виртуальная бумага (область, в которой вы рисуете) отобразит свои пиксели размером более 1 пикселя экрана, вы начнете видеть «искажение». Например, в вашей любимой программе просмотра изображений, если вы откроете одну из своих кистей и увеличите изображение, оно также будет искажено. Вы не можете избежать этого, если только не используете кисти-кисточки (с ними нет ответа и он намного сложнее).

Самым быстрым способом было бы использовать более детализированные кисти, но это выдумка, если при достаточном увеличении текстуры текстура тоже будет выглядеть искаженной.

Вы также можете добавить фильтр увеличения , используя glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_ MAG _FILTER, GL_LINEAR); , Вы использовали MIN в своем образце, добавьте, что это сгладит текстуры

1 голос
/ 13 марта 2012

Я не уверен, что вы имеете в виду под высоким разрешением.opengl - векторная библиотека с системой рендеринга на основе растрового изображения.резервное хранилище будет иметь размер в пикселях (умноженный на масштабный коэффициент содержимого) слоя, который вы используете для создания рендеринга буфера в:

- (BOOL)renderbufferStorage:(NSUInteger)target fromDrawable:(id<EAGLDrawable>)drawable

после его создания невозможно изменить разрешениеи, как правило, не имеет смысла делать это в целом, один пиксель рендеринга буфера на экранный пиксель имеет наибольшее значение.

трудно точно знать, какую проблему вы пытаетесь решить, не зная, о каком увеличении вы говорите.я предполагаю, что вы установили CAEAGLLayer в UIScrollView, и вы видите пиксельные артефакты.это неизбежно, как еще это могло бы работать?

Если вы хотите, чтобы ваши линии были гладкими, вам нужно реализовать их с помощью треугольных полос с альфа-смешиванием по краям, что обеспечит сглаживание.вместо масштабирования самого слоя вы просто «масштабируете» содержимое, масштабируя вершины, но сохраняя размер CAEAGLLayer того же размера.это устранит пикселизацию и даст смешанные края альфа чистоты.

...