OpenGL 利用framebuffer实现快速精确的点选拾取
来源:互联网 发布:java编译器中文安卓版 编辑:程序博客网 时间:2024/06/05 17:28
本文介绍利用framebuffer来实现opengl的点选拾取,编程语言C++,GLSL,编程环境VS2008,依赖库glew,OpenGL版本4.3。
不多说,直接介绍原理。此原理依赖opengl的几个技术特点包括 着色其多重输出,颜色值的宽动态表述,离屏渲染。
完整代码请看https://pan.baidu.com/s/1slaOpkx
email: hj3952321@163.com
离屏渲染就是将着色器的输出定向到自定义framebuffer中,而不是屏幕,framebuffer定义如下:
enum RBUFFERenum{DEPTH=0,POS,KEY_AND_ID,VID,MP0_WP2_0,MP1_WP2_1,MP2_WP2_2,WP0,WP1,RENDERBUFFERS_COUNT};
struct Buffers
{
RBUFFERenum mBufferName;
GLenum mAttachIndex;
GLenum mInternalFormat;
};
static Buffers gbuffers[RENDERBUFFERS_COUNT] = { \
{DEPTH, GL_DEPTH_ATTACHMENT, GL_DEPTH_COMPONENT32F},
{POS, GL_COLOR_ATTACHMENT0, GL_RGBA32F},
{KEY_AND_ID, GL_COLOR_ATTACHMENT1, GL_RGBA32I},
{VID, GL_COLOR_ATTACHMENT2, GL_RGBA32I},
{MP0_WP2_0, GL_COLOR_ATTACHMENT3, GL_RGBA32F},
{MP1_WP2_1, GL_COLOR_ATTACHMENT4, GL_RGBA32F},
{MP2_WP2_2, GL_COLOR_ATTACHMENT5, GL_RGBA32F},
{WP0, GL_COLOR_ATTACHMENT6, GL_RGBA32F},
{WP1, GL_COLOR_ATTACHMENT7, GL_RGBA32F}
};
Framebuffer::Framebuffer(GLuint width, GLuint height)
{
glGenFramebuffers(1,&mFramebuffer);
glGenRenderbuffers(RENDERBUFFERS_COUNT, mRenderbuffers);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mFramebuffer);
int i = 0;
for(; i < RENDERBUFFERS_COUNT; i++)
{
glBindRenderbuffer(GL_RENDERBUFFER, mRenderbuffers[i]);
glRenderbufferStorage(GL_RENDERBUFFER, gbuffers[i].mInternalFormat, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, gbuffers[i].mAttachIndex, GL_RENDERBUFFER, mRenderbuffers[i]);
}
unsigned int status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
}
对应片段着色器如下:
#version 430 core
layout (location = 0) out vec4 oPos;
layout (location = 1) out ivec4 key_and_id;
layout (location = 2) out ivec4 oVID;
layout (location = 3) out vec4 omPoso0;
layout (location = 4) out vec4 omPoso1;
layout (location = 5) out vec4 omPoso2;
layout (location = 6) out vec4 owPoso0;
layout (location = 7) out vec4 owPoso1;//MAX_COLOR_ATTACHMENTS = 8
uniform int globalKey1 = int(4);
uniform int localKey1 = int(16);
uniform int globalKey2 = int(64);
uniform int localKey2 = int(256);
in GS_FS_INTERFACE{
in vec3 pos;
in ivec3 VID;
in vec3 mPoso[3];
in vec3 wPoso[3];
};
void main(void)
{
oPos = vec4(pos, 1);
oVID = ivec4(VID, 2);
key_and_id = ivec4(globalKey1, globalKey2, localKey1, gl_PrimitiveID + 1);
omPoso0 = vec4(mPoso[0],wPoso[2].x);
omPoso1 = vec4(mPoso[1],wPoso[2].y);
omPoso2 = vec4(mPoso[2],wPoso[2].z);
owPoso0 = vec4(wPoso[0],7);
owPoso1 = vec4(wPoso[1],8);
}
着色器多重输出的buffer个数不同驱动实现有所差别,我所使用的支持最多8个buffer,所以着色器的out location从0到7.此着色器拾取对象是三角形,能够得到像素点的世界坐标和所在的三角形图元的ID,及三角形图元三个角所对应的模型坐标和世界坐标,最关键的是key_and_id,根据这个输出用户自定义的三个key值,可以找到像素点对应的原始数据模型。其中点所在图元的三个点的坐标和ID需要几何着色器来辅助得到。最简单的点选只需要oPos和key_and_id,oPos是通过片段着色器光栅化插值得到的,这个必须有,而用户根据key_and_id就能够获得顶点原始信息,进而就能得到其它信息。这里有个细节需要注意,glDraw命令的每一次执行,图元ID(gl_PrimitiveID)是从0开始计数的,而gl_vertexID是与VBO对应的,也是说比如VBO中有8个三角形图元对应有24个顶点坐标,分两次绘制,第一次绘制前4个图元,得到的图元ID是0-3,顶点ID是0-11,第二次绘制后4个图元,得到的图元ID也是0-3,但顶点ID是12-23.输出的图元ID做了加1处理,当读到的ID是0时,说明此处没有图元绘制。
- OpenGL 利用framebuffer实现快速精确的点选拾取
- 拾取操作的实现[OpenGL]
- 如何利用FDD模式实现项目的精确、快速开发
- opengl的拾取
- VTK系列——拾取点/显示当前点选点并删除上次的点选点
- OpenGL橡皮筋技术与拾取技术的实现
- OpenGL: 通过射线求交实现物体的拾取
- OpenGL拾取
- 利用stm32f103的TIM2实现精确延时
- 关于OpenGL的RenderBuffer,FrameBuffer
- 关于OpenGL的RenderBuffer,FrameBuffer
- OpenGL鼠标拾取的实现:终于搞定(包括细节问题)
- OpenGL鼠标拾取的实现:终于搞定(包括细节问题)
- [置顶] OpenGL鼠标拾取的实现:终于搞定(包括细节问题)
- Android中CheckBox的点选实现
- DX11_基于GPU_GeometryShader的3D精确拾取
- DX11_基于GPU_ComputeShader的3D精确拾取
- DX11_基于GPU_GeometryShader的3D精确拾取
- 详解ObjC之注释、标识符和变量
- android打开媒体库、照相机相关代码总结及常用UI处理代码,值得收藏
- leetcode_c++:链表:Reverse Linked List II (092)
- 补充说明Window、PhoneWindow与DecorView
- maven私服nexus-bundle的安装和启动
- OpenGL 利用framebuffer实现快速精确的点选拾取
- 经典继承方法实现(模拟extjs底层继承机制)
- Spark性能优化:shuffle调优
- poj --3614 Sunscreen
- easyui 演示 财务会计区间
- Windows下条件变量实现读写同步
- 前台页面向后台提交中文出现乱码解决办法
- hdu3506Monkey Party
- java之构造函数