OpenGL 拾取

教程地址

点击屏蔽,获取点击的图元,并用红色进行渲染。

具体的方法:分两步绘制

  • 创建一个framebuffer,并链接一个颜色缓存和深度缓存,渲染时颜色缓存中保存的是像素所对应的物体的索引、物体部件的索引和渲染的图元的索引。物体索引和物体部件索引由程序传入着色器。使用深度缓存可以保证颜色缓存中保存的是距离近平面最近的图元的信息。
//像素信息结构体
 struct PixelInfo {
	GLuint ObjectID;
	GLuint DrawID;
	GLuint PrimID;
	PixelInfo()
	{
		ObjectID = 0;
		DrawID = 0;
		PrimID = 0;
	}
 };

bool PickingTexture::Init(unsigned int WindowWidth, unsigned int WindowHeight)
{
    // Create the FBO
    glGenFramebuffers(1, &m_fbo);    
    glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);

    // Create the texture object for the primitive information buffer
    glGenTextures(1, &m_pickingTexture);
    glBindTexture(GL_TEXTURE_2D, m_pickingTexture);
    //注意texutre的格式要与像素信息结构体相匹配
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32UI, WindowWidth, WindowHeight, 0, GL_RGB_INTEGER, GL_UNSIGNED_INT, NULL);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_pickingTexture, 0);    

	
    // Create the texture object for the depth buffer
    glGenTextures(1, &m_depthTexture);
    glBindTexture(GL_TEXTURE_2D, m_depthTexture); 
    glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, WindowWidth, WindowHeight, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_depthTexture, 0);    

	glReadBuffer(GL_NONE);
	glDrawBuffer(GL_COLOR_ATTACHMENT0);

    // Verify that the FBO is correct
    GLenum Status = glCheckFramebufferStatus(GL_FRAMEBUFFER);

    if (Status != GL_FRAMEBUFFER_COMPLETE) {
        printf("FB error, status: 0x%x\n", Status);
        return false;
    }
    
    // Restore the default framebuffer
    glBindTexture(GL_TEXTURE_2D, 0);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    return GLCheckError();
}
  • 第一步,绘制并保存像素信息。
//顶点着色器
#version 330         
                                                                                                                                                   
layout (location = 0) in vec3 Position;    
                                                                                                                             
uniform mat4 gWVP;   
                                                                                                                                                   
void main()                                                                         
{                                                                                   
    gl_Position = gWVP * vec4(Position, 1.0);                                       
}


//片元着色器
#version 330                                                                        
                                                                                                                                                                                                                                                        
uniform uint gDrawIndex;                                                            
uniform uint gObjectIndex;                                                          
 //输出像素为uvec3                                                                                   
out uvec3 FragColor;

void main()                                                                         
{     
	//颜色缓存清除为(0,0,0), 图元所索加1进行区分                                                                             
	FragColor = uvec3(gObjectIndex, gDrawIndex,gl_PrimitiveID + 1);    
}

//程序绘制设置
 void PickingPhase()
 {
     Pipeline p;
     p.Scale(0.1f, 0.1f, 0.1f);
     p.Rotate(0.0f, 90.0f, 0.0f);
     p.SetCamera(m_pGameCamera->GetPos(), m_pGameCamera->GetTarget(), m_pGameCamera->GetUp());
     p.SetPerspectiveProj(m_persProjInfo);

     m_pickingTexture.EnableWriting();

     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

     m_pickingEffect.Enable();
	 //绘制两个物体
     for (uint i = 0 ; i < (int)ARRAY_SIZE_IN_ELEMENTS(m_worldPos) ; i++) {
         p.WorldPos(m_worldPos[i]);
         //设置物体的索引 
         m_pickingEffect.SetObjectIndex(i);
         m_pickingEffect.SetWVP(p.GetWVPTrans());    
         m_pMesh->Render(&m_pickingEffect);
     }
     
     m_pickingTexture.DisableWriting();        
 }

void Mesh::Render(IRenderCallbacks* pRenderCallbacks)
{
    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);
    glEnableVertexAttribArray(2);
GLExitIfError;    
    for (unsigned int i = 0 ; i < m_Entries.size() ; i++) {
        glBindBuffer(GL_ARRAY_BUFFER, m_Entries[i].VB);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
        glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*)12);
        glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*)20);

        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_Entries[i].IB);
GLExitIfError;
        const unsigned int MaterialIndex = m_Entries[i].MaterialIndex;
GLExitIfError;
        if (MaterialIndex < m_Textures.size() && m_Textures[MaterialIndex]) {
            m_Textures[MaterialIndex]->Bind(GL_TEXTURE0);
        }
GLExitIfError;
        if (pRenderCallbacks) {
        	//物体的部件索引
            pRenderCallbacks->DrawStartCB(i);
        }
GLExitIfError;        
        glDrawElements(GL_TRIANGLES, m_Entries[i].NumIndices, GL_UNSIGNED_INT, 0);
    }

    glDisableVertexAttribArray(0);
    glDisableVertexAttribArray(1);
    glDisableVertexAttribArray(2);
}

  • 第二步,切换program,绑定默认framebuffer,点击屏幕,获取像素信息,绘制图元,再次绘制物体。
void RenderPhase()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
    Pipeline p;
    p.Scale(0.1f, 0.1f, 0.1f);
    p.Rotate(0.0f, 90.0f, 0.0f);
    p.SetCamera(m_pGameCamera->GetPos(), m_pGameCamera->GetTarget(), m_pGameCamera->GetUp());
    p.SetPerspectiveProj(m_persProjInfo);
    
    // If the left mouse button is clicked check if it hit a triangle
    // and color it red
    if (m_leftMouseButton.IsPressed) {
        PickingTexture::PixelInfo Pixel = m_pickingTexture.ReadPixel(m_leftMouseButton.x, WINDOW_HEIGHT - m_leftMouseButton.y - 1);
        GLExitIfError;
        if (Pixel.PrimID != 0) {                
            m_simpleColorEffect.Enable();
            assert(Pixel.ObjectID < ARRAY_SIZE_IN_ELEMENTS(m_worldPos));
            p.WorldPos(m_worldPos[Pixel.ObjectID]);
            m_simpleColorEffect.SetWVP(p.GetWVPTrans());
            // Must compensate for the decrement in the FS!
            m_pMesh->Render(Pixel.DrawID, Pixel.PrimID - 1); 
        }
    }
    
    // render the objects as usual
    m_lightingEffect.Enable();
    m_lightingEffect.SetEyeWorldPos(m_pGameCamera->GetPos());
    
    for (unsigned int i = 0 ; i < ARRAY_SIZE_IN_ELEMENTS(m_worldPos) ; i++) {
        p.WorldPos(m_worldPos[i]);
        m_lightingEffect.SetWVP(p.GetWVPTrans());
        m_lightingEffect.SetWorldMatrix(p.GetWorldTrans());                
        m_pMesh->Render(NULL);
    }        
}
//绘制红色图元
void Mesh::Render(unsigned int DrawIndex, unsigned int PrimID)
{
    assert(DrawIndex < m_Entries.size());
    
    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);
    glEnableVertexAttribArray(2);

    glBindBuffer(GL_ARRAY_BUFFER, m_Entries[DrawIndex].VB);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*)12);
    glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*)20);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_Entries[DrawIndex].IB);

    glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, (const GLvoid*)(PrimID * 3 * sizeof(GLuint)));

    glDisableVertexAttribArray(0);
    glDisableVertexAttribArray(1);
    glDisableVertexAttribArray(2);    
}

效果图:
在这里插入图片描述

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值