• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

              C++博客 :: 首頁 :: 聯系 ::  :: 管理
              163 Posts :: 4 Stories :: 350 Comments :: 0 Trackbacks

            常用鏈接

            留言簿(48)

            我參與的團隊

            搜索

            •  

            積分與排名

            • 積分 - 398977
            • 排名 - 59

            最新評論

            閱讀排行榜

            評論排行榜

            歡迎來到另一個有些復雜的課程,陰影。這一課的效果好的有些讓人不可思議,陰影可以變形,混合在其他的物體上。
            這一課要求你必須對OpenGL比較了解,它假設你知道許多OpenGL的知識,你必須知道蒙板緩存,基本的OpenGL步驟。如果你對這些不太熟悉,我建議你可以看看前面的教程。當然,在這一課里,我們用到了很多數學知識,請準備好一本數學手冊在你的身邊。
            首先我們定義陰影體可以延伸的距離。 
              

            // 定義陰影體可以延伸的距離
            #define INFINITY 100

              
             下面定義一個3D頂點結構 
              

            // 3D頂點結構
            struct sPoint
            {
             GLfloat x, y, z;
            };

              
             定義一個平面結構 
              

            // 平面方程為: ax + by + cz + d = 0
            struct sPlaneEq
            {
             GLfloat a, b, c, d;
            };

              
             下面定義一個用來投影的三角形的結構
            3個整形索引指定了模型中三角形的三個頂點
            第二個變量指定了三角形面的法線
            平面方程描述了三角所在的平面
            臨近的3個頂點索引,指定了與這個三角形相鄰的三個頂點
            最后一個變量指定這個三角形是否投出陰影
             
              

            // 描述一個模型表面的結構
            struct sPlane
            {
             unsigned int p[3];   // 3個整形索引指定了模型中三角形的三個頂點
             sPoint normals[3];   // 第二個變量指定了三角形面的法線
             unsigned int neigh[3];   // 與本三角形三個邊相鄰的面的索引
             sPlaneEq PlaneEq;   // 平面方程描述了三角所在的平面
             bool visible;   // 最后一個變量指定這個三角形是否投出陰影?
            };

              
             最后我們用下面的結構描述一個產生陰影的物體。 
              

            struct glObject{ GLuint nPlanes, nPoints; sPoint points[100]; sPlane planes[200];};
              
             下面的代碼用來讀取模型,它的代碼本身就解釋了它的功能。它從文件中讀取數據,并把頂點和索引存儲在上面定義的結構中,并把所有的臨近頂點初始化為-1,它代表這沒有任何頂點與它相鄰,我們將在以后計算它。 
              

            bool readObject( const char *filename, glObject*o)
            {
              FILE *file;
              unsigned int i;

              file = fopen(st, "r");
              if (!file) return FALSE;
              //讀取頂點
              fscanf(file, "%d", &(o->nPoints));
              for (i=1;i<=o->nPoints;i++){
                fscanf(file, "%f", &(o->points[i].x));
                fscanf(file, "%f", &(o->points[i].y));
                fscanf(file, "%f", &(o->points[i].z));
              }
              //讀取三角形面
              fscanf(file, "%d", &(o->nPlanes));
              for (i=0;inPlanes;i++){
                fscanf(file, "%d", &(o->planes[i].p[0]));
                fscanf(file, "%d", &(o->planes[i].p[1]));
                fscanf(file, "%d", &(o->planes[i].p[2]));
             //讀取每個頂點的法線
                fscanf(file, "%f", &(o->planes[i].normals[0].x));
                fscanf(file, "%f", &(o->planes[i].normals[0].y));
                fscanf(file, "%f", &(o->planes[i].normals[0].z));
                fscanf(file, "%f", &(o->planes[i].normals[1].x));
                fscanf(file, "%f", &(o->planes[i].normals[1].y));
                fscanf(file, "%f", &(o->planes[i].normals[1].z));
                fscanf(file, "%f", &(o->planes[i].normals[2].x));
                fscanf(file, "%f", &(o->planes[i].normals[2].y));
                fscanf(file, "%f", &(o->planes[i].normals[2].z));
              }
             return true;
            }

              
             現在從setConnectivity函數開始,事情變得越來越復雜了,這個函數用來查找每個面的相鄰的頂點,下面是它的偽代碼:
             
              

            對于模型中的每一個面A 對于面A中的每一條邊  如果我們不只到這條邊相鄰的頂點   那么對于模型中除了面A外的每一個面B    對于面B中的每一條邊     如果面A的邊和面B的邊是同一條邊,那么這兩個面相鄰      設置面A和面B的相鄰屬性
              
             下面的代碼完成上面偽代碼中最后兩行的內容,你先獲得每個面中邊的兩個頂點,然后檢測他們是否相鄰,如果是則設置各自的相鄰頂點信息 
              

             int vertA1 = pFaceA->vertexIndices[edgeA];
             int vertA2 = pFaceA->vertexIndices[( edgeA+1 )%3];

             int vertB1 = pFaceB->vertexIndices[edgeB];
             int vertB2 = pFaceB->vertexIndices[( edgeB+1 )%3];

             // 測試他們是否為同一邊,如果是則設置相應的相鄰頂點信息
             if (( vertA1 == vertB1 && vertA2 == vertB2 ) || ( vertA1 == vertB2 && vertA2 == vertB1 ))
             {
              pFaceA->neighbourIndices[edgeA] = faceB;
              pFaceB->neighbourIndices[edgeB] = faceA;
              edgeFound = true;
              break;
             }

              
             完整的SetConnectivity函數的代碼如下 
              


            // 設置相鄰頂點信息
            inline void SetConnectivity(glObject *o){
             unsigned int p1i, p2i, p1j, p2j;
             unsigned int P1i, P2i, P1j, P2j;
             unsigned int i,j,ki,kj;

             //對于模型中的每一個面A
             for(i=0;inPlanes-1;i++)
             {
              //對于除了此面的其它的面B
              for(j=i+1;jnPlanes;j++)
              {
               //對于面A中的每一個相鄰的頂點
               for(ki=0;ki<3;ki++)
               {
                //如果這個相鄰的頂點沒有被設置
                if(!o->planes[i].neigh[ki])
                {
                 for(kj=0;kj<3;kj++)
                 {
                  p1i=ki;
                  p1j=kj;
                  p2i=(ki+1)%3;
                  p2j=(kj+1)%3;

                  p1i=o->planes[i].p[p1i];
                  p2i=o->planes[i].p[p2i];
                  p1j=o->planes[j].p[p1j];
                  p2j=o->planes[j].p[p2j];
                
                  //如果面A的邊P1i->P1j和面B的邊P2i->P2j為同一條邊,則又下面的公式的P1i=P1j,并且P2i=P2j
                  P1i=((p1i+p2i)-abs(p1i-p2i))/2;
                  P2i=((p1i+p2i)+abs(p1i-p2i))/2;
                  P1j=((p1j+p2j)-abs(p1j-p2j))/2;
                  P2j=((p1j+p2j)+abs(p1j-p2j))/2;

                  //記錄與這個邊相鄰的面的索引
                  if((P1i==P1j) && (P2i==P2j))
                  {
                   o->planes[i].neigh[ki] = j+1;  
                   o->planes[j].neigh[kj] = i+1;  
                  }
                 }
                }
               }
              }
             }
            }

              
             下面的函數用來繪制模型 
              

            // 繪制模型,像以前一樣它繪制組成模型的三角形
            void drawObject( const ShadowedObject& object )
            {
             glBegin( GL_TRIANGLES );
             for ( int i = 0; i < object.nFaces; i++ )
             {
              const Face& face = object.pFaces[i];

              for ( int j = 0; j < 3; j++ )
              {
               const Point3f& vertex = object.pVertices[face.vertexIndices[j]];

               glNormal3f( face.normals[j].x, face.normals[j].y, face.normals[j].z );
               glVertex3f( vertex.x, vertex.y, vertex.z );
              }
             }
             glEnd();
            }

              
             下面的函數用來計算平面的方程參數 
              

            void calculatePlane( const ShadowedObject& object, Face& face )
            {
             // 獲得平面的三個頂點
             const Point3f& v1 = object.pVertices[face.vertexIndices[0]];
             const Point3f& v2 = object.pVertices[face.vertexIndices[1]];
             const Point3f& v3 = object.pVertices[face.vertexIndices[2]];

             face.planeEquation.a = v1.y*(v2.z-v3.z) + v2.y*(v3.z-v1.z) + v3.y*(v1.z-v2.z);
             face.planeEquation.b = v1.z*(v2.x-v3.x) + v2.z*(v3.x-v1.x) + v3.z*(v1.x-v2.x);
             face.planeEquation.c = v1.x*(v2.y-v3.y) + v2.x*(v3.y-v1.y) + v3.x*(v1.y-v2.y);
             face.planeEquation.d = -( v1.x*( v2.y*v3.z - v3.y*v2.z ) +
                v2.x*(v3.y*v1.z - v1.y*v3.z) +
                v3.x*(v1.y*v2.z - v2.y*v1.z) );
            }

              
             你還可以呼吸么?好的,我們繼續:) 接下來你將學習如何去投影,castShadow函數幾乎用到了所有OpenGL的功能,完成這個函數后,把它傳遞到doShadowPass函數來通過兩個渲染通道繪制出陰影.
            首先,我們看看哪些面面對著燈光,我們可以通過燈光位置和平面方程計算出.如果燈光到平面的位置大于0,則位于燈光的上方,否則位于燈光的下方(如果有什么問題,翻一下你高中的解析幾何). 
              

            void castShadow( ShadowedObject& object, GLfloat *lightPosition )
            {
             // 設置哪些面在燈光的前面
             for ( int i = 0; i < object.nFaces; i++ )
             {
              const Plane& plane = object.pFaces[i].planeEquation;

              GLfloat side = plane.a*lightPosition[0]+
               plane.b*lightPosition[1]+
               plane.c*lightPosition[2]+
               plane.d;

              if ( side > 0 )
               object.pFaces[i].visible = true;
              else
               object.pFaces[i].visible = false;
             }

              
             下面設置必要的狀態來渲染陰影.
            首先,禁用燈光和繪制顏色,因為我們不計算光照,這樣可以節約計算量.
            接著,設置深度緩存,深度測試還是需要的,但我們不希望我們的陰影體向實體一樣具有深度,所以關閉深度緩存.
            最后我們啟用蒙板緩存,讓陰影體的位置在蒙板中被設置為1. 
              

             glDisable( GL_LIGHTING );     // 關閉燈光
             glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );  // 關閉顏色緩存的寫入 
             glDepthFunc( GL_LEQUAL );     // 設置深度比較函數
             glDepthMask( GL_FALSE );     // 關閉深度緩存的寫入 
             glEnable( GL_STENCIL_TEST );    // 使用蒙板緩存
             glStencilFunc( GL_ALWAYS, 1, 0xFFFFFFFFL );   // 設置蒙板函數

              
             現在到了陰影被實際渲染得地方了,我們使用了下面提到的doShadowPass函數,它用來繪制陰影體的邊界面.我們通過兩個步驟來繪制陰影體,首先使用前向面增加陰影體在蒙板緩存中的值,接著使用后向面減少陰影體在蒙板緩存中的值. 
              

             // 如果是逆時針(即面向視點)的多邊形,通過了蒙板和深度測試,則把蒙板的值增加1
             glFrontFace( GL_CCW );
             glStencilOp( GL_KEEP, GL_KEEP, GL_INCR );
             doShadowPass( object, lightPosition );
             // 如果是順時針(即背向視點)的多邊形,通過了蒙板和深度測試,則把蒙板的值減少1
             glFrontFace( GL_CW );
             glStencilOp( GL_KEEP, GL_KEEP, GL_DECR );
             doShadowPass( object, lightPosition );

              
             為了更好的理解這兩個步驟,我建議你把第二步注釋掉看看效果,如下所示:

             
            圖 1: 步驟1 圖 2: 步驟2


            最后一步就是把陰影體所在的位置繪制上陰影的顏色 
              

             glFrontFace( GL_CCW );
             glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE ); 

             // 把陰影繪制上顏色
             glColor4f( 0.0f, 0.0f, 0.0f, 0.4f );
             glEnable( GL_BLEND );
             glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
             glStencilFunc( GL_NOTEQUAL, 0, 0xFFFFFFFFL );
             glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP );
             glPushMatrix();
             glLoadIdentity();
             glBegin( GL_TRIANGLE_STRIP );
              glVertex3f(-0.1f, 0.1f,-0.10f);
              glVertex3f(-0.1f,-0.1f,-0.10f);
              glVertex3f( 0.1f, 0.1f,-0.10f);
              glVertex3f( 0.1f,-0.1f,-0.10f);
             glEnd();
             glPopMatrix();
            }

              
             下面的部分我們繪制構成陰影體邊界的四邊形,當我們循環所有的三角形面的時候,我們檢測它是否是邊界邊,如果是我們繪制從燈光到這個邊界邊的射線,并衍生它用來構成四邊形.
            這里要用一個蠻力,我們檢測物體模型中每一個三角形面,找出其邊界并連接燈光到邊界的直線,把直線延長出一定的距離,構成陰影體.

            下面的代碼完成這些功能,它看起來并沒有想象的復雜.
             
              

            void doShadowPass(glObject *o, float *lp)
            {
             unsigned int i, j, k, jj;
             unsigned int p1, p2;
             sPoint   v1, v2;

             //對模型中的每一個面
             for (i=0; inPlanes;i++)
             { 
              //如果面在燈光的前面
              if (o->planes[i].visible)
              {
               //對于被燈光照射的面的每一個相鄰的面
               for (j=0;j<3;j++)
               {
                k = o->planes[i].neigh[j];
                //如果面不存在,或不被燈光照射,那么這個邊是邊界
                if ((!k) || (!o->planes[k-1].visible))
                {
                 // 獲得面的兩個頂點
                 p1 = o->planes[i].p[j];
                 jj = (j+1)%3;
                 p2 = o->planes[i].p[jj];

                 //計算邊的頂點到燈光的方向,并放大100倍
                 v1.x = (o->points[p1].x - lp[0])*100;
                 v1.y = (o->points[p1].y - lp[1])*100;
                 v1.z = (o->points[p1].z - lp[2])*100;

                 v2.x = (o->points[p2].x - lp[0])*100;
                 v2.y = (o->points[p2].y - lp[1])*100;
                 v2.z = (o->points[p2].z - lp[2])*100;
                 
                 //繪制構成陰影體邊界的面
                 glBegin(GL_TRIANGLE_STRIP);
                  glVertex3f(o->points[p1].x,
                     o->points[p1].y,
                     o->points[p1].z);
                  glVertex3f(o->points[p1].x + v1.x,
                     o->points[p1].y + v1.y,
                     o->points[p1].z + v1.z);

                  glVertex3f(o->points[p2].x,
                     o->points[p2].y,
                     o->points[p2].z);
                  glVertex3f(o->points[p2].x + v2.x,
                     o->points[p2].y + v2.y,
                     o->points[p2].z + v2.z);
                 glEnd();
                }
               }
              }
             }

            }


              
             既然我們已經能繪制陰影了,那么我們開始繪制我們的場景吧 
              

            bool drawGLScene()
            {
             GLmatrix16f Minv;
             GLvector4f wlp, lp;

             // 清空緩存
             glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

             glLoadIdentity();       // 設置燈光,并繪制球
             glTranslatef(0.0f, 0.0f, -20.0f);    
             glLightfv(GL_LIGHT1, GL_POSITION, LightPos);   
             glTranslatef(SpherePos[0], SpherePos[1], SpherePos[2]);  
             gluSphere(q, 1.5f, 32, 16);     
              
             下面我們計算燈光在物體坐標系中的位置 
              

             glLoadIdentity();      
             glRotatef(-yrot, 0.0f, 1.0f, 0.0f);    
             glRotatef(-xrot, 1.0f, 0.0f, 0.0f);    
             glTranslatef(-ObjPos[0], -ObjPos[1], -ObjPos[2]);  
             glGetFloatv(GL_MODELVIEW_MATRIX,Minv);    // 計算從世界坐標系變化到物體坐標系中的坐標
             lp[0] = LightPos[0];      // 保存燈光的位置
             lp[1] = LightPos[1];      
             lp[2] = LightPos[2];      
             lp[3] = LightPos[3];      
             VMatMult(Minv, lp);      // 計算最后燈光的位置

              
             下面繪制房間,物體和它的陰影 
              

             glLoadIdentity();  
             glTranslatef(0.0f, 0.0f, -20.0f);    
             DrawGLRoom();       // 繪制房間
             glTranslatef(ObjPos[0], ObjPos[1], ObjPos[2]);   
             glRotatef(xrot, 1.0f, 0.0f, 0.0f);    
             glRotatef(yrot, 0.0f, 1.0f, 0.0f);    
             DrawGLObject(obj);       // 繪制物體
             CastShadow(&obj, lp);      // 繪制物體的陰影

              
             下面的代碼繪制一個黃色的球代表了燈光的位置 
              

             glColor4f(0.7f, 0.4f, 0.0f, 1.0f);    
             glDisable(GL_LIGHTING);      
             glDepthMask(GL_FALSE);      
             glTranslatef(lp[0], lp[1], lp[2]);    
             gluSphere(q, 0.2f, 16, 8);     
             glEnable(GL_LIGHTING);      
             glDepthMask(GL_TRUE);      
              
             最后設置物體的控制 
              

             xrot += xspeed;       // 增加X軸選擇速度
             yrot += yspeed;       // 增加Y軸選擇速度

             glFlush();       // 強制OpenGL完成所有的命令
             return TRUE;       // 成功返回
            }

              
             繪制房間墻面 
              

            void DrawGLRoom()        // 繪制房間(盒裝)
            {
             glBegin(GL_QUADS);       // 繪制四邊形
              // 地面
              glNormal3f(0.0f, 1.0f, 0.0f);    // 法線向上
              glVertex3f(-10.0f,-10.0f,-20.0f);   
              glVertex3f(-10.0f,-10.0f, 20.0f);   
              glVertex3f( 10.0f,-10.0f, 20.0f);   
              glVertex3f( 10.0f,-10.0f,-20.0f);   
              // 天花板
              glNormal3f(0.0f,-1.0f, 0.0f);    // 法線向下
              glVertex3f(-10.0f, 10.0f, 20.0f);   
              glVertex3f(-10.0f, 10.0f,-20.0f);   
              glVertex3f( 10.0f, 10.0f,-20.0f);   
              glVertex3f( 10.0f, 10.0f, 20.0f);   
              // 前面
              glNormal3f(0.0f, 0.0f, 1.0f);    // 法線向后
              glVertex3f(-10.0f, 10.0f,-20.0f);   
              glVertex3f(-10.0f,-10.0f,-20.0f);   
              glVertex3f( 10.0f,-10.0f,-20.0f);   
              glVertex3f( 10.0f, 10.0f,-20.0f);   
              // 后面
              glNormal3f(0.0f, 0.0f,-1.0f);    // 法線向前
              glVertex3f( 10.0f, 10.0f, 20.0f);   
              glVertex3f( 10.0f,-10.0f, 20.0f);   
              glVertex3f(-10.0f,-10.0f, 20.0f);   
              glVertex3f(-10.0f, 10.0f, 20.0f);   
              // 左面
              glNormal3f(1.0f, 0.0f, 0.0f);    // 法線向右
              glVertex3f(-10.0f, 10.0f, 20.0f);   
              glVertex3f(-10.0f,-10.0f, 20.0f);   
              glVertex3f(-10.0f,-10.0f,-20.0f);   
              glVertex3f(-10.0f, 10.0f,-20.0f);   
              // 右面
              glNormal3f(-1.0f, 0.0f, 0.0f);    // 法線向左
              glVertex3f( 10.0f, 10.0f,-20.0f);   
              glVertex3f( 10.0f,-10.0f,-20.0f);  
              glVertex3f( 10.0f,-10.0f, 20.0f);   
              glVertex3f( 10.0f, 10.0f, 20.0f);   
             glEnd();        // 結束繪制
            }

              
             下面的函數完成矩陣M與向量V的乘法M=M*V
             
              

            void VMatMult(GLmatrix16f M, GLvector4f v)
            {
             GLfloat res[4];       // 保存中間計算結果
             res[0]=M[ 0]*v[0]+M[ 4]*v[1]+M[ 8]*v[2]+M[12]*v[3];
             res[1]=M[ 1]*v[0]+M[ 5]*v[1]+M[ 9]*v[2]+M[13]*v[3];
             res[2]=M[ 2]*v[0]+M[ 6]*v[1]+M[10]*v[2]+M[14]*v[3];
             res[3]=M[ 3]*v[0]+M[ 7]*v[1]+M[11]*v[2]+M[15]*v[3];
             v[0]=res[0];       // 把結果保存在V中
             v[1]=res[1];
             v[2]=res[2];
             v[3]=res[3];       
            }

              
             下面的函數用來初始化模型對象 
              

            int InitGLObjects()       // 初始化模型對象
            {
             if (!ReadObject("Data/Object2.txt", &obj))    // 讀取模型數據
             {
              return FALSE;      // 返回失敗
             }

             SetConnectivity(&obj);      // 設置相鄰頂點的信息

             for ( int i=0;i < obj.nPlanes;i++)     // 計算每個面的平面參數
              CalcPlane(obj, &obj.planes[i]);   

             return TRUE;       //成功返回
            }


              
             其他的函數我們不做過多解釋了,這會分散你的注意力,好好享受陰影帶給你的快感吧.
            下面還有一些說明:
            球體不會產生陰影,因為我們沒有設置其投影.
            如果你發現程序很慢,買塊好的顯卡吧.

            最后我希望你喜歡它,如果有什么好的建議,請告訴我.
             

            posted on 2007-12-20 11:52 sdfasdf 閱讀(1516) 評論(4)  編輯 收藏 引用 所屬分類: OPENGL

            Feedback

            # re: NEHE的OPENGL中文教程 第27課 影子 2007-12-20 20:49 學海一人
            繼續努力  回復  更多評論
              

            # re: NEHE的OPENGL中文教程 第27課 影子 2007-12-20 21:12 修遠
            頂一下,老兄  回復  更多評論
              

            # re: NEHE的OPENGL中文教程 第27課 影子 2008-05-04 20:28 kxlsc1985
            glStencilFunc(GL_NOTEQUAL, 0, 0xffffffff);
            glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
            glPushMatrix();
            glLoadIdentity();
            、、、、、、、、、、、、、、、、
            glBegin(GL_TRIANGLE_STRIP);
            glVertex3f(-0.1f, 0.1f,-0.1f);
            glVertex3f(-0.1f,-0.1f,-0.1f);
            glVertex3f( 0.1f, 0.1f,-0.1f);
            glVertex3f( 0.1f,-0.1f,-0.1f);
            glEnd();
            glPopMatrix();
            glDisable(GL_BLEND);
            、、、、、、、、、、、、、、、
            不懂為什么要畫矩形  回復  更多評論
              

            # re: NEHE的OPENGL中文教程 第27課 影子 2008-05-04 20:30 kxlsc1985
            是3dobject.h文件中的最后一部分  回復  更多評論
              

            热综合一本伊人久久精品| 国产精品久久久久久一区二区三区| 天天久久狠狠色综合| 一本伊大人香蕉久久网手机| 久久99久久成人免费播放| 精品久久久久久久久免费影院| 久久久无码精品亚洲日韩按摩| 91精品国产综合久久精品| 久久乐国产精品亚洲综合| 五月丁香综合激情六月久久 | 岛国搬运www久久| 久久亚洲AV成人无码| 爱做久久久久久| 亚洲精品无码久久一线| 久久本道久久综合伊人| 亚洲AV无码1区2区久久| 久久九色综合九色99伊人| 国产精品对白刺激久久久| 久久午夜无码鲁丝片秋霞| 国产成人精品久久亚洲高清不卡| 亚洲午夜无码久久久久| 久久久久亚洲AV成人网人人网站 | 久久九九久精品国产免费直播| 国产69精品久久久久久人妻精品| 久久精品国产一区二区电影| 亚洲国产成人久久综合一 | 国产精品久久久久乳精品爆 | 久久久91人妻无码精品蜜桃HD| 久久久亚洲欧洲日产国码aⅴ| 国产成人综合久久精品红| 免费一级做a爰片久久毛片潮| 91精品免费久久久久久久久| 狠狠色丁香久久综合五月| 国产精品久久国产精品99盘| 久久A级毛片免费观看| 久久久久久午夜成人影院 | 久久播电影网| 久久无码一区二区三区少妇| 久久国产成人午夜aⅴ影院| 99久久免费只有精品国产| 久久九九免费高清视频|