[OpenGL] Shadow Map 陰影 - 程式人生

文章推薦指數: 80 %
投票人數:10人

[OpenGL] Shadow Map 陰影. 阿新• • 發佈:2018-12-25 ... 一文中已經介紹了shadow map的基本原理,至今為止,它依舊是在遊戲開發中運用較(最?)廣的一種陰影技術。

程式人生>>[OpenGL]ShadowMap陰影 [OpenGL]ShadowMap陰影 阿新••發佈:2018-12-25                   圖:隨著鍵盤控制點光源位置移動,陰影發生實時的變換     之前在 https://blog.csdn.net/ZJU_fish1996/article/details/51932954 一文中已經介紹了shadowmap的基本原理,至今為止,它依舊是在遊戲開發中運用較(最?)廣的一種陰影技術。

本文是自己花了週末放假兩天的時間,做的一個單點光源版的低精度硬陰影紋理,且有些地方比較偷懶,比如第一次pass僅記錄了需要生成陰影物體的深度(即圖中的cube),而第二次pass中繪製陰影時僅對陰影投射的物體(即圖中的平面)進行深度比較,某種程度上避開了shadowmap存在的浮點精度誤差的缺陷。

基本原理     關於陰影,從理解上最直觀的定義是燈光照不到的位置,以這一定義為基礎,我們可以這樣判斷某一點是否落在陰影下:     在以燈光為中心的觀察座標系中,該點和燈光之間進行連線,如果線段中有其它遮擋物,那麼該點在陰影中;如果沒有遮擋物,那麼該點被光照射。

這和做z-buffer運算計算遮擋關係非常類似,從這個角度來看,如果該點的深度大於深度模板中記錄的深度,那麼該點在陰影中;如果該點的深度等於模板中的深度,那麼該點被光照射。

    最終,我們需要至少繪製兩次:第一次把物體轉換到燈光檢視空間下,獲取並寫入深度到紋理。

第二次將物體轉換到相機檢視空間下,並同時記錄單個物體轉換到燈光檢視空間下的深度資訊,用該深度資訊與深度紋理進行比較,判斷畫素點是否在陰影中,如果在,按照正常的變換計算出顏色後,給顏色乘以一個陰影係數。

實現細節     (1)深度計算最終取的值是投影空間的z值,該z值需要在片元著色器中除以遠裁剪面保證歸一化。

不同的光源對應的投影矩陣有所差異,點光源對應透視矩陣,而平行光源對應正交矩陣。

遠近裁剪面差值較小時紋理精度會比較大,但是這將不利於表現大場景,且數值較大的裁剪面取得的深度能夠更接近線性。

也就是說,遠近裁剪面的選取對演算法的效果有一定影響。

    (2)在寫入陰影深度紋理時,同樣的,我們依然簡單使用了整數幀緩衝區,對浮點深度進行編碼存在rgba分量中,在使用的時候再進行解碼。

精度越高的紋理效果表現越好,鋸齒效果越不明顯,但也會耗費一定效能。

    (3)我們在片元著色器進行深度的比較。

深度的比較需要在同一個座標系下進行,才能保證比較的正確性,在這裡,我們把物體都轉換到燈光視角空間下進行對比。

一個要點是,在第二次繪製,對某個畫素點進行深度比較時,我們需要在陰影貼圖中找到它對應的畫素點。

經過透視變換,頂點被轉換到齊次裁剪空間座標,此時x,y分佈在[-1,1]之間,而紋理uv座標的取值範圍為[0,1],我們經過x'=0.5*x+0.5的運算可將前者對映到後者範圍中,再根據該值作為紋理索引去取對應位置的深度即可。

    (4)對於不在陰影中的物體,兩者深度值是一樣的,此時進行浮點數相等比較可能存在誤差,會導致畫面產生波紋,進行比較的時候需要儘可能排除這一影響,如兩個深度差值到達了一個臨界值才認為它們是不相等的。

程式碼部分     vShader0.glsl     記錄物體在燈光視角空間下的深度。

