glDepthMask 使用时遇到的问题

原文 http://stackmirror.cn/page/3xwgq8v46k4

https://stackoverflow.com/questions/3388294/opengl-question-about-the-usage-of-gldepthmask

问 :我如下绘制物体A。 场景中还有其它物体。

void Draw()
{
if( glIsList( displayListID ) )
{
glPushAttrib( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_ENABLE_BIT );

    glEnable( GL_BLEND );
    glEnable( GL_DEPTH_TEST );
    //glDepthMask( GL_FALSE );
    glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );

    glEnable( GL_LINE_SMOOTH );
    glEnable( GL_POINT_SMOOTH );
    glEnable( GL_POLYGON_SMOOTH );

    glMatrixMode( GL_MODELVIEW ); 

    color.setAlpha(alpha); // set alpha transparent of this objectA
    glCallList( displayListID );

    //glDepthMask( GL_TRUE );
    glDisable( GL_BLEND );  

    glPopAttrib();
}

}

现在的问题是, 如果我注释掉//glDepthMask( GL_FALSE ); //glDepthMask( GL_TRUE );这两句, 物体A和场景中其它物体的深度都会正确。
但是, 修改物体A的alpha 值就不会起作用(如 color.setAlpha(alpha) )。

如果我取消那两句的注释, alpha 的修改能正常工作,但是深度会出现问题, 换句话说, A应该在其它物体后面,但看上去它在前面。
我该如何解决这个问题?
谢谢

答:
1)开启深度写入, glDepthMask( GL_TRUE )
2)渲染所有的不透明物体,以任何顺序
3) 关闭深度写入, glDepthMask( GL_FALSE )
4) 开启混合 glEnable( GL_BLEND )
5) 从远到近渲染透明物体

为什么要这么做?
你需要关注两个缓存: 深度缓存和颜色缓存。 这两个缓存其实就是两个很大的2维数组, 大小为窗口的高度 X 宽度。 颜色缓存不停地更新(如果测试通过),最终会得到屏幕上看到的颜色。每一个屏幕像素的值都会有颜色缓存跟它对应(如像像素pixel[100][100] 的最终颜色就是颜色缓存color[100][100])。 和颜色缓存类似,每一个像素也都一个深度缓存的值跟它对应, 只不过它用在别的地方。 深度缓存则描述片元离相机的远近,然后取最近的深度。

如果你渲染一个三角形,它远离相机,它会为将要覆盖的屏幕像素产生一组颜色和深度缓存。当渲染另一个离相机近一点的多边形,它也会为它覆盖的像素产生一组颜色和深度缓存。现在颜色缓存就会产生“竞争”,离得远的片元(深度值大)将被丢弃。最后, 只有离相机最近的片元才能跟新颜色和深度buffer, 渲染到屏幕上(如果两个多边形重叠,则会产生Z冲突)。

一开始渲染不透明物体,允许写入深度 。 这意味着所有渲染的物体,只有赢得深度测试时,才会有机会更新深度缓冲区和颜色缓冲区。

接下来3) 关闭深度写入, glDepthMask( GL_FALSE ) , 4)开启混合 glEnable( GL_BLEND ) 5)从远到近渲染透明物体

感觉这很奇怪?

关闭深度写入(glDepthMask( GL_FALSE ) )后,渲染透明物体, OpenGL将读取深度缓存,然后决定时候丢弃该片元(例如, 如果你的透明物体在已经绘制的不透明物体后面, 则透明物体的片元将丢弃)。

由于没有开启深度写入, 当透明物体离相机更近时,此透明的片元不会阻挡后面的片元,而是会跟他们混合(跟新颜色buffer, 但不更新深度buffer)。

这很重要,因为假如你渲染离你很近的挡风玻璃,让它区更新深度缓冲区,那么接下的要绘制的物体你将不会看到,如果它在挡风玻璃后面(深度测试失败)。

关闭深度测试是“欺骗”OpenGL, 让它不知道哪一个透明片元离相机最近(透明片元不会因为之前绘制的透明片元而深度测试失败),关闭深度写入常常会用来渲染透明片元。同时,也能解释为什么要由远到近地绘制透明物体。

展开阅读全文

使用时遇到问题

10-30

