To rectify an image with a shader, you can upload both the image data and the distortion maps and apply them as textures to an object such as a quad. Instead of sampling the image data directly, your fragment shader instead samples the distortion map texture. You then use the texture coordinates from the distortion texture to look up the brightness value in the image texture. See Rectifying with a Shader for more information about the distortion map texture and the fragment shader to use it.
14 #include "ExampleConnection.h"
19 static const char* GLSL_VERT = STRINGIFY(
24 gl_Position = ftransform();
25 gl_TexCoord[0]=gl_MultiTexCoord0;
28 static const char* GLSL_FRAG = STRINGIFY(
30 uniform sampler2D rawTexture;
31 uniform sampler2D distortionTexture;
35 vec2 distortionIndex = texture2D(distortionTexture, gl_TexCoord[0].st).xy;
36 float hIndex = distortionIndex.r;
37 float vIndex = distortionIndex.g;
39 if(vIndex > 0.0 && vIndex < 1.0 && hIndex > 0.0 && hIndex < 1.0)
41 gl_FragColor = vec4(texture2D(rawTexture, distortionIndex).rrr, 1.0);
45 gl_FragColor = vec4(0.2, 0.0, 0.0, 1.0);
50 LEAP_CONNECTION *connection;
52 LEAP_IMAGE_FRAME_REQUEST_TOKEN *image_token = 0;
55 void* image_buffer = NULL;
56 float* distortion_buffer_left = NULL;
57 float* distortion_buffer_right = NULL;
58 uint64_t image_size = 1;
59 bool imageRequested = false;
60 bool imageReady = false;
61 uint64_t currentDistortionId = 0;
63 int window; // GLUT window handle
64 int windowWidth = 800;
65 int windowHeight = 400;
67 GLuint vertShader, fragShader, program;
68 GLuint rawTextureLeft = 0;
69 GLuint rawTextureRight = 0;
70 GLuint distortionTextureLeft = 0;
71 GLuint distortionTextureRight = 0;
73 /** Callback for when an image request completes. */
74 void OnImages(const LEAP_IMAGE_COMPLETE_EVENT *imageCompleteEvent){
77 imageRequested = false;
79 image_width = imageCompleteEvent->properties->width;
80 image_height = imageCompleteEvent->properties->height;
82 //Save the distortion data if it's version id changes
83 if(currentDistortionId != imageCompleteEvent->matrix_version){
84 size_t distortion_size = 64 * 64 * 2;
85 distortion_buffer_left = malloc(sizeof(float) * distortion_size);
86 distortion_buffer_right = malloc(sizeof(float) * distortion_size);
87 memcpy(distortion_buffer_left, imageCompleteEvent->distortion_matrix[0], sizeof(float) * distortion_size);
88 memcpy(distortion_buffer_right, imageCompleteEvent->distortion_matrix[1], sizeof(float) * distortion_size);
89 currentDistortionId = imageCompleteEvent->matrix_version;
93 /** Callback for when an image request fails. */
94 void OnImageError(const LEAP_IMAGE_FRAME_REQUEST_ERROR_EVENT *imageErrorEvent){
95 if(imageErrorEvent->error == eLeapImageRequestError_ImagesDisabled)
96 printf("Warning: Images disabled. Check your control panel settings.");
98 //Resize image buffer if too small
99 if(image_size < imageErrorEvent->required_buffer_len){
100 image_size = imageErrorEvent->required_buffer_len;
101 if(image_buffer) free(image_buffer);
102 image_buffer = malloc((size_t)image_size);
103 printf("Resized image buffer to %lli.\n", (long long int)image_size);
108 imageRequested = false;
112 /* Notifies us that a new frame is available. */
113 void OnFrame(const LEAP_TRACKING_EVENT *frame){
114 if(!imageRequested && !imageReady){
115 imageRequested = true;
116 LEAP_IMAGE_FRAME_DESCRIPTION frameDescription;
117 frameDescription.type = eLeapImageType_Default;
118 frameDescription.frame_id = frame->info.frame_id;
119 frameDescription.buffer_len = image_size;
120 frameDescription.pBuffer = image_buffer;
122 image_token = malloc(sizeof(LEAP_IMAGE_FRAME_REQUEST_TOKEN));
123 eLeapRS result = LeapRequestImages(*connection, &frameDescription, image_token);
124 if(result != eLeapRS_Success)
125 printf("LeapRequestImages call was %s.\n", ResultString(result));
131 glMatrixMode(GL_MODELVIEW);
135 glClearColor(1.0f, 1.0f, 1.0f, 1.0f );
136 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
139 //Setup perspective and view matrices
140 glMatrixMode(GL_PROJECTION);
141 checkGLError("set matrix mode");
143 setPerspectiveFrustrum(96, windowWidth/windowHeight, 1, 20);
144 checkGLError("set frustrum");
146 glMatrixMode(GL_MODELVIEW);
148 glTranslatef(1.05f, 0.0, -1.01f);
150 glEnable(GL_TEXTURE_2D);
151 glUseProgram(program);
154 glActiveTexture(GL_TEXTURE0);
155 glBindTexture(GL_TEXTURE_2D, rawTextureLeft);
156 glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, image_width, image_height, 0, GL_RED, GL_UNSIGNED_BYTE, image_buffer);
157 checkGLError("Initializing raw texture");
159 glActiveTexture(GL_TEXTURE1);
160 glBindTexture(GL_TEXTURE_2D, distortionTextureLeft);
161 glTexImage2D(GL_TEXTURE_2D, 0, GL_RG, 64, 64, 0, GL_RG, GL_FLOAT, distortion_buffer_left);
162 checkGLError("Initializing distortion texture");
164 glBegin(GL_QUADS); // Draw A Quad for camera image
165 glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 0.0f); // Top Left
166 glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 0.0f); // Top Right
167 glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 0.0f); // Bottom Right
168 glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 0.0f); // Bottom Left
171 // Right camera image
172 glActiveTexture(GL_TEXTURE0);
173 glBindTexture(GL_TEXTURE_2D, rawTextureRight);
174 glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, image_width, image_height, 0, GL_RED, GL_UNSIGNED_BYTE,
175 (GLvoid*)((size_t)(image_buffer) + (image_width * image_height)));
176 checkGLError("Updating raw texture with right image");
178 glActiveTexture(GL_TEXTURE1);
179 glBindTexture(GL_TEXTURE_2D, distortionTextureRight);
180 glTexImage2D(GL_TEXTURE_2D, 0, GL_RG, 64, 64, 0, GL_RG, GL_FLOAT, distortion_buffer_right);
181 checkGLError("Updating distortion texture with right distortion map");
183 glTranslatef(-2.01f, 0.0, 0.0);
185 glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 0.0f); // Top Left
186 glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 0.0f); // Top Right
187 glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f,-1.0f, 0.0f); // Bottom Right
188 glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f,-1.0f, 0.0f); // Bottom Left
200 void reshape(int w, int h)
202 glViewport(0, 0, (GLsizei) w, (GLsizei) h);
205 void keyboard(unsigned char key, int x, int y)
210 glutDestroyWindow(window);
212 LeapCancelImageFrameRequest(*connection, *image_token);
213 if(image_buffer) free(image_buffer);
226 int main(int argc, char *argv[])
228 ConnectionCallbacks.on_frame = OnFrame;
229 ConnectionCallbacks.on_image_complete = OnImages;
230 ConnectionCallbacks.on_image_request_error = OnImageError;
232 connection = OpenConnection();
237 glutInit(&argc, argv);
238 glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
239 glutInitWindowSize(windowWidth, windowHeight);
240 window = glutCreateWindow("LeapC Distortion Shader Example");
242 #if defined(GLEW_VERSION)
243 GLenum err = glewInit();
244 if (err != GLEW_OK) {
245 /* Problem: glewInit failed, something is seriously wrong. */
246 fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
253 glutReshapeFunc(reshape);
254 glutKeyboardFunc(keyboard);
255 glutDisplayFunc(display);
258 glClearColor(0.0, 0.0, 0.0, 0.0);
259 glColor3f(1.0, 1.0, 1.0);
261 // init shader and textures
263 //Create the shader program
264 program = createProgram(GLSL_VERT, GLSL_FRAG);
265 glUseProgram(program);
266 GLuint rawSampler = glGetUniformLocation(program, "rawTexture");
267 GLuint distortionSampler = glGetUniformLocation(program, "distortionTexture");
268 glUniform1i(rawSampler, 0);
269 glUniform1i(distortionSampler, 1);
272 rawTextureLeft = createTextureReference();
273 distortionTextureLeft = createTextureReference();
274 rawTextureRight = createTextureReference();
275 distortionTextureRight = createTextureReference();
281 free(distortion_buffer_left);
282 free(distortion_buffer_right);
This example is only supported on platforms for which a working version of GLUT exists. It should not be overly difficult to port the example to a different OpenGL-based context, however.