青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

實時陰影繪制技術研究

C++博客 首頁 新隨筆 聯系 聚合 管理
  48 Posts :: 20 Stories :: 57 Comments :: 0 Trackbacks

GameRes游戲開發資源網 http://www.gameres.com

軟陰影

www.GameDev.net 作者:Anirudh.S Shastry 

http://www.gamedev.net/reference/articles/article2193.asp

譯者:赟

介紹... 1

近況... 1

軟陰影... 2

那么它如何工作?... 2

步驟一:渲染陰影映射圖(shadow map... 2

步驟二:將帶陰影的場景渲染到緩沖中... 4

步驟三:對屏幕緩沖進行模糊... 7

步驟四:渲染帶陰影的場景... 11

參考文獻... 13

 

 

介紹

最初,動態陰影技術只有在有限的幾種情況下才能實現。但是,隨著強大的可編程圖形硬件的面世,動態陰影技術已經完全取代了以前的如light map這樣的靜態陰影技術及像projected shadows這樣的半動態陰影技術。目前兩種流行的動態陰影技術分別是shadow volumesshadow mapping

 

近況

shadow volumes技術是一種基于幾何形體的技術,它需要幾何體在一定方向的燈光下的輪廓去產生一個封閉的容積,然后通過光線的投射就可以決定場景的陰影部分(常常使用模板緩沖去模擬光線的投射)。這項技術是像素精確的,不會產生任何的鋸齒現象,但是與其他的技術一樣,它也有缺點。最主要的兩個問題一是極度依賴幾何形體,二是需要非常高的填充率。由于這些缺點,使得shadow mapping技術漸漸地變得更為流行起來。

陰影映射技術是一種圖像空間的技術,它首先在以光源位置作為視點的情況下渲染整個場景的深度信息,然后再使用這些深度信息去決定場景的哪一部分是處于陰影之中。雖然這項技術有許多優點,但它有鋸齒現象并且依賴z-緩沖技術。不過它的優點足以抵消它的這些缺點,因此本文選用了這項技術。

 

軟陰影

硬陰影破壞了場景的真實性,因此,我們必須仿造軟陰影來提升場景的可視效果。許多狂熱的學者都拿出了描述軟陰影技術的論文。但實際上,這些技術大部分都是很難在一個較為復雜的場景下實現實時效果。直到我們擁有了能克服這些技術局限性的硬件后,我們才真正的采用了這些方法。

本文采用了基于圖像空間的方法,并利用shadow mapping技術來產生軟陰影。這個方法不能產生完美的陰影,因為沒有真正的模擬出本影和半影,但它不僅僅可以解決陰影映射技術的鋸齒現象,還能以賞心悅目的軟陰影來提升場景的可視效果。

 

那么它如何工作?

首先,我們生成陰影映射圖(shadow map),具體方法是以光源位置為視點,將場景的深度信息渲染到浮點格式的緩沖中去。然后我們不是像通常那樣在陰影下渲染場景,而是將陰影區域渲染到一幅屏幕大小的緩沖中去,這樣就可以使用bloom filter進行模糊并將它投射回屏幕空間中使其顯示在屏幕上。是不是很簡單?

本文只處理了聚光燈源這種情況,但可以很方便的推廣到點光源上。

下面是具體步驟:

通過將深度信息寫入浮點紋理的方法產生陰影映射圖(shadow map)。

深度比較后將場景的陰影部分渲染到定點紋理,此時不要任何的燈光。

使用bloom filter模糊上一步的紋理,本文采用了separable Gaussian filter也可用其他的方法。

在所有的光源下將上一步模糊后的紋理投射到屏幕空間中,從而得到最終的效果。

步驟:渲染陰影映射圖(shadow map

首先,我們需要創建一個能保存屏幕深度信息的紋理。因為要把這幅紋理作為render target,所以我們還要創建一個表面(surface)來保存紋理的表面信息。由于深度信息值的范圍很大因此這幅紋理必須是浮點類型的。R32F的格式有足夠的精度可以滿足我們的需要。下面是創建紋理的代碼片斷:

// Create the shadow map 
if( FAILED( g_pd3dDevice->CreateTexture( SHADOW_MAP_SIZE,
                     SHADOW_MAP_SIZE, 1, D3DUSAGE_RENDERTARGET,
                     D3DFMT_R32F, D3DPOOL_DEFAULT, &g_pShadowMap,
                     NULL ) ) )
{
   MessageBox( g_hWnd, "Unable to create shadow map!",
               "Error", MB_OK | MB_ICONERROR );
   return E_FAIL;
}
 
// Grab the texture's surface
g_pShadowMap->GetSurfaceLevel( 0, &g_pShadowSurf );

 

為了完成陰影映射圖,我們要把場景的深度信息渲染到陰影映射圖中。為此在光源的世界-視點-投影變換矩陣(world-view-projection matrix)下渲染整個場景。下面是構造這些矩陣的代碼:

// Ordinary view matrix 
D3DXMatrixLookAtLH( &matView, &vLightPos, &vLightAim, &g_vUp );
// Projection matrix for the light
D3DXMatrixPerspectiveFovLH( &matProj, D3DXToRadian(30.0f),
1.0f, 1.0f, 1024.0f );

//實際上作者在例程中使用的是D3DXMatrixOrthoLH( &matProj, 45.0f, 45.0f, 1.0f, //1024.0f )。這個函數所構造的project矩陣與D3DXMatrixPerspectiveFovLH()構造的//不同之處在于:它沒有透視效果。即物體的大小與視點和物體的距離沒有關系。顯然例//程中模擬的是平行光源(direction light),而這里模擬的是聚光燈源(spot light不知翻譯得對不對?)

// Concatenate the world matrix with the above 
// two to get the required matrix
matLightViewProj = matWorld * matView * matProj;
 

下面是渲染場景深度的頂點渲染和像素渲染的代碼:

 

// Shadow generation vertex shader
struct VSOUTPUT_SHADOW
{
   float4 vPosition    : POSITION;
   float  fDepth       : TEXCOORD0;
};
 
VSOUTPUT_SHADOW VS_Shadow( float4 inPosition : POSITION )
{
   // Output struct
   VSOUTPUT_SHADOW OUT = (VSOUTPUT_SHADOW)0;
   // Output the transformed position
   OUT.vPosition = mul( inPosition, g_matLightViewProj );
   // Output the scene depth
   OUT.fDepth = OUT.vPosition.z;
   return OUT;
}

這里我們將頂點的位置與變換矩陣相乘,并將變換后的z值作為深度。在像素渲染中將深度值以顏色(color)的方式輸出。

float4  PS_Shadow( VSOUTPUT_SHADOW IN ) : COLOR0
{
   // Output the scene depth
   return float4( IN.fDepth, IN.fDepth, IN.fDepth, 1.0f );
}

瞧,我們完成了陰影映射圖,下面就是以顏色方式輸出的陰影映射圖,深藍色部分表明較小的深度值,淺藍色部分表明較大的深度值。

步驟二:將帶陰影的場景渲染到緩沖中

下面,我們要把場景的帶陰影的部分渲染到并不立即顯示的緩沖中,使我們可以進行模糊處理,然后再將它投射回屏幕。首先把場景的陰影部分渲染到一幅屏幕大小的定點紋理中。

// Create the screen-sized buffer map 
if( FAILED( g_pd3dDevice->CreateTexture( SCREEN_WIDTH,
            SCREEN_HEIGHT, 1, D3DUSAGE_RENDERTARGET,
            D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT,
            &g_pScreenMap, NULL ) ) )
{
   MessageBox( g_hWnd, "Unable to create screen map!",
               "Error", MB_OK | MB_ICONERROR );
   return E_FAIL;
}
// Grab the texture's surface
g_pScreenMap->GetSurfaceLevel( 0, & g_pScreenSurf );

為了獲得投影紋理坐標(projective texture coordinates),我們需要一個紋理矩陣,作用是把投影空間(projection space)中的位置變換到紋理空間(texture space)中去。

// Generate the texture matrix
float fTexOffs = 0.5 + (0.5 / (float)SHADOW_MAP_SIZE);
D3DXMATRIX matTexAdj( 0.5f,     0.0f,      0.0f,  0.0f,
                          0.0f,     -0.5f,     0.0f,  0.0f,
                          0.0f,      0.0f,     1.0f,  0.0f,
                          fTexOffs, fTexOffs, 0.0f, 1.0f );
//這個矩陣是把projection space中范圍為[-11]x,y坐標值轉換到紋理空間中
//[01]的范圍中去。注意y軸的方向改變了。那個(0.5 / (float)SHADOW_MAP_SIZE)
//的值有什么作用我還不清楚,原文也沒有說明。
 
matTexture = matLightViewProj * matTexAdj;
 

我們像往常那樣通過深度的比較來獲得陰影因數,但隨后并不是像平常那樣輸出整個照亮了的場景,我們只輸出陰影因數。下面的頂點渲染和像素渲染完成這個工作。

// Shadow mapping vertex shader
struct VSOUTPUT_UNLIT
{
   float4 vPosition   : POSITION;
   float4 vTexCoord   : TEXCOORD0;
   float  fDepth      : TEXCOORD1;
};
 
VSOUTPUT_UNLIT VS_Unlit( float4 inPosition : POSITION )
{
   // Output struct
   VSOUTPUT_UNLIT OUT = (VSOUTPUT_UNLIT)0;
 
   // Output the transformed position
   OUT.vPosition = mul( inPosition, g_matWorldViewProj );
 
   // Output the projective texture coordinates
   OUT.vTexCoord = mul( inPosition, g_matTexture );
 
   // Output the scene depth
   OUT.fDepth = mul( inPosition, g_matLightViewProj ).z;
 
   return OUT;
}

我們采用percentage closer filtering (PCF)來平滑鋸齒邊緣。為了完成“PCF”,我們簡單的對周圍8個紋理點進行采樣,并取得它們深度比較的平均值。

// Shadow mapping pixel shader
//注意這里采用的是tex2Dproj()函數以及轉換到紋理空間的向量(x,y,z,w)對紋理進//行采樣。這與d3d9sdkshadowmap例子用tex2D()及向量(x,y)進行采樣不同。具體//區別及原因很容易從程序中看出,我就不再啰嗦了。
float4  PS_Unlit( VSOUTPUT_UNLIT IN ) : COLOR0
{
   // Generate the 9 texture co-ordinates for a 3x3 PCF kernel
   float4 vTexCoords[9];
   // Texel size
   float fTexelSize = 1.0f / 1024.0f;
 
   // Generate the tecture co-ordinates for the specified depth-map size
   // 4 3 5
   // 1 0 2
   // 7 6 8
   VTexCoords[0] = IN.vTexCoord;
   vTexCoords[1] = IN.vTexCoord + float4( -fTexelSize, 0.0f, 0.0f, 0.0f );
   vTexCoords[2] = IN.vTexCoord + float4(  fTexelSize, 0.0f, 0.0f, 0.0f );
   vTexCoords[3] = IN.vTexCoord + float4( 0.0f, -fTexelSize, 0.0f, 0.0f );
   vTexCoords[6] = IN.vTexCoord + float4( 0.0f,  fTexelSize, 0.0f, 0.0f );
   vTexCoords[4] = IN.vTexCoord + float4( -fTexelSize, -fTexelSize, 0.0f, 0.0f );
   vTexCoords[5] = IN.vTexCoord + float4(  fTexelSize, -fTexelSize, 0.0f, 0.0f );
   vTexCoords[7] = IN.vTexCoord + float4( -fTexelSize,  fTexelSize, 0.0f, 0.0f );
   vTexCoords[8] = IN.vTexCoord + float4(  fTexelSize,  fTexelSize, 0.0f, 0.0f );
   // Sample each of them checking whether the pixel under test is shadowed or not
   float fShadowTerms[9];
   float fShadowTerm = 0.0f;
   for( int i = 0; i < 9; i++ )
   {
      float A = tex2Dproj( ShadowSampler, vTexCoords[i] ).r;
      float B = (IN.fDepth - 0.1f);
 
      // Texel is shadowed
      fShadowTerms[i] = A < B ? 0.0f : 1.0f;
      fShadowTerm     += fShadowTerms[i];
   }
   // Get the average
   fShadowTerm /= 9.0f;
   return fShadowTerm;
}

屏幕緩沖完成了,我們還需要進行模糊工作。

步驟三:對屏幕緩沖進行模糊

我們采用seperable gaussian filter模糊屏幕緩沖。但我們也可以用Poisson filter。這次的render targetsA8R8G8B8的紋理和相關的表面。我們需要兩個render targets,一個進行水平階段,一個進行垂直階段。

// Create the blur maps
for( int i = 0; i < 2; i++ )
{
   if( FAILED( g_pd3dDevice->CreateTexture( SCREEN_WIDTH,
                           SCREEN_HEIGHT, 1, D3DUSAGE_RENDERTARGET,
                           D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT,
                           &g_pBlurMap[i], NULL ) ) )
   {
      MessageBox( g_hWnd, "Unable to create blur map!",
                  "Error", MB_OK | MB_ICONERROR );
      return E_FAIL;
   }
  // Grab the texture's surface
   g_pBlurMap[i]->GetSurfaceLevel( 0, & g_pBlurSurf[i] );
}

我們用下面的代碼生成15個高斯偏移量(Gaussian offsets)及他們的權重(corresponding weights)。

float GetGaussianDistribution( float x, float y, float rho )
{
   float g = 1.0f / sqrt( 2.0f * 3.141592654f * rho * rho );
   return g * exp( -(x * x + y * y) / (2 * rho * rho) );
}
 
void GetGaussianOffsets( bool bHorizontal,
                         D3DXVECTOR2 vViewportTexelSize,
                         D3DXVECTOR2* vSampleOffsets,
                         float* fSampleWeights )
{
   // Get the center texel offset and weight
   fSampleWeights[0] = 1.0f * GetGaussianDistribution( 0, 0, 2.0f );
   vSampleOffsets[0] = D3DXVECTOR2( 0.0f, 0.0f );
   // Get the offsets and weights for the remaining taps
   if( bHorizontal )
   {
      for( int i = 1; i < 15; i += 2 )
      {
         vSampleOffsets[i + 0] = D3DXVECTOR2( i * vViewportTexelSize.x, 0.0f );
         vSampleOffsets[i + 1] = D3DXVECTOR2( -i * vViewportTexelSize.x, 0.0f );
         fSampleWeights[i + 0] = 2.0f * GetGaussianDistribution( float(i + 0), 0.0f, 3.0f );
         fSampleWeights[i + 1] = 2.0f * GetGaussianDistribution( float(i + 1), 0.0f, 3.0f );
      }
   }
   else 
   {
      for( int i = 1; i < 15; i += 2 )
      {
         vSampleOffsets[i + 0] = D3DXVECTOR2( 0.0f, i * vViewportTexelSize.y );
         vSampleOffsets[i + 1] = D3DXVECTOR2( 0.0f, -i * vViewportTexelSize.y );
         fSampleWeights[i + 0] = 2.0f * GetGaussianDistribution( 0.0f, float(i + 0), 3.0f );
         fSampleWeights[i + 1] = 2.0f * GetGaussianDistribution( 0.0f, float(i + 1), 3.0f );
      }
   }

}

為了模糊屏幕緩沖,我們將模糊映射圖(blur map)作為render target,使用下面的頂點渲染和像素渲染代碼渲染一個與屏幕等大的方塊。

// 作者在程序中預先定義的屏幕大小是1024 * 768,而隨后定義的與屏幕等大的方塊為:

// pVertices[0].p = D3DXVECTOR4( 0.0f, 0.0f, 0.0f, 1.0f );

//  pVertices[1].p = D3DXVECTOR4( 0.0f, 768 / 2, 0.0f, 1.0f );

//  pVertices[2].p = D3DXVECTOR4( 1024 / 2, 0.0f, 0.0f, 1.0f );

//  pVertices[3].p = D3DXVECTOR4( 1024 / 2, 768 / 2, 0.0f, 1.0f );

//  這種方法與d3dsdkHDRLight中獲得render target width and height然后再構造的//  方法不同

// svQuad[0].p = D3DXVECTOR4(-0.5f, -0.5f, 0.5f, 1.0f);

// svQuad[1].p = D3DXVECTOR4(Width-0.5f, -0.5f, 0.5f, 1.0f);

// svQuad[2].p = D3DXVECTOR4(-0.5f, Height-0.5f, 0.5f, 1.0f);

// svQuad[3].p = D3DXVECTOR4(Width-0.5f,fHeight-0.5f, 0.5f, 1.0f);

// 而一般定義的窗口大小往往與從render target獲得的width and height不相同。

// 而二者的fvf都是D3DFVF_XYZRHW。這兩種方法有什么區別我一直沒想通。

 

// Gaussian filter vertex shader
struct VSOUTPUT_BLUR
{
   float4 vPosition    : POSITION;
   float2 vTexCoord    : TEXCOORD0;
};
 
VSOUTPUT_BLUR VS_Blur( float4 inPosition : POSITION, float2 inTexCoord : TEXCOORD0 )
{
   // Output struct
   VSOUTPUT_BLUR OUT = (VSOUTPUT_BLUR)0;
   // Output the position
   OUT.vPosition = inPosition;
   // Output the texture coordinates
   OUT.vTexCoord = inTexCoord;
   return OUT;
}
// Horizontal blur pixel shader
float4 PS_BlurH( VSOUTPUT_BLUR IN ): COLOR0
{
   // Accumulated color
   float4 vAccum = float4( 0.0f, 0.0f, 0.0f, 0.0f );
   // Sample the taps (g_vSampleOffsets holds the texel offsets
   // and g_fSampleWeights holds the texel weights)
   for(int i = 0; i < 15; i++ )
   {
      vAccum += tex2D( ScreenSampler, IN.vTexCoord + g_vSampleOffsets[i] ) * g_fSampleWeights[i];
   }
   return vAccum;
}
 
// Vertical blur pixel shader
float4 PS_BlurV( VSOUTPUT_BLUR IN ): COLOR0
{
   // Accumulated color
   float4 vAccum = float4( 0.0f, 0.0f, 0.0f, 0.0f );
   // Sample the taps (g_vSampleOffsets holds the texel offsets and
   // g_fSampleWeights holds the texel weights)
   for( int i = 0; i < 15; i++ )
   {
      vAccum += tex2D( BlurHSampler, IN.vTexCoord + g_vSampleOffsets[i] ) * g_fSampleWeights[i];
   }
   return vAccum;
}

這里,模糊映射圖已經完成了,為了增加陰影的模糊程度,增加了紋理上點的采樣距離。最后一步自然是將模糊后的紋理圖投射回屏幕空間使其顯示在屏幕上。

After first Gaussian pass

After second Gaussian pass

步驟四:渲染帶陰影的場景

為了將模糊后的紋理投射到屏幕上,我們像平常那樣渲染場景,但投影模糊后的紋理時要使用屏幕空間的坐標。我們使用裁剪空間的坐標和一些數學方法來產生屏幕空間的坐標。下面的頂點渲染和像素渲染將完成這個工作:

struct VSOUTPUT_SCENE
{
   float4 vPosition      : POSITION;
   float2 vTexCoord      : TEXCOORD0;
   float4 vProjCoord     : TEXCOORD1;
   float4 vScreenCoord   : TEXCOORD2;
   float3 vNormal        : TEXCOORD3;
   float3 vLightVec      : TEXCOORD4;
   float3 vEyeVec        : TEXCOORD5;
};
// Scene vertex shader
VSOUTPUT_SCENE VS_Scene( float4 inPosition : POSITION,
                         float3 inNormal : NORMAL,
                         float2 inTexCoord : TEXCOORD0 )
{
   VSOUTPUT_SCENE OUT = (VSOUTPUT_SCENE)0;
   // Output the transformed position
   OUT.vPosition = mul( inPosition, g_matWorldViewProj );
 
   // Output the texture coordinates
   OUT.vTexCoord = inTexCoord;
 
   // Output the projective texture coordinates (we use this
   // to project the spot texture down onto the scene)
   // 這個是用來產生light map的紋理坐標的。最終效果圖中地面上光照效果就是用
//  這個坐標配合上一幅這樣的light map實現的。

 
   OUT.vProjCoord = mul( inPosition, g_matTexture );
 
   // Output the screen-space texture coordinates
   // 這個就是將裁剪空間的坐標轉換到屏幕空間的坐標,方法和裁剪空間的坐標轉換
//  紋理空間的坐標的方法很相似。
   OUT.vScreenCoord.x = ( OUT.vPosition.x * 0.5 + OUT.vPosition.w * 0.5 );
   OUT.vScreenCoord.y = ( OUT.vPosition.w * 0.5 - OUT.vPosition.y * 0.5 );
   OUT.vScreenCoord.z = OUT.vPosition.w;
   OUT.vScreenCoord.w = OUT.vPosition.w;
 
   // Get the world space vertex position
   float4 vWorldPos = mul( inPosition, g_matWorld );
 
   // Output the world space normal
   OUT.vNormal = mul( inNormal, g_matWorldIT );
 
   // Move the light vector into tangent space
   OUT.vLightVec = g_vLightPos.xyz - vWorldPos.xyz;
 
   // Move the eye vector into tangent space
   OUT.vEyeVec = g_vEyePos.xyz - vWorldPos.xyz;
   return OUT;
}
float4 PS_Scene( VSOUTPUT_SCENE IN ) : COLOR0
{
   // Normalize the normal, light and eye vectors
   IN.vNormal   = normalize( IN.vNormal );
   IN.vLightVec = normalize( IN.vLightVec );
   IN.vEyeVec   = normalize( IN.vEyeVec );
   // Sample the color and normal maps
   float4 vColor  = tex2D( ColorSampler, IN.vTexCoord );
   // Compute the ambient, diffuse and specular lighting terms
   float ambient  = 0.0f;
   float diffuse  = max( dot( IN.vNormal, IN.vLightVec ), 0 );
   float specular = pow(max(dot( 2 * dot( IN.vNormal, IN.vLightVec ) * IN.vNormal
                                 - IN.vLightVec, IN.vEyeVec ), 0 ), 8 );
   if( diffuse == 0 ) specular = 0;
   // Grab the shadow term
   float fShadowTerm = tex2Dproj( BlurVSampler, IN.vScreenCoord );
   // Grab the spot term
   float fSpotTerm = tex2Dproj( SpotSampler, IN.vProjCoord );
   // Compute the final color
   return (ambient * vColor) +
          (diffuse * vColor * g_vLightColor * fShadowTerm * fSpotTerm) +
          (specular * vColor * g_vLightColor.a * fShadowTerm * fSpotTerm);
}

終于完成了。看上去不錯。該技術的優點一是解決了鋸齒問題,二是在多光源,低內存下實現了軟陰影。另外該技術與陰影生成方法無關,可以很容易的在shadow volumes技術中采用這項技術。缺點是由于進行了模糊處理而需要一些填充率。

下面是不同階段的效果比較圖:

謝謝你閱讀這篇文章,如有疑問歡迎來信anidex@yahoo.com. (這是原作者的信箱)

 

(汗,好多東西心里明白,但翻譯出來就是不滿意。各位要是看不明白就找出原文研究吧。)

參考文獻

  • Hardware Shadow Mapping. Cass Everitt, Ashu Rege and Cem Cebenoyan.
  • Hardware-accelerated Rendering of Antialiased Shadows with Shadow Maps. Stefan Brabec and Hans-Peter Seidel.
posted on 2005-12-23 02:19 苦行僧 閱讀(4695) 評論(0)  編輯 收藏 引用 所屬分類: 轉載
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            亚洲免费在线观看视频| 日韩视频在线观看一区二区| 午夜精品久久久久久久99热浪潮| 亚洲国产综合91精品麻豆| 香蕉久久夜色精品国产使用方法| 国产日韩欧美日韩| 久久精品成人欧美大片古装| 午夜影视日本亚洲欧洲精品| 国产一区二区看久久| 老司机精品久久| 欧美不卡福利| 中文av字幕一区| 久久婷婷国产综合国色天香| 伊人久久久大香线蕉综合直播| 久久综合电影一区| 欧美高清视频一区二区| 亚洲免费中文字幕| 久久久久一区| 亚洲精品在线一区二区| 99在线精品视频在线观看| 国产日韩欧美不卡在线| 欧美国产视频在线| 国产精品久久久久aaaa樱花| 久久不射电影网| 欧美成人一区在线| 欧美一区二区三区在线视频| 久久综合电影| 亚洲欧美日韩精品在线| 免费成人黄色片| 亚洲欧美综合v| 欧美不卡视频一区| 欧美影院成年免费版| 欧美高清在线视频| 久久久精品999| 欧美视频在线一区| 免费在线国产精品| 国产欧美欧洲在线观看| 亚洲人成网站精品片在线观看| 国产一区二区三区黄| 99成人精品| 日韩天天综合| 久久五月激情| 久久久午夜视频| 国产精品久久久久久福利一牛影视 | 欧美日本一区二区视频在线观看 | 99re8这里有精品热视频免费| 翔田千里一区二区| 亚洲欧美久久| 欧美日韩精品在线| 亚洲夫妻自拍| 亚洲激情一区| 久久亚洲免费| 噜噜噜躁狠狠躁狠狠精品视频 | 国产视频在线观看一区二区| 99国产一区| 一本色道久久综合亚洲精品高清| 狂野欧美激情性xxxx| 蜜桃久久av一区| 尤物yw午夜国产精品视频| 欧美一区二视频| 久久精品二区| 黄色成人在线| 久久这里有精品15一区二区三区| 久久综合九色欧美综合狠狠| 国产一区二区精品久久99| 亚洲男女自偷自拍| 久久不射中文字幕| 黄色小说综合网站| 久久香蕉国产线看观看av| 乱人伦精品视频在线观看| 国语自产精品视频在线看抢先版结局 | 久久成人免费日本黄色| 亚洲欧美日韩综合aⅴ视频| 欧美日韩麻豆| 99精品欧美| 欧美在线高清视频| 国产真实乱偷精品视频免| 久久精品国产一区二区三区| 免费日韩视频| 一本在线高清不卡dvd| 欧美日韩亚洲一区| 亚洲欧美精品中文字幕在线| 久久久久久久久久久久久女国产乱 | 亚洲视频在线观看免费| 欧美一区二区网站| 狠狠色香婷婷久久亚洲精品| 狂野欧美激情性xxxx| 日韩亚洲欧美在线观看| 欧美亚洲专区| 一区二区三区自拍| 欧美精品免费播放| 亚洲欧美日本国产有色| 免费短视频成人日韩| 一区二区三区日韩精品视频| 国产欧美一区二区三区沐欲| 久久香蕉国产线看观看av| 夜夜夜久久久| 久久综合久久久| 一区二区三欧美| 国产一区二区0| 欧美久久一级| 久久久99国产精品免费| 亚洲精品少妇| 免费成人在线视频网站| 亚洲永久在线| 亚洲精品久久久久久一区二区 | 久久夜色精品国产亚洲aⅴ| 亚洲国产精品久久久久秋霞不卡 | 亚洲精品一区二区三| 国产精品一区二区三区成人| 免费亚洲一区二区| 亚洲欧美成人网| 最新日韩在线| 狼人社综合社区| 午夜精品亚洲一区二区三区嫩草| 亚洲国产精品成人| 国产美女精品视频免费观看| 欧美激情中文字幕在线| 久久久免费观看视频| 一区二区三区四区蜜桃| 亚洲福利国产精品| 久久婷婷av| 久久久亚洲国产美女国产盗摄| 亚洲欧美日韩国产中文在线| 国产精品美女久久久久久久 | 欧美伦理一区二区| 久久久午夜电影| 小处雏高清一区二区三区| 日韩小视频在线观看专区| 亚洲第一区在线观看| 久久夜色精品国产亚洲aⅴ| 欧美一区二区三区四区视频| 这里只有精品视频| 亚洲精选一区二区| 亚洲人成网站777色婷婷| 欧美大片va欧美在线播放| 欧美亚洲免费高清在线观看| 亚洲在线第一页| 在线亚洲精品| 一区二区三区鲁丝不卡| 99v久久综合狠狠综合久久| 日韩一级二级三级| 亚洲精品美女久久久久| 亚洲精品乱码| 日韩一级在线| 亚洲午夜视频| 亚洲欧美视频在线| 欧美一区二视频| 久热这里只精品99re8久| 久久先锋影音| 欧美激情偷拍| 欧美午夜精品久久久| 国产精品久久久久久久久久三级 | 狠狠色狠狠色综合人人| 在线观看一区| 亚洲裸体视频| 亚洲已满18点击进入久久| 欧美一级专区| 蜜臀av在线播放一区二区三区| 女同一区二区| 亚洲精品国久久99热| 一区二区三区四区蜜桃| 欧美一区二区在线免费播放| 蜜月aⅴ免费一区二区三区| 欧美精品一区二区三| 国产精品成人久久久久| 国产亚洲一区在线| 最新国产精品拍自在线播放| 在线午夜精品自拍| 久久精品成人欧美大片古装| 亚洲电影网站| 亚洲午夜久久久| 久久蜜桃精品| 欧美日韩成人综合在线一区二区| 国产精品亚洲激情| 亚洲国产成人久久综合一区| 亚洲一区二区免费| 久久美女性网| 日韩一级在线观看| 久久久久久高潮国产精品视| 欧美日韩成人| 黄色成人小视频| 亚洲欧美激情诱惑| 欧美大片免费看| 亚洲夜晚福利在线观看| 老色批av在线精品| 国产精品一区在线观看你懂的| 亚洲激情黄色| 久久国产精品一区二区三区| 亚洲国产高清aⅴ视频| 午夜欧美大片免费观看| 欧美啪啪成人vr| 永久555www成人免费| 亚洲无吗在线| 亚洲丶国产丶欧美一区二区三区| 午夜视频一区在线观看| 欧美日韩综合网| 亚洲乱码视频| 欧美激情小视频| 久久久国产精品一区二区中文|