第四章 二维网格与交互式图形-4.2通过图形交互实时显示——flashlight

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/JennyBi/article/details/82017203

main.cpp 

#include <stdio.h>//加载合适的头文件
#include <stdlib.h>
#include "kernel.h"
#ifdef _WIN32
#define WINDOWS_LEAN_AND_MEAN
#define NOMINMAX
#include <windows.h>
#endif // _WIN32
#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glew.h>
#include <GL/freeglut.h>
#endif // __APPLE__
#include <cuda_runtime.h>
#include <cuda_gl_interop.h>
#include "interactions.h"

GLuint pbo = 0;
GLuint tex = 0;
struct cudaGraphicsResource *cuda_pbo_resource;

void render()
{
	uchar4 *d_out = 0;
	cudaGraphicsMapResources(1, &cuda_pbo_resource, 0);
	cudaGraphicsResourceGetMappedPointer((void**)&d_out, NULL, cuda_pbo_resource);
	kernelLauncher(d_out, W, H, loc);
	cudaGraphicsUnmapResources(1, &cuda_pbo_resource, 0);
}

void drawTexture() {
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, W, H, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);//建立二维纹理图像,创建四边形图像
	glEnable(GL_TEXTURE_2D);
	glBegin(GL_QUADS);
	glTexCoord2f(0.0f, 0.0f); glVertex2f(0, 0);
	glTexCoord2f(0.0f, 1.0f); glVertex2f(0, H);
	glTexCoord2f(1.0f, 1.0f); glVertex2f(W, H);
	glTexCoord2f(1.0f, 0.0f); glVertex2f(W, 0);
	glEnd();
	glDisable(GL_TEXTURE_2D);
}

void display()//窗口中显示的内容
{
	render();//计算新像素值
	drawTexture();//画OPENGL纹理
	glutSwapBuffers();//交换显示缓冲区。
	//双缓冲是一种用来提高图形程序效率的常见技术。
	//一个缓冲区提供可被读取用于显示的内存,与此同时,另一个缓冲区提供一段内存,保证下一帧的内容能够被写入。
	//在图形序列的帧与帧之间,两个缓冲区交换它们的读/写角色。
}

void initGLUT(int *argc, char **argv)
{
	glutInit(argc, argv);
	glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
	glutInitWindowSize(W, H);
	glutCreateWindow(TITLE_STRING);
#ifndef __APPLE__
	glewInit();
#endif // !__APPLE__

}

void initPixelBuffer()//初始化像素缓冲区
{
	glGenBuffers(1, &pbo);
	glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);
	glBufferData(GL_PIXEL_UNPACK_BUFFER, 4 * W*H * sizeof(GLubyte), 0, GL_STREAM_DRAW);
	glGenTextures(1, &tex);
	glBindTexture(GL_TEXTURE_2D, tex);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	cudaGraphicsGLRegisterBuffer(&cuda_pbo_resource, pbo, cudaGraphicsMapFlagsWriteDiscard);
	//CUDA注册OPENGL缓冲区
	//如果映射成功,则将缓冲区内存的控制交给CUDA来进行写输出。
	//如果没有映射成功,则返回缓冲区内存的控制给OPENGL用于显示。
}

void exitfunc()
{
	if (pbo)
	{
		cudaGraphicsUnregisterResource(cuda_pbo_resource);
		glDeleteBuffers(1, &pbo);
		glDeleteTextures(1, &tex);
	}
}

int main(int argc, char** argv)
{
	printInstructions();//将一些用户指令打印到命令窗口
	initGLUT(&argc, argv);//初始化GLUT库,并且设置图像窗口的规格,包括显示模式(RGBA),缓冲区(double型),尺寸(W*H)和标题。
	gluOrtho2D(0, W, H, 0);//建立视觉变换(简单的投影)。
	glutKeyboardFunc(keyboard);//键盘和鼠标的交互
	glutSpecialFunc(handleSpecialKeypress);
	glutPassiveMotionFunc(mouseMove);
	glutMotionFunc(mouseDrag);
	glutDisplayFunc(display);
	initPixelBuffer();
	glutMainLoop();//
	atexit(exitfunc);//执行清理工作,删除OPENGL的像素缓冲和纹理。
	return 0;
}