各位大侠rn我在使用以下代码模拟键盘动作时rn产生了一些问题rn比如我要模拟 rn循环输入rnA B C Drn4个键.rnrn正确结果: ABCDABCDABCD...rn当前结果可能是:a00cd00070bdabbd...rn不知道是为什么呢?rnrn我的目的是为了在使用DXINPUT的游戏中模拟按键rnrn分少请勿怪!rnrn[code=C/C++]rn#includern#includern#includernusing namespace std;rnrn#include"WinIo.h"rnrn#define VK_A 0x41rn#define KBC_KEY_CMD 0x64 //键盘命令端口rn#define KBC_KEY_DATA 0x60rnrn//键盘数据端口rnvoid KBCWait4IBE()rnrn DWORD dwRegVal = 0;rn dorn GetPortVal(0x64, &dwRegVal, 1);rn while(dwRegVal & 0x00000001);rnrnrnvoid MyKeyDownEx(long vKeyCoad) //模拟扩展键按下,参数vKeyCoad是扩展键的虚拟码rnrn long btScancode=MapVirtualKey(vKeyCoad,0);rn KBCWait4IBE(); //等待键盘缓冲区为空rn SetPortVal(KBC_KEY_CMD,0xD2,1); //发送键盘写入命令rn KBCWait4IBE();rn SetPortVal(KBC_KEY_DATA,0xE0,1); //写入扩展键标志信息rn KBCWait4IBE(); //等待键盘缓冲区为空rn SetPortVal(KBC_KEY_CMD,0xD2,1); //发送键盘写入命令rn KBCWait4IBE();rn SetPortVal(KBC_KEY_DATA,btScancode,1); //写入按键信息,按下键rnrnrnvoid MyKeyUpEx(long vKeyCoad)//模拟扩展键弹起rnrn long btScancode = MapVirtualKey(vKeyCoad,0);rn KBCWait4IBE(); //等待键盘缓冲区为空rn SetPortVal(KBC_KEY_CMD,0xD2,1); //发送键盘写入命令rn KBCWait4IBE();rn SetPortVal(KBC_KEY_DATA,0xE0,1); //写入扩展键标志信息rn KBCWait4IBE(); //等待键盘缓冲区为空rn SetPortVal(KBC_KEY_CMD,0xD2,1); //发送键盘写入命令rn KBCWait4IBE();rn SetPortVal(KBC_KEY_DATA,(btScancode|0x80),1); //写入按键信息,释放键rnrnrnvoid MyKeyDown(long vKeyCoad)rnrn long byScancode = MapVirtualKey(vKeyCoad,0);rn KBCWait4IBE(); //等待键盘缓冲区为空rn if(SetPortVal(KBC_KEY_CMD,0xD2,1)==false)rn cout<<"发送键盘写入命令失败!"< 论坛

ODBC使用时遇到问题

05-08

//我是初学,用ODBC调用数据库,使用的代码是rn CListCtrl& ctrlList = (CListCtrl&) GetListCtrl();rn ctrlList.DeleteAllItems();rn while(ctrlList.DeleteColumn(0));rn UpdateWindow();rnrn CString strSQL;rn strSQL = _T("SELECT * FROM saleinfo;");rnrn if(!ShowInformation(strSQL)) AfxMessageBox("数据获取失败!");rnrn//其中,showinformation的代码:rnBOOL CXiaoshouView::ShowInformation(CString strSQL)rnrn CRect rect;rn CListCtrl& ctrlList = (CListCtrl&) GetListCtrl();rn ctrlList.GetWindowRect(rect);rnrn tryrn // get recordset field informationrn BeginWaitCursor();rn if(m_pCommonRS->IsOpen()) m_pCommonRS->Close(); rn m_pCommonRS->Open(CRecordset::dynaset, strSQL);rn if(!m_pCommonRS->IsEOF())rn m_pCommonRS->MoveLast(); rn m_pCommonRS->MoveFirst(); rn rn int nFieldCount = m_pCommonRS->GetODBCFieldCount(); rn CODBCFieldInfo fieldinfo; rn for(int n=0;nGetODBCFieldInfo(n, fieldinfo);rn int nWidth = ctrlList.GetStringWidth(fieldinfo.m_strName) + 15;rn ctrlList.InsertColumn(n, fieldinfo.m_strName, LVCFMT_LEFT, nWidth);rn rn // get recordset data informationrn CString strValue; rn m_pCommonRS->MoveFirst(); rn int nCount = 0;rnrn while(!m_pCommonRS->IsEOF())rn ctrlList.InsertItem(nCount, strValue);rn for(int j=0;jGetFieldValue(j, strValue);rn ctrlList.SetItemText(nCount, j, strValue);rn rn m_pCommonRS->MoveNext(); rn nCount ++;rn rn EndWaitCursor();rn rnrn catch(CDBException *e)rn e->ReportError();rn EndWaitCursor();rn return FALSE;rn rnrn return TRUE;rnrnrnrn//但是编译的时候我只要点到这个地方,然后就会说rn//"0x5f703ebf"指令引用的"0x00000004"内存,该内存不能为"read".rn//要终止程序,请单击"确定".rn//要调试程序,请单击"取消".rnrn 论坛

没有更多推荐了,返回首页