uniformmat4ProjectMatrix; uniformmat4LightMatrix; uniformmat4ModelMatrix; attributevec4a_position; varyingfloatv_depth; voidmain() { gl_Position=ModelMatrix*a_position; gl_Position=LightMatrix*gl_Position; gl_Position=ProjectMatrix*gl_Position; v_depth=gl_Position.z; }     fShader0.glsl     歸一化深度並編碼(未做線性處理),存在256位RGBA通道的顏色緩衝區中。

varyingfloatv_depth; uniformfloatzFar; voidmain() { floatfColor=v_depth/zFar; floatfR,fB,fG,fA; fColor=modf(fColor*256,fR); fColor=modf(fColor*256,fG); fColor=modf(fColor*256,fB); fColor=modf(fColor*256,fA); gl_FragColor=vec4(fR/256,fG/256,fB/256,fA/256); }     vShader1.glsl     將物體變換到視點空間下,並且同時記錄它在燈光檢視空間下的位置資訊。

(該例子中,主要針對的是兩個平面) uniformmat4ModelMatrix; uniformmat4ViewMatrix; uniformmat4ProjectMatrix; uniformmat4LightMatrix; attributevec4a_position; varyingvec4lightPos; attributevec3a_normal; varyingvec3v_normal; voidmain() { v_normal=a_normal; gl_Position=ProjectMatrix*(ViewMatrix*(ModelMatrix*a_position)); lightPos=ProjectMatrix*(LightMatrix*(ModelMatrix*a_position)); }     fShader1.glsl     解碼紋理裡深度,獲取當前畫素點的深度,以及對應紋理的深度,進行比較並判斷是否在紋理中。

對當前畫素進行簡單光照計算,最後乘以陰影係數。

uniformsampler2DShadowMap; uniformvec3lightLocation; varyingvec4lightPos; varyingvec3v_normal; uniformmat4IT_ModelMatrix; uniformfloatzFar; varyingvec3worldPos; floatGetShadow() { floatfShadow=1.0; floatfDistance=lightPos.z/zFar; vec2uv=lightPos.xy/lightPos.w*0.5+vec2(0.5,0.5); vec4fFactor=vec4(1,65536.0/16777216.0,256.0/16777216.0,1.0/16777216.0); vec4distance=texture2D(ShadowMap,uv); floatfDistanceMap=dot(distance,fFactor); if(fDistance-0.009>fDistanceMap) { fShadow=0.4; } returnfShadow; } voidmain() { floatfShadow=GetShadow(); vec3ambient=vec3(0.3,0.3,0.3); vec3worldLightLocation=normalize(lightLocation); vec3worldNormal=normalize(mat3(IT_ModelMatrix)*v_normal); vec3diffuseColor=vec3(0.4,0.4,0.4); vec3diffuse=diffuseColor*clamp(dot(worldNormal,worldLightLocation),0,1); vec4color=vec4(ambient+diffuse,1); gl_FragColor=color*fShadow; }     vShader1.glsl      為了偷懶新增的,對圖中立方體做最簡單的變換,不考慮陰影和光照,僅單獨貼了一個紋理。

uniformmat4ModelMatrix; uniformmat4ViewMatrix; uniformmat4ProjectMatrix; attributevec2a_texcoord; attributevec4a_position; varyingvec2v_texcoord; voidmain() { gl_Position=ProjectMatrix*(ViewMatrix*(ModelMatrix*a_position)); v_texcoord=a_texcoord; }     fShader1.glsl     同上,僅應用於圖中立方體。