kernel.h

#pragma once
#ifndef KERNEL_H
#define KERNEL_H

struct uchar4;
struct int2;

void kernelLauncher(uchar4 *d_out, int w, int h, int2 pos);

#endif // !KERNEL_H

kernel.cu

#include "kernel.h"
#define TX 32
#define TY 32

__device__ unsigned char clip(int n)
{
	return n > 255 ? 255 : (n < 0 ? 0 : n);
}

__global__ void distanceKernel(uchar4 *d_out, int w, int h, int2 pos)
{
	const int c = blockIdx.x*blockDim.x + threadIdx.x;
	const int r = blockIdx.y*blockDim.y + threadIdx.y;
	if ((c>=w)||(r>=h))
		return;
	const int i = c + r*w;
	const int dist = sqrtf((c - pos.x)*(c - pos.x) + (r - pos.y)*(r - pos.y));
	const unsigned char intensity = clip(255 - dist);
	d_out[i].x = intensity;
	d_out[i].y = intensity;
	d_out[i].z = 0;
	d_out[i].w = 255;
}

void kernelLauncher(uchar4 *d_out, int w, int h, int2 pos)//计算网格维度,启动内核
{
	const dim3 blockSize(TX, TY);
	const dim3 gridSize = dim3((w + TX - 1) / TX, (h + TY - 1) / TY);
	distanceKernel << <gridSize, blockSize >> > (d_out, w, h, pos);
}

interactions.h

//指定回调函数来控制flashlight应用程序的交互
//显示一个可交互式改变的图像。每个图像元素对应该位置到参考点的距离,这个参考点可以被交互式地移动。
#pragma once
#ifndef INTERACTIONS_H
#define INTERACTIONS_H
#define W 600//图像维度
#define H 600
#define DELTA 5//每按下箭头键参考点移动的距离(以像素为单位)
#define  TITLE_STRING "flashlight:distance image display app"//标题栏中显示的文本
int2 loc = { W / 2,H / 2 };//参考点的位置,图像的中心
bool dragMode = false;

void keyboard(unsigned char key, int x, int y)
{
	if (key=='a')
	{
		dragMode = !dragMode;
	}
	if (key==27)
	{
		exit(0);
	}
	glutPostRedisplay();//在每个回调函数的结尾被调用,根据交互输入计算出一个新的图像用于显示(调用main.cpp中的display())
}

void mouseMove(int x, int y)
{
	if (dragMode)
	{
		return;
	}
	loc.x = x;
	loc.y = y;
	glutPostRedisplay();
}

void mouseDrag(int x, int y)
{
	if (!dragMode)
	{
		return;
	}
	loc.x = x;
	loc.y = y;
	glutPostRedisplay();
}

void handleSpecialKeypress(int key, int x, int y)
{
	if (key==GLUT_KEY_LEFT)
	{
		loc.x -= DELTA;
	}
	if (key==GLUT_KEY_RIGHT)
	{
		loc.x += DELTA;
	}
	if (key==GLUT_KEY_UP)
	{
		loc.y -= DELTA;
	}
	if (key == GLUT_KEY_DOWN)
	{
		loc.y += DELTA;
	}
	glutPostRedisplay();
}

void printInstructions()
{
	printf("flashlight interactions\n");
	printf("a: toggle mouse tracking mode\n");
	printf("arrow keys: move ref location\n");
	printf("esc: close graphics window\n");
}
#endif // !INTERACTIONS_H

运行结果:

猜你喜欢

转载自blog.csdn.net/JennyBi/article/details/82017203
今日推荐