selection - OpenGL ES 2.0 Object Picking on iOS -


what best method select objects have been drawn in opengl es 2.0 (ios)?

i drawing points.

here working prototype of color picking, tested on old ipads , working well. part of project called incube chess 1 may find in app store. main code see located in class derived glkviewcontroller this:

@interface incubeviewcontroller : glkviewcontroller 

this means have glkview in it: ((glkview *)self.view).

here properties:

@property (strong, nonatomic) eaglcontext *context; @property (strong, nonatomic) glkbaseeffect *effect; 

don't forget synthesize them in *.m file.

@synthesize context = _context; @synthesize effect = _effect; 

the idea have chess pieces on table (or objects in 3d scene) , need find piece in list of pieces tapping on screen. is, need convert 2d screen tap coords (@point in case) chess piece instance.

each piece has unique id call "seal". can allocate seals from 1 something. selection function returns piece seal found tap coords. having seal can find piece in pieces hash table or array in way this:

-(piece *)findpiecebyseal:(gluint)seal {         /* !!! black background in off screen buffer produces 0 seals. allows            filter out taps did not select (will            mentioned below) !!! */         if (seal == 0)                 return nil;         pieceseal *sealkey = [[pieceseal alloc] init:s];         piece *p = [sealhash objectforkey:sealkey];         [sealkey release];         return p; } 

"sealhash" nsmutabledictionary.

now main selection function. note, glkview antialised , can't use buffers color picking. mean need create own off screen buffer antialiasing disabled picking purposes only.

- (nsuinteger)findsealbypoint:(cgpoint)point {         nsinteger height = ((glkview *)self.view).drawableheight;         nsinteger width = ((glkview *)self.view).drawablewidth;         byte pixelcolor[4] = {0,};         gluint colorrenderbuffer;         gluint framebuffer;          glgenframebuffers(1, &framebuffer);         glbindframebuffer(gl_framebuffer, framebuffer);         glgenrenderbuffers(1, &colorrenderbuffer);         glbindrenderbuffer(gl_renderbuffer, colorrenderbuffer);          glrenderbufferstorage(gl_renderbuffer, gl_rgba8_oes, width, height);         glframebufferrenderbuffer(gl_framebuffer, gl_color_attachment0_oes, gl_renderbuffer, colorrenderbuffer);          glenum status = glcheckframebufferstatus(gl_framebuffer);         if (status != gl_framebuffer_complete) {                 nslog(@"framebuffer status: %x", (int)status);                 return 0;         }          [self render:dm_select];          cgfloat scale = uiscreen.mainscreen.scale;         glreadpixels(point.x * scale, (height - (point.y * scale)), 1, 1, gl_rgba, gl_unsigned_byte, pixelcolor);          gldeleterenderbuffers(1, &colorrenderbuffer);         gldeleteframebuffers(1, &framebuffer);          return pixelcolor[0]; } 

note function takes account display scale (retina or new ipads).

here render() function used in function above. note, rendering purposes clear s buffer background color , selecting case makes black can check if tapped on piece @ or not.

- (void) render:(drawmode)mode {         if (mode == dm_render)                 glclearcolor(backgroundcolor.r, backgroundcolor.g,                              backgroundcolor.b, 1.0f);         else                 glclearcolor(0.0f, 0.0f, 0.0f, 1.0f);          glclear(gl_color_buffer_bit | gl_depth_buffer_bit);          /* draw pieces. */         (int = 0; < [model->pieces count]; i++) {                 piece *p = [model->pieces objectatindex:i];                 [self drawpiece:p mode:mode];         } } 

next how draw piece.