uniformsampler2Dtexture; varyingvec2v_texcoord; voidmain() { gl_FragColor=texture2D(texture,v_texcoord); }     mainwidget.h #ifndefMAINWIDGET_H #defineMAINWIDGET_H #include"geometryengine.h" #include #include #include #include #include #include #include #include classGeometryEngine; classMainWidget:publicQOpenGLWidget,protectedQOpenGLFunctions { Q_OBJECT public: explicitMainWidget(QWidget*parent=nullptr); ~MainWidget()override; protected: voidkeyPressEvent(QKeyEvent*event)override; voidinitializeGL()override; voidresizeGL(intw,inth)override; voidpaintGL()override; voidmousePressEvent(QMouseEvent*e)override; voidmouseReleaseEvent(QMouseEvent*e)override; voidtimerEvent(QTimerEvent*e)override; private: QQuaternionrotation; QBasicTimertimer; QVector2DmousePressPosition; QVector3DrotationAxis; qrealangularSpeed; GLuintshadowMap; GLuintfBO; floatzFar=100.0f; intscreenX=640; intscreenY=480; QMatrix4x4lightMatrix; QMatrix4x4viewMatrix; QMatrix4x4projection; QVector3DlightPos=QVector3D(10,20,4); QVector3DeyeLocation=QVector3D(0,0,20); QVector3DlookAtLocation=QVector3D(0,0,0); GeometryEngine*geometries; QOpenGLTexture*texture; QOpenGLShaderProgramprogram0; QOpenGLShaderProgramprogram; QOpenGLShaderProgramprogram1; voidCalculateViewMatrix(); voidCalculateLightMatrix(); }; #endif//MAINWIDGET_H     mainwidget.cpp #include"mainwidget.h" #include #include MainWidget::MainWidget(QWidget*parent): QOpenGLWidget(parent), angularSpeed(0), geometries(nullptr) { } MainWidget::~MainWidget() { makeCurrent(); deletegeometries; doneCurrent(); } voidMainWidget::keyPressEvent(QKeyEvent*event) { constfloatstep=0.3f; if(event->key()==Qt::Key_W) { lightPos.setZ(lightPos.z()-step); CalculateLightMatrix(); update(); } elseif(event->key()==Qt::Key_S) { lightPos.setZ(lightPos.z()+step); CalculateLightMatrix(); update(); } elseif(event->key()==Qt::Key_A) { lightPos.setX(lightPos.x()-step); CalculateLightMatrix(); update(); } elseif(event->key()==Qt::Key_D) { lightPos.setX(lightPos.x()+step); CalculateLightMatrix(); update(); } elseif(event->key()==Qt::Key_Q) { lightPos.setY(lightPos.y()+step); CalculateLightMatrix(); update(); } elseif(event->key()==Qt::Key_E) { lightPos.setY(lightPos.y()-step); CalculateLightMatrix(); update(); } } voidMainWidget::initializeGL() { initializeOpenGLFunctions(); CalculateViewMatrix(); CalculateLightMatrix(); //清屏顏色 glClearColor(0,0,0,0); //開啟剔除 glEnable(GL_CULL_FACE); glEnable(GL_DEPTH_TEST); //addshader0 QOpenGLShader*vShader0=newQOpenGLShader(QOpenGLShader::Vertex); QOpenGLShader*fShader0=newQOpenGLShader(QOpenGLShader::Fragment); vShader0->compileSourceFile(":/vShader0.glsl"); fShader0->compileSourceFile(":/fShader0.glsl"); program0.addShader(vShader0); program0.addShader(fShader0); program0.link(); //addshader1 QOpenGLShader*vShader=newQOpenGLShader(QOpenGLShader::Vertex); QOpenGLShader*fShader=newQOpenGLShader(QOpenGLShader::Fragment); vShader->compileSourceFile(":/vShader.glsl"); fShader->compileSourceFile(":/fShader.glsl"); program.addShader(vShader); program.addShader(fShader); program.link(); //addshader2 QOpenGLShader*vShader1=newQOpenGLShader(QOpenGLShader::Vertex); QOpenGLShader*fShader1=newQOpenGLShader(QOpenGLShader::Fragment); vShader1->compileSourceFile(":/vShader1.glsl"); fShader1->compileSourceFile(":/fShader1.glsl"); program1.addShader(vShader1); program1.addShader(fShader1); program1.link(); geometries=newGeometryEngine; //載入立方體的紋理 texture=newQOpenGLTexture(QImage(":/cube.png").mirrored()); texture->setMinificationFilter(QOpenGLTexture::Nearest); texture->setMagnificationFilter(QOpenGLTexture::Linear); texture->setWrapMode(QOpenGLTexture::Repeat); //建立一個幀緩衝物件 glGenFramebuffers(1,&fBO); glBindFramebuffer(GL_FRAMEBUFFER,fBO); //生成紋理影象,附加到幀緩衝 glGenTextures(1,&shadowMap); glBindTexture(GL_TEXTURE_2D,shadowMap); glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,screenX,screenY,0,GL_RGBA,GL_UNSIGNED_BYTE,nullptr); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glBindTexture(GL_TEXTURE_2D,0); glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D,shadowMap,0); timer.start(12,this); } //計算view矩陣 voidMainWidget::CalculateViewMatrix() { QVector3DupDir(0,1,0); QVector3DN=eyeLocation-lookAtLocation;//這裡是和OpenGL的z軸方向保持一致 QVector3DU=QVector3D::crossProduct(upDir,N); QVector3DV=QVector3D::crossProduct(N,U); N.normalize(); U.normalize(); V.normalize(); viewMatrix.setRow(0,{U.x(),U.y(),U.z(),-QVector3D::dotProduct(U,eyeLocation)});//x viewMatrix.setRow(1,{V.x(),V.y(),V.z(),-QVector3D::dotProduct(V,eyeLocation)});//y viewMatrix.setRow(2,{N.x(),N.y(),N.z(),-QVector3D::dotProduct(N,eyeLocation)});//z viewMatrix.setRow(3,{0,0,0,1}); } voidMainWidget::mousePressEvent(QMouseEvent*e) { //Savemousepressposition mousePressPosition=QVector2D(e->localPos()); } voidMainWidget::mouseReleaseEvent(QMouseEvent*e) { //Mousereleaseposition-mousepressposition QVector2Ddiff=QVector2D(e->localPos())-mousePressPosition; //Rotationaxisisperpendiculartothemousepositiondifference //vector QVector3Dn=QVector3D(diff.y(),diff.x(),0.0).normalized(); //Accelerateangularspeedrelativetothelengthofthemousesweep qrealacc=diff.length()/100.0; //Calculatenewrotationaxisasweightedsum rotationAxis=(rotationAxis*angularSpeed+n*acc).normalized(); //Increaseangularspeed angularSpeed+=acc; } voidMainWidget::timerEvent(QTimerEvent*) { //Decreaseangularspeed(friction) angularSpeed*=0.99; //Stoprotationwhenspeedgoesbelowthreshold if(angularSpeed<0.01){ angularSpeed=0.0; }else{ //Updaterotation rotation=QQuaternion::fromAxisAndAngle(rotationAxis,angularSpeed)*rotation; //Requestanupdate update(); } } voidMainWidget::CalculateLightMatrix() { QVector3DlookAtLocation=QVector3D(0,0,0); QVector3DupDir(0,1,0); QVector3DN=lightPos-lookAtLocation; QVector3DU=QVector3D::crossProduct(upDir,N); QVector3DV=QVector3D::crossProduct(N,U); N.normalize(); U.normalize(); V.normalize(); lightMatrix.setRow(0,{U.x(),U.y(),U.z(),-QVector3D::dotProduct(U,lightPos)});//x lightMatrix.setRow(1,{V.x(),V.y(),V.z(),-QVector3D::dotProduct(V,lightPos)});//y lightMatrix.setRow(2,{N.x(),N.y(),N.z(),-QVector3D::dotProduct(N,lightPos)});//z lightMatrix.setRow(3,{0,0,0,1}); } voidMainWidget::resizeGL(intw,inth) { screenX=w; screenY=h; floataspect=float(w)/float(h?h:1); constqrealzNear=2.0,fov=60.0; projection.setToIdentity(); projection.perspective(fov,aspect,zNear,zFar); } voidMainWidget::paintGL() { QMatrix4x4plane1ModelMatrix; plane1ModelMatrix.translate(0,-5,5); plane1ModelMatrix.scale(8.0f,1.0f,5.0f); QMatrix4x4plane2ModelMatrix; plane2ModelMatrix.rotate(90,QVector3D(1,0,0)); plane2ModelMatrix.scale(8.0f,1.0f,5.0f); QMatrix4x4cubeModelMatrix; cubeModelMatrix.translate(0,-3,4); cubeModelMatrix.rotate(rotation); cubeModelMatrix.scale(2,2,2); glBindFramebuffer(GL_FRAMEBUFFER,fBO); glClearColor(1,1,1,1); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); program0.bind(); program0.setUniformValue("LightMatrix",lightMatrix); program0.setUniformValue("ProjectMatrix",projection); program0.setUniformValue("zFar",zFar); program0.setUniformValue("ModelMatrix",cubeModelMatrix); geometries->drawCubeGeometry(&program0); glBindFramebuffer(GL_FRAMEBUFFER,0); glClearColor(0,0,0,1); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); program.bind(); glBindTexture(GL_TEXTURE_2D,shadowMap); program.setUniformValue("ShadowMap",0); program.setUniformValue("LightMatrix",lightMatrix); program.setUniformValue("ProjectMatrix",projection); program.setUniformValue("ViewMatrix",viewMatrix); program.setUniformValue("lightLocation",lightPos); program.setUniformValue("zFar",zFar); QMatrix4x4IT_Matrix; IT_Matrix=plane1ModelMatrix.inverted(); IT_Matrix=IT_Matrix.transposed(); program.setUniformValue("IT_ModelMatrix",IT_Matrix); program.setUniformValue("ModelMatrix",plane1ModelMatrix); geometries->drawPlane(&program); QMatrix4x4IT_Matrix2; IT_Matrix2=plane2ModelMatrix.inverted(); IT_Matrix2=IT_Matrix2.transposed(); program.setUniformValue("IT_ModelMatrix",IT_Matrix2); program.setUniformValue("ModelMatrix",plane2ModelMatrix); geometries->drawPlane(&program); program1.bind(); texture->bind(); program1.setUniformValue("ProjectMatrix",projection); program1.setUniformValue("ViewMatrix",viewMatrix); program1.setUniformValue("ModelMatrix",cubeModelMatrix); program1.setUniformValue("texture",0); geometries->drawCubeGeometry(&program1); }     geometryengine.h #ifndefGEOMETRYENGINE_H #defineGEOMETRYENGINE_H #include #include #include classGeometryEngine:protectedQOpenGLFunctions { public: GeometryEngine(); virtual~GeometryEngine(); voiddrawCubeGeometry(QOpenGLShaderProgram*program); voiddrawPlane(QOpenGLShaderProgram*program); private: voidinitCubeGeometry(); QOpenGLBufferscreenArrayBuf; QOpenGLBufferscreenIndexBuf; QOpenGLBufferarrayBuf; QOpenGLBufferindexBuf; }; #endif//GEOMETRYENGINE_H     geometryengine.cpp #include"geometryengine.h" #include #include structVertexData { QVector3Dposition; QVector2Dtexture; }; structVertexData1 { QVector3Dposition; QVector3Dnormal; }; GeometryEngine::GeometryEngine() :screenIndexBuf(QOpenGLBuffer::IndexBuffer),indexBuf(QOpenGLBuffer::IndexBuffer) { initializeOpenGLFunctions(); arrayBuf.create(); indexBuf.create(); screenArrayBuf.create(); screenIndexBuf.create(); initCubeGeometry(); } GeometryEngine::~GeometryEngine() { arrayBuf.destroy(); indexBuf.destroy(); screenArrayBuf.destroy(); screenIndexBuf.destroy(); } voidGeometryEngine::initCubeGeometry() { VertexDatavertices[]={ //Vertexdataforface0 {QVector3D(-1.0f,-1.0f,1.0f),QVector2D(0.0f,0.0f)},//v0 {QVector3D(1.0f,-1.0f,1.0f),QVector2D(0.33f,0.0f)},//v1 {QVector3D(-1.0f,1.0f,1.0f),QVector2D(0.0f,0.5f)},//v2 {QVector3D(1.0f,1.0f,1.0f),QVector2D(0.33f,0.5f)},//v3 //Vertexdataforface1 {QVector3D(1.0f,-1.0f,1.0f),QVector2D(0.0f,0.5f)},//v4 {QVector3D(1.0f,-1.0f,-1.0f),QVector2D(0.33f,0.5f)},//v5 {QVector3D(1.0f,1.0f,1.0f),QVector2D(0.0f,1.0f)},//v6 {QVector3D(1.0f,1.0f,-1.0f),QVector2D(0.33f,1.0f)},//v7 //Vertexdataforface2 {QVector3D(1.0f,-1.0f,-1.0f),QVector2D(0.66f,0.5f)},//v8 {QVector3D(-1.0f,-1.0f,-1.0f),QVector2D(1.0f,0.5f)},//v9 {QVector3D(1.0f,1.0f,-1.0f),QVector2D(0.66f,1.0f)},//v10 {QVector3D(-1.0f,1.0f,-1.0f),QVector2D(1.0f,1.0f)},//v11 //Vertexdataforface3 {QVector3D(-1.0f,-1.0f,-1.0f),QVector2D(0.66f,0.0f)},//v12 {QVector3D(-1.0f,-1.0f,1.0f),QVector2D(1.0f,0.0f)},//v13 {QVector3D(-1.0f,1.0f,-1.0f),QVector2D(0.66f,0.5f)},//v14 {QVector3D(-1.0f,1.0f,1.0f),QVector2D(1.0f,0.5f)},//v15 //Vertexdataforface4 {QVector3D(-1.0f,-1.0f,-1.0f),QVector2D(0.33f,0.0f)},//v16 {QVector3D(1.0f,-1.0f,-1.0f),QVector2D(0.66f,0.0f)},//v17 {QVector3D(-1.0f,-1.0f,1.0f),QVector2D(0.33f,0.5f)},//v18 {QVector3D(1.0f,-1.0f,1.0f),QVector2D(0.66f,0.5f)},//v19 //Vertexdataforface5 {QVector3D(-1.0f,1.0f,1.0f),QVector2D(0.33f,0.5f)},//v20 {QVector3D(1.0f,1.0f,1.0f),QVector2D(0.66f,0.5f)},//v21 {QVector3D(-1.0f,1.0f,-1.0f),QVector2D(0.33f,1.0f)},//v22 {QVector3D(1.0f,1.0f,-1.0f),QVector2D(0.66f,1.0f)},//v23 }; GLushortindices[]={ 0,1,2,3,3,//Face0-trianglestrip(v0,v1,v2,v3) 4,4,5,6,7,7,//Face1-trianglestrip(v4,v5,v6,v7) 8,8,9,10,11,11,//Face2-trianglestrip(v8,v9,v10,v11) 12,12,13,14,15,15,//Face3-trianglestrip(v12,v13,v14,v15) 16,16,17,18,19,19,//Face4-trianglestrip(v16,v17,v18,v19) 20,20,21,22,23//Face5-trianglestrip(v20,v21,v22,v23) }; //TransfervertexdatatoVBO0 arrayBuf.bind(); arrayBuf.allocate(vertices,24*sizeof(VertexData)); //TransferindexdatatoVBO1 indexBuf.bind(); indexBuf.allocate(indices,34*sizeof(GLushort)); VertexData1screenVertices[]= { {QVector3D(-1.0f,0.0f,-1.0f),QVector3D(0,1,0)}, {QVector3D(-1.0f,0.0f,1.0f),QVector3D(0,1,0)}, {QVector3D(1.0f,0.0f,1.0f),QVector3D(0,1,0)}, {QVector3D(1.0f,0.0f,-1.0f),QVector3D(0,1,0)}, }; GLushortscreenIndices[]={ 0,1,2,2,3,0 }; screenArrayBuf.bind(); screenArrayBuf.allocate(screenVertices,4*sizeof(VertexData1)); screenIndexBuf.bind(); screenIndexBuf.allocate(screenIndices,6*sizeof(GLushort)); } voidGeometryEngine::drawCubeGeometry(QOpenGLShaderProgram*program) { arrayBuf.bind(); indexBuf.bind(); intoffset=0; intvertexLocation=program->attributeLocation("a_position"); program->enableAttributeArray(vertexLocation); program->setAttributeBuffer(vertexLocation,GL_FLOAT,offset,3,sizeof(VertexData)); offset+=sizeof(QVector3D); inttexcoordLocation=program->attributeLocation("a_texcoord"); program->enableAttributeArray(texcoordLocation); program->setAttributeBuffer(texcoordLocation,GL_FLOAT,offset,2,sizeof(VertexData)); glDrawElements(GL_TRIANGLE_STRIP,34,GL_UNSIGNED_SHORT,nullptr); } voidGeometryEngine::drawPlane(QOpenGLShaderProgram*program) { screenArrayBuf.bind(); screenIndexBuf.bind(); intoffset=0; intvertexLocation=program->attributeLocation("a_position"); program->enableAttributeArray(vertexLocation); program->setAttributeBuffer(vertexLocation,GL_FLOAT,offset,3,sizeof(VertexData1)); offset+=sizeof(QVector3D); intnormalLocation=program->attributeLocation("a_normal"); program->enableAttributeArray(normalLocation); program->setAttributeBuffer(normalLocation,GL_FLOAT,offset,3,sizeof(VertexData1)); glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_SHORT,nullptr); }     main.cpp #include #include #include #ifndefQT_NO_OPENGL #include"mainwidget.h" #endif intmain(intargc,char*argv[]) { QApplicationapp(argc,argv); QSurfaceFormatformat; format.setDepthBufferSize(24); QSurfaceFormat::setDefaultFormat(format); app.setApplicationName("cube"); app.setApplicationVersion("0.1"); #ifndefQT_NO_OPENGL MainWidgetwidget; widget.show(); #else QLabelnote("OpenGLSupportrequired"); note.show(); #endif returnapp.exec(); } [圖形學]《Real-TimeRendering》卡通渲染 «上一篇 B+樹以及非聚簇索引和聚簇索引下一篇» 相關推薦 [OpenGL]ShadowMap陰影                   圖:隨著鍵盤控制點光源位置移動,陰影發生實時的變換 ... box_shadowdiv陰影效果 div內陰影 box-shadow:0px0px10px5px#D0E2E9inset; d... 零基礎學習OpenGL(十二)--陰影(一)陰影對映     陰影是光線被阻擋的結果;當一個光源的光線由於其他物體的阻擋不能夠達到一個物體的表面的時候,那麼這... OpenGL(十九)陰影通過ShadowMap的shader實現 陰影可以使角色與地面的關係更加明確。

本文主要介紹如何通過ShadowMap在OpenGL中實現陰影。

核心原理Shad... (ShadowMapping)陰影對映原理與實現 安卓demo下載 轉載請宣告出處:http://... OpenGL陰影,ShadowMapping(附源程式) OpenGL陰影,ShadowMapping(附源程式)   實驗平臺:Win7,VS2010   先上結果截圖... OpenGL陰影,ShadowVolumes(附源程式,使用VCGlib) 轉載自:http://www.cnblogs.com/liangliangh/p/4165228.html 實驗平臺... 陰影對映(ShadowMap)的研究(五) 陰影對映(ShadowMap)的研究(五)        我成功地將別人的例子加以改進,使用QOpenGLWidget作... OpenGLes2.0使用shadowmapping方法制作陰影時,陰影穿透實體現象的形成原因及初步應對思路 在本人開發手機遊戲《KF坦克》時,發現了一個問題,具體如下: 一、開發環境描述: window7+adt-bundle-wi... 盒子陰影——Box-shadow strong半徑類型web設定chrome瀏覽器瀏覽器可選trobox-shadow:陰影水平偏移量陰影... 搜尋 基礎教學 Mysql入門 Sql入門 Android入門 Docker入門 Go語言入門 Ruby程式入門 Python入門 Python進階 Django入門 Python爬蟲入門 最近訪問 [OpenGL]+Shadow+Map+陰影 獲取+input[type=file]+檔案上傳尺寸 inet_ntoa()+inet_addr()的用法 高數積分導數公式 百冠受阻但費德勒依舊恐怖+這會是最後一次巴黎嗎 天力卓越精財生產管理系統v6.6.2.1(255用戶)專業版網絡版 php增刪改查示例 Linux系統日誌 2的n次方對照表 使用char指標賦值引發警告deprecated+conversion+from+string+constant+to+‘char星’



請為這篇文章評分?