- (void) drawpiece:(piece *)p mode:(drawmode)mode {         piecetype type;          [self pushmatrix];          glkmatrix4 modelviewmatrix = self.effect.transform.modelviewmatrix;          glkmatrix4 translatematrix = glkmatrix4maketranslation(p->drawpos.x,                                                                p->drawpos.y,                                                                p->drawpos.z);         modelviewmatrix = glkmatrix4multiply(modelviewmatrix, translatematrix);          glkmatrix4 rotatematrix;         glkmatrix4 scalematrix;          if (mode == dm_render) {                 scalematrix = glkmatrix4makescale(p->scale.x,                                                   p->scale.y, p->scale.z);         } else {                 /* !!! make piece bit bigger in off screen buffer selection                    purposes sure tapped correctly                    finger.*/                 scalematrix = glkmatrix4makescale(p->scale.x + 0.2,                                                   p->scale.y + 0.2, p->scale.z + 0.2);         }          modelviewmatrix = glkmatrix4multiply(modelviewmatrix, scalematrix);          self.effect.transform.modelviewmatrix = modelviewmatrix;          type = p->type;          if (mode == dm_render) {                 /* !!! use real pieces color , light on normal drawing !!! */                 glkvector4 color[pclast] = {                         [pcwhite] = whitescolor,                         [pcblack] = blackscolor                 };                 self.effect.constantcolor = color[p->color];                 self.effect.light0.enabled = gl_true;         } else {                 /* !!! use piece seal color. important turn light off !!! */                 self.effect.light0.enabled = gl_false;                 self.effect.constantcolor = glkvector4make(p->seal / 255.0f,                                                            0.0f, 0.0f, 0.0f);         }          /* normal render piece using geometry buffers. */         [self renderpiece:type];          [self popmatrix]; } 

this how use functions shown above.

- (ibaction) tapgesture:(id)sender {         if ([(uitapgesturerecognizer *)sender state] == uigesturerecognizerstateended) {                 cgpoint tap = [(uitapgesturerecognizer *)sender locationinview:self.view];                 piece *p = [self findpiecebyseal:[self findsealbypoint:tap]];                  /* !!! selected object !!! */         } } 

this it. have precise picking algorithm better ray tracing or others.

here helpers push/pop matrix things.

- (void)pushmatrix {         assert(matrixsp < sizeof(matrixstack) / sizeof(glkmatrix4));         matrixstack[matrixsp++] = self.effect.transform.modelviewmatrix; }  - (void)popmatrix {         assert(matrixsp > 0);         self.effect.transform.modelviewmatrix = matrixstack[--matrixsp]; } 

here glkview setup/cleanup functions used.

- (void)viewdidload {         [super viewdidload];         self.context = [[[eaglcontext alloc] initwithapi:keaglrenderingapiopengles2] autorelease];         if (!self.context)                 nslog(@"failed create es context");          glkview *view = (glkview *)self.view;         view.context = self.context;         view.drawabledepthformat = glkviewdrawabledepthformat24;          [self setupgl]; }  - (void)viewdidunload {             [super viewdidunload];          [self teardowngl];          if ([eaglcontext currentcontext] == self.context)                 [eaglcontext setcurrentcontext:nil];         self.context = nil; }  - (void)setupgl {         [eaglcontext setcurrentcontext:self.context];          self.effect = [[[glkbaseeffect alloc] init] autorelease];         if (self.effect) {                 self.effect.useconstantcolor = gl_true;                 self.effect.colormaterialenabled = gl_true;                 self.effect.light0.enabled = gl_true;                 self.effect.light0.diffusecolor = glkvector4make(1.0f, 1.0f, 1.0f, 1.0f);         }          /* !!! draw antialiased geometry !!! */         ((glkview *)self.view).drawablemultisample = glkviewdrawablemultisample4x;         self.pauseonwillresignactive = yes;         self.resumeondidbecomeactive = yes;         self.preferredframespersecond = 30;          gldisable(gl_dither);         glenable(gl_cull_face);         glenable(gl_depth_test);         gllinewidth(2.0f);          /* load pieces geometry */         [self loadgeometry]; }  - (void)teardowngl {         drawready = no;         [eaglcontext setcurrentcontext:self.context];         [self unloadgeometry]; } 

hope helps , may closes "the picking question" forever :)


Comments

Popular posts from this blog

linux - Using a Cron Job to check if my mod_wsgi / apache server is running and restart -

actionscript 3 - TweenLite does not work with object -

jQuery Ajax Render Fragments OR Whole Page -