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

eryar

PipeCAD - Plant Piping Design Software.
RvmTranslator - Translate AVEVA RVM to OBJ, glTF, etc.
posts - 603, comments - 590, trackbacks - 0, articles - 0

Surface Normal Averaging

Posted on 2014-02-27 21:47 eryar 閱讀(4504) 評(píng)論(0)  編輯 收藏 引用 所屬分類: 2.OpenCASCADE

Surface Normal Averaging

eryar@163.com

摘要Abstract:正確設(shè)置網(wǎng)格面上點(diǎn)的法向,對(duì)幾何體在光照等情況下顯示得更真實(shí),這樣就可以減少頂點(diǎn)數(shù)量,提高渲染速度。本文通過(guò)將OpenCascade中的形狀離散成網(wǎng)格數(shù)據(jù)后在OpenSceneGraph中顯示,及使用OSG的快速法向osgUtil::SmoothingVisitor優(yōu)化與使用OpenCascade來(lái)計(jì)算正確的法向的結(jié)果的對(duì)比,說(shuō)明面法向量的重要性。

關(guān)鍵字Key Words:OpenCascade, OpenSceneGraph, Normal Averaging, Triangulation Mesh

一、引言 Introduction

OpenGL中的頂點(diǎn)(Vertex)不是一個(gè)值,而由其空間坐標(biāo)值、法向、顏色坐標(biāo)、紋理坐標(biāo)、霧坐標(biāo)等所組成的一個(gè)集合。一個(gè)最基本的幾何體對(duì)象至少需要設(shè)置一個(gè)合法的頂點(diǎn)數(shù)組,并記錄頂點(diǎn)數(shù)據(jù);如有必要,還可以設(shè)置顏色數(shù)組、法線數(shù)組、紋理坐標(biāo)數(shù)組等多種信息。

在很多應(yīng)用中,網(wǎng)格上的各點(diǎn)都需要一個(gè)表面法向量,它的作用非常廣泛。例如可用來(lái)計(jì)算光照、背面剔除、模擬粒子系統(tǒng)在表面的“彈跳”效果、通過(guò)只需要正面而加速碰撞檢測(cè)等。

wps_clip_image-22656

Figure 1.1 Lighting on a surface

wps_clip_image-29877

Figure 1.2 Light is reflected off objects at specific angles

如上圖所示,物體在光照情況下的反射光等的計(jì)算是與法向N有關(guān)的。

二、OpenCascade中面的法向計(jì)算 Finding Normal for OpenCascade Face

在OpenCascade中可以將拓樸形狀轉(zhuǎn)換成STL格式的文件進(jìn)行模型的數(shù)據(jù)交換。其中STL結(jié)構(gòu)中只保存了三角網(wǎng)格的頂點(diǎn)坐標(biāo)和三角面的法向量。為了將拓樸數(shù)據(jù)轉(zhuǎn)換成STL的網(wǎng)格數(shù)據(jù),先將拓樸形狀進(jìn)行三角剖分,再將剖分的網(wǎng)格保存成STL即可。其中每個(gè)三角面的法向計(jì)算也是直接根據(jù)兩個(gè)向量的叉乘得來(lái)。

wps_clip_image-29679

Figure 2.1 A normal vector as cross product of two vectors

實(shí)現(xiàn)文件是RWStl.cxx,其中計(jì)算法向的程序代碼如下所示:

 

//=====================================================================//function : WriteBinary
//purpose  : write a binary STL file in Little Endian format
//=====================================================================
Standard_Boolean RWStl::WriteBinary (const Handle(StlMesh_Mesh)& theMesh,
                                    
const OSD_Path& thePath,
                                    
const Handle(Message_ProgressIndicator)& theProgInd)
{
  OSD_File aFile (thePath);
  aFile.Build (OSD_WriteOnly, OSD_Protection());

  Standard_Real x1, y1, z1;
  Standard_Real x2, y2, z2;
  Standard_Real x3, y3, z3;

 
// writing 80 bytes of the trash?
  char sval[80];
  aFile.Write ((Standard_Address)sval,
80);
  WriteInteger (aFile, theMesh
->NbTriangles());

 
int dum=0;
  StlMesh_MeshExplorer aMexp (theMesh);

 
// create progress sentry for domains
  Standard_Integer aNbDomains = theMesh->NbDomains();
  Message_ProgressSentry aDPS (theProgInd,
"Mesh domains", 0, aNbDomains, 1);
 
for (Standard_Integer nbd = 1; nbd <= aNbDomains && aDPS.More(); nbd++, aDPS.Next())
  {
   
// create progress sentry for triangles in domain
    Message_ProgressSentry aTPS (theProgInd, "Triangles", 0,
        theMesh
->NbTriangles (nbd), IND_THRESHOLD);
    Standard_Integer aTriangleInd
= 0;
   
for (aMexp.InitTriangle (nbd); aMexp.MoreTriangle(); aMexp.NextTriangle())
    {
      aMexp.TriangleVertices (x1,y1,z1,x2,y2,z2,x3,y3,z3);
     
//pgo      aMexp.TriangleOrientation (x,y,z);
      gp_XYZ Vect12 ((x2-x1), (y2-y1), (z2-z1));
      gp_XYZ Vect13 ((x3
-x1), (y3-y1), (z3-z1));
      gp_XYZ Vnorm
= Vect12 ^ Vect13;
      Standard_Real Vmodul
= Vnorm.Modulus ();
     
if (Vmodul > gp::Resolution())
      {
        Vnorm.Divide(Vmodul);
      }
     
else
      {
       
// si Vnorm est quasi-nul, on le charge a 0 explicitement
        Vnorm.SetCoord (0., 0., 0.);
      }

      WriteDouble2Float (aFile, Vnorm.X());
      WriteDouble2Float (aFile, Vnorm.Y());
      WriteDouble2Float (aFile, Vnorm.Z());

      WriteDouble2Float (aFile, x1);
      WriteDouble2Float (aFile, y1);
      WriteDouble2Float (aFile, z1);

      WriteDouble2Float (aFile, x2);
      WriteDouble2Float (aFile, y2);
      WriteDouble2Float (aFile, z2);

      WriteDouble2Float (aFile, x3);
      WriteDouble2Float (aFile, y3);
      WriteDouble2Float (aFile, z3);

      aFile.Write (
&dum, 2);

     
// update progress only per 1k triangles
      if (++aTriangleInd % IND_THRESHOLD == 0)
      {
       
if (!aTPS.More())
         
break;
        aTPS.Next();
      }
    }
  }
  aFile.Close();
  Standard_Boolean isInterrupted
= !aDPS.More();
 
return !isInterrupted;
}

這種方式渲染的圖形效果如下圖所示:

wps_clip_image-11876

Figure 2.2 A typical sphere made up of triangles

上面的球面是由三角形組成,由OpenCascade的三角剖分算法生成。如果將每個(gè)三角面的法向作為每個(gè)頂點(diǎn)的法向,則渲染效果如下圖所示:

wps_clip_image-31623

Figure 2.3 Specific the triangle face normal as the vertex normal of the trangle

如上圖所示,在光照效果下每個(gè)三角面界限分明,感覺(jué)不是很光滑,面之間的過(guò)渡很生硬。

三、OpenSceneGraph中面的法向計(jì)算 Finding Normal for OpenSceneGraph Mesh

直接將網(wǎng)格頂點(diǎn)的法向設(shè)置成三角面的法向產(chǎn)生的效果不是很理想,通過(guò)改變頂點(diǎn)法向的方向可以讓曲面更滑,這種技術(shù)稱為法向平均(Normal Averaging)。利用法向平均技術(shù)可以產(chǎn)生一些有意思的視覺(jué)效果。如果有個(gè)面像下面圖所示:

wps_clip_image-28615

Figure 3.1 Jagged surface with the usual surface normals

當(dāng)我們考慮兩個(gè)相連面的頂點(diǎn)處的法向?yàn)閮上噙B面的法向的平均值時(shí),那么這兩個(gè)相連表面的連接處在OpenGL中渲染時(shí)看上去就不那么棱角分明了,如下圖所示:

wps_clip_image-19581

Figure 3.2 Averaging the normals will make sharp corners appear softer

對(duì)于球面或更一般的自由曲面,法向平均的算法也是適用的。如下圖所示:

wps_clip_image-25766

Figure 3.3 An approximation with normals perpendicular to each face

wps_clip_image-16699

Figure 3.4 Each normal is perpendicular to the surface itself

球面的法向計(jì)算還是相當(dāng)簡(jiǎn)單的。但是對(duì)于一般的曲面就不是那么容易了。這種情況下需要計(jì)算多邊形面片相連處的頂點(diǎn)的法向,將相連接處的頂點(diǎn)的法向設(shè)置為各相鄰面的平均法向后,視覺(jué)效果還是很棒的,光滑。

The actual normal you assign to that vertex is the average of these normals. The visual effect is a nice, smooth, regular surface, even though it is actually composed of numerous small, flat segments.

在OpenSceneGraph中生成頂點(diǎn)法向量的類是osgUtil::SmoothingVisitor,它使用了Visitor的模式,通過(guò)遍歷場(chǎng)景中的幾何體,生成頂點(diǎn)的法向量。對(duì)于上面同一個(gè)球的網(wǎng)格,使用osgUtil::SmoothingVisitor生成法向后在光照下的顯示效果如下圖所示:

wps_clip_image-27777

Figure 3.5 Use osgUtil::SmoothingVisitor to generate normals for the sphere

四、計(jì)算正確的法向 Finding the Correct Normal for the Face

不管是STL中三角面的法向還是使用osgUtil::SmoothingVisitor來(lái)生成面的法向都是無(wú)奈之舉,因?yàn)槎际窃陔x散的三角網(wǎng)格上找出法向,不精確,在光照下渲染效果都不是很理想。但是OpenCascade作為幾何造型內(nèi)核,提供了計(jì)算曲面法向的功能,因此有能力計(jì)算出頂點(diǎn)處的法向的精確值。

當(dāng)計(jì)算網(wǎng)格曲面頂點(diǎn)的法向時(shí),共享頂點(diǎn)處的法向最好設(shè)置為頂點(diǎn)各相連面的法向的平均值。對(duì)于參數(shù)化的曲面,是可以直接計(jì)算出每個(gè)頂點(diǎn)處的法向,就不需要再求法向平均值了,因?yàn)橐呀?jīng)有了曲面法向數(shù)學(xué)定義的值。所以在OpenCascade中計(jì)算出來(lái)曲面中某個(gè)頂點(diǎn)的法向就是數(shù)學(xué)定義上面的法向。計(jì)算方法如下:

對(duì)頂點(diǎn)處的參數(shù)u,v分別求一階導(dǎo)數(shù),得出頂點(diǎn)處在u,v方向的切向量,如下圖所示:

wps_clip_image-22287

Figure 4.1 Derivatives with respect to u and v 

wps_clip_image-1012

Figure 4.1 Tangents on a surface

將u和v方向的切向量叉乘就得到了該頂點(diǎn)處的法向,計(jì)算方法如下所示:

wps_clip_image-25225

叉乘后頂點(diǎn)處的法向如下圖所示:

wps_clip_image-22056

Figure 4.2 Normal on a surface

OpenCascade中計(jì)算曲面表面屬性的類是BRepLProp_SLProps,計(jì)算法向部分程序如下所示:

 

Standard_Boolean LProp_SLProps::IsNormalDefined()
{

 
if (normalStatus == LProp_Undefined) {
   
return Standard_False;
  }
 
else if (normalStatus >= LProp_Defined) {
   
return Standard_True;
  }
 
 
// first try the standard computation of the normal.
  CSLib_DerivativeStatus Status;
  CSLib::Normal(d1U, d1V, linTol, Status, normal);
 
if (Status  == CSLib_Done ) {
    normalStatus
= LProp_Computed;
   
return Standard_True;
  }
 
  normalStatus
= LProp_Undefined;
 
return Standard_False;
}

此類的使用方法如下所示:

 

const TopoDS_Face& theFace = TopoDS::Face(faceExp.Current());
BRepLProp_SLProps theProp(BRepAdaptor_Surface(theFace),
1, Precision::Confusion());

theProp.SetParameters(u, v);

if (theProp.IsNormalDefined())
{
    gp_Vec theNormal
= theProp.Normal();
}

計(jì)算法向后渲染效果如下圖所示:

wps_clip_image-20387

Figure 4.3 Sphere vertex normals computed by BRepLProp_SLProps

由圖可知,OpenCascade計(jì)算的面的法向在渲染時(shí)效果很好。

五、程序示例 Putting It All Together

將這三種情況產(chǎn)生的渲染效果放在一起來(lái)比較,程序代碼如下所示:

 

/*
*    Copyright (c) 2014 eryar All Rights Reserved.
*
*           File : Main.cpp
*         Author : eryar@163.com
*           Date : 2014-02-25 17:00
*        Version : 1.0v
*
*    Description : Learn the Normal Averaging from OpenGL SuperBible.
*
*      Key Words : OpenCascade, OpenSceneGraph, Normal Averaging
*                 
*/

// OpenCascade library.
#define WNT
#include
<Poly_Triangulation.hxx>
#include
<TColgp_Array1OfPnt2d.hxx>

#include
<TopoDS.hxx>
#include
<TopoDS_Face.hxx>
#include
<TopoDS_Shape.hxx>
#include
<TopExp_Explorer.hxx>

#include
<BRep_Tool.hxx>
#include
<BRepAdaptor_Surface.hxx>
#include
<BRepLProp_SLProps.hxx>

#include
<BRepMesh.hxx>

#include
<BRepPrimAPI_MakeBox.hxx>
#include
<BRepPrimAPI_MakeCone.hxx>
#include
<BRepPrimAPI_MakeSphere.hxx>

#pragma comment(lib,
"TKernel.lib")
#pragma comment(lib,
"TKMath.lib")
#pragma comment(lib,
"TKG3d.lib")
#pragma comment(lib,
"TKBRep.lib")
#pragma comment(lib,
"TKMesh.lib")
#pragma comment(lib,
"TKPrim.lib")
#pragma comment(lib,
"TKTopAlgo.lib")


// OpenSceneGraph library.
#include <osg/MatrixTransform>
#include
<osg/Material>

#include
<osgGA/StateSetManipulator>

#include
<osgViewer/Viewer>
#include
<osgViewer/ViewerEventHandlers>

#include
<osgUtil/SmoothingVisitor>

#pragma comment(lib,
"osgd.lib")
#pragma comment(lib,
"osgDBd.lib")
#pragma comment(lib,
"osgGAd.lib")
#pragma comment(lib,
"osgUtild.lib")
#pragma comment(lib,
"osgViewerd.lib")
#pragma comment(lib,
"osgManipulatord.lib")

/**
* @breif Build the mesh for the OpenCascade TopoDS_Shape.
* @param [in] TopoDS_Shape theShape OpenCascade TopoDS_Shape.
* @param [in] Standard_Boolean bSetNormal If set to true, will set the vertex normal correctly
*             else will set vertex normal by its triangle face normal.
*/
osg::Geode
* BuildMesh(const TopoDS_Shape& theShape, Standard_Boolean bSetNormal = Standard_False)
{
    Standard_Real theDeflection
= 0.1;
    BRepMesh::Mesh(theShape, theDeflection);

    osg::ref_ptr
<osg::Geode> theGeode = new osg::Geode();

   
for (TopExp_Explorer faceExp(theShape, TopAbs_FACE); faceExp.More(); faceExp.Next())
    {
        TopLoc_Location theLocation;
       
const TopoDS_Face& theFace = TopoDS::Face(faceExp.Current());
       
const Handle_Poly_Triangulation& theTriangulation = BRep_Tool::Triangulation(theFace, theLocation);
        BRepLProp_SLProps theProp(BRepAdaptor_Surface(theFace),
1, Precision::Confusion());

       
if (theTriangulation.IsNull())
        {
           
continue;
        }

        osg::ref_ptr
<osg::Geometry> theMesh = new osg::Geometry();
        osg::ref_ptr
<osg::Vec3Array> theVertices = new osg::Vec3Array();
        osg::ref_ptr
<osg::Vec3Array> theNormals = new osg::Vec3Array();

       
for (Standard_Integer t = 1; t <= theTriangulation->NbTriangles(); ++t)
        {
           
const Poly_Triangle& theTriangle = theTriangulation->Triangles().Value(t);
            gp_Pnt theVertex1
= theTriangulation->Nodes().Value(theTriangle(1));
            gp_Pnt theVertex2
= theTriangulation->Nodes().Value(theTriangle(2));
            gp_Pnt theVertex3
= theTriangulation->Nodes().Value(theTriangle(3));

            gp_Pnt2d theUV1
= theTriangulation->UVNodes().Value(theTriangle(1));
            gp_Pnt2d theUV2
= theTriangulation->UVNodes().Value(theTriangle(2));
            gp_Pnt2d theUV3
= theTriangulation->UVNodes().Value(theTriangle(3));

            theVertex1.Transform(theLocation.Transformation());
            theVertex2.Transform(theLocation.Transformation());
            theVertex3.Transform(theLocation.Transformation());

           
// find the normal for the triangle mesh.
            gp_Vec V12(theVertex1, theVertex2);
            gp_Vec V13(theVertex1, theVertex3);
            gp_Vec theNormal
= V12 ^ V13;
            gp_Vec theNormal1
= theNormal;
            gp_Vec theNormal2
= theNormal;
            gp_Vec theNormal3
= theNormal;

           
if (theNormal.Magnitude() > Precision::Confusion())
            {
                theNormal.Normalize();
                theNormal1.Normalize();
                theNormal2.Normalize();
                theNormal3.Normalize();
            }

            theProp.SetParameters(theUV1.X(), theUV1.Y());
           
if (theProp.IsNormalDefined())
            {
                theNormal1
= theProp.Normal();
            }

            theProp.SetParameters(theUV2.X(), theUV2.Y());
           
if (theProp.IsNormalDefined())
            {
                theNormal2
= theProp.Normal();
            }

            theProp.SetParameters(theUV3.X(), theUV3.Y());
           
if (theProp.IsNormalDefined())
            {
                theNormal3
= theProp.Normal();
            }

           
if (theFace.Orientation() == TopAbs_REVERSED)
            {
                theNormal.Reverse();
                theNormal1.Reverse();
                theNormal2.Reverse();
                theNormal3.Reverse();
            }

            theVertices
->push_back(osg::Vec3(theVertex1.X(), theVertex1.Y(), theVertex1.Z()));
            theVertices
->push_back(osg::Vec3(theVertex2.X(), theVertex2.Y(), theVertex2.Z()));
            theVertices
->push_back(osg::Vec3(theVertex3.X(), theVertex3.Y(), theVertex3.Z()));

           
if (bSetNormal)
            {
                theNormals
->push_back(osg::Vec3(theNormal1.X(), theNormal1.Y(), theNormal1.Z()));
                theNormals
->push_back(osg::Vec3(theNormal2.X(), theNormal2.Y(), theNormal2.Z()));
                theNormals
->push_back(osg::Vec3(theNormal3.X(), theNormal3.Y(), theNormal3.Z()));
            }
           
else
            {
                theNormals
->push_back(osg::Vec3(theNormal.X(), theNormal.Y(), theNormal.Z()));
                theNormals
->push_back(osg::Vec3(theNormal.X(), theNormal.Y(), theNormal.Z()));
                theNormals
->push_back(osg::Vec3(theNormal.X(), theNormal.Y(), theNormal.Z()));
            }
        }

        theMesh
->setVertexArray(theVertices);
        theMesh
->setNormalArray(theNormals);
        theMesh
->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
        theMesh
->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES, 0, theVertices->size()));

        theGeode
->addDrawable(theMesh);
    }

   
// Set material for the mesh.
    osg::ref_ptr<osg::StateSet> theStateSet = theGeode->getOrCreateStateSet();
    osg::ref_ptr
<osg::Material> theMaterial = new osg::Material();

    theMaterial
->setDiffuse(osg::Material::FRONT, osg::Vec4(1.0f, 0.0f, 0.0f, 1.0f));
    theMaterial
->setSpecular(osg::Material::FRONT, osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
    theMaterial
->setShininess(osg::Material::FRONT, 100.0f);

    theStateSet
->setAttribute(theMaterial);

   
return theGeode.release();
}

osg::Node
* BuildScene(void)
{
    osg::ref_ptr
<osg::Group> theRoot = new osg::Group();

   
// 1. Build a sphere without setting vertex normal correctly.
    TopoDS_Shape theSphere = BRepPrimAPI_MakeSphere(1.6);
    osg::ref_ptr
<osg::Node> theSphereNode = BuildMesh(theSphere);
    theRoot
->addChild(theSphereNode);

   
// 2. Build a sphere without setting vertex normal correctly, but will
   
// use osgUtil::SmoothingVisitor to find the average normals.
    osg::ref_ptr<osg::MatrixTransform> theSmoothSphere = new osg::MatrixTransform();
    osg::ref_ptr
<osg::Geode> theSphereGeode = BuildMesh(theSphere);
    theSmoothSphere
->setMatrix(osg::Matrix::translate(5.0, 0.0, 0.0));

   
// Use SmoothingVisitor to find the vertex average normals.
    osgUtil::SmoothingVisitor sv;
    sv.apply(
*theSphereGeode);

    theSmoothSphere
->addChild(theSphereGeode);
    theRoot
->addChild(theSmoothSphere);

   
// 3. Build a sphere with setting vertex normal correctly.
    osg::ref_ptr<osg::MatrixTransform> theBetterSphere = new osg::MatrixTransform();
    osg::ref_ptr
<osg::Geode> theSphereGeode1 = BuildMesh(theSphere, Standard_True);
    theBetterSphere
->setMatrix(osg::Matrix::translate(10.0, 0.0, 0.0));

    theBetterSphere
->addChild(theSphereGeode1);
    theRoot
->addChild(theBetterSphere);

   
return theRoot.release();
}

int main(int argc, char* argv[])
{
    osgViewer::Viewer viewer;   

    viewer.setSceneData(BuildScene());

    viewer.addEventHandler(
new osgViewer::StatsHandler());
    viewer.addEventHandler(
new osgViewer::WindowSizeHandler());
    viewer.addEventHandler(
new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()));

   
return viewer.run();
}

生成效果圖如下所示:

wps_clip_image-7902

Figure 5.1 Same sphere triangulation mesh

wps_clip_image-5142

Figure 5.2 Same sphere mesh with different vertex normals

由上圖可知,相同的球面網(wǎng)格,當(dāng)頂點(diǎn)的法向?yàn)槿敲娴姆ㄏ驎r(shí),在有光照的情況下,渲染效果最差。使用osgUtil::SmoothingVisitor法向生成算法生成的頂點(diǎn)法向與使用類BRepLProp_SLProps計(jì)算出的法向,在光照情況下顯示效果相當(dāng)。

wps_clip_image-2529

Figure 5.3 Pipe and equipments with correct vertex normals

wps_clip_image-28058

六、結(jié)論 Conclusion

正確設(shè)置網(wǎng)格面頂點(diǎn)的法向可以在光照環(huán)境中看上去更光滑真實(shí)。利用法向平均算法或使用曲面的參數(shù)方程求解曲面頂點(diǎn)上法向,可以在滿足顯示效果基本相同的條件下減少網(wǎng)格頂點(diǎn)的數(shù)量,可以提高渲染速度。

七、參考資料 References

1. Waite group Press, OpenGL Super Bible(1st), Macmillan Computer Publishing, 1996

2. Richard S. Wright Jr., Benjamin Lipchak, OpenGL SuperBible(3rd), Sams Publishing, 2004

3. vsocc.cpp in netgen

4. Kelly Dempski, Focus on Curves and Surfaces, Premier Press, 2003

5. 王銳,錢學(xué)雷,OpenSceneGraph三維渲染引擎設(shè)計(jì)與實(shí)踐,清華大學(xué)出版社

6. 肖鵬,劉更代,徐明亮,OpenSceneGraph三維渲染引擎編程指南,清華大學(xué)出版社

 

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            久久成人综合视频| 亚洲综合色激情五月| 亚洲第一视频网站| 狠狠色综合日日| 在线播放视频一区| 亚洲精品小视频| 亚洲一区二区黄| 久久久久久免费| 亚洲国产精品热久久| 亚洲福利小视频| 一区二区国产在线观看| 亚洲一区在线视频| 久久天天躁狠狠躁夜夜av| 欧美成人性生活| 国产精品日韩精品欧美在线| 一区二区三区自拍| 一区二区三区四区蜜桃| 欧美与黑人午夜性猛交久久久| 久久影音先锋| 亚洲视频导航| 亚洲激情中文1区| 国产精品成人一区二区| 国产视频亚洲精品| 日韩写真视频在线观看| 久久国产精品电影| 亚洲人成人一区二区在线观看 | 99精品视频免费观看| 亚洲欧美区自拍先锋| 欧美超级免费视 在线| 国产精品99久久久久久白浆小说| 久久精品日韩一区二区三区| 欧美日韩综合视频网址| 亚洲国内在线| 久久精品理论片| 一区二区高清| 欧美精品一区二区精品网| 韩国av一区二区三区在线观看| 一区二区三区高清不卡| 欧美高清视频一区二区| 久久国产精品久久精品国产| 国产精品大全| 一区二区三区四区五区在线 | 中文日韩欧美| 欧美激情一二区| 久久精品国产综合| 国产亚洲在线| 欧美在线观看一区| 亚洲天天影视| 国产精品xxxxx| 亚洲一区在线看| 日韩午夜电影av| 欧美日韩成人激情| 制服诱惑一区二区| 一区二区免费看| 欧美天堂亚洲电影院在线播放| 日韩视频一区二区三区在线播放免费观看 | 夜夜嗨av一区二区三区中文字幕| 欧美黄色免费| 欧美福利精品| 99国产成+人+综合+亚洲欧美| 亚洲大胆av| 老司机精品视频一区二区三区| 国产精品久久久久久一区二区三区 | 欧美国产日韩二区| 亚洲黄色尤物视频| 亚洲国产精品久久精品怡红院| 欧美成人黄色小视频| 亚洲三级免费观看| 亚洲丰满在线| 一区二区三区精品国产| 日韩午夜在线视频| 欧美婷婷六月丁香综合色| 亚洲图片欧美一区| 在线一区欧美| 很黄很黄激情成人| 亚洲国产高清在线| 欧美色欧美亚洲另类二区| 亚洲欧美欧美一区二区三区| 午夜久久黄色| 1024欧美极品| 99国产精品国产精品毛片| 国产精品久久久99| 久久嫩草精品久久久精品| 老鸭窝毛片一区二区三区| 日韩亚洲在线观看| 亚洲午夜久久久久久尤物| 激情欧美丁香| 亚洲日本欧美| 国产精品综合| 欧美高清不卡在线| 国产精品亚洲综合| 亚洲高清影视| 国产视频观看一区| 亚洲日本免费| 激情久久五月| 亚洲在线免费观看| 亚洲乱码一区二区| 久久久久www| 亚洲一区中文| 嫩草国产精品入口| 欧美亚洲专区| 欧美精品久久99久久在免费线| 欧美在线影院在线视频| 欧美猛交免费看| 美女诱惑黄网站一区| 国产精品白丝av嫩草影院| 你懂的亚洲视频| 国产一区激情| 亚洲午夜久久久久久久久电影院| 亚洲成色最大综合在线| 亚洲综合电影| 中国av一区| 欧美国产大片| 欧美mv日韩mv亚洲| 国产亚洲精品一区二555| 亚洲精品美女在线观看播放| 激情欧美一区二区三区| 亚洲免费影视| 亚洲伊人观看| 欧美日韩免费高清| 亚洲精品视频免费观看| 亚洲精品国产视频| 欧美a级一区二区| 欧美大学生性色视频| 在线观看亚洲精品| 久久久人成影片一区二区三区| 久久国产日韩| 欧美一级成年大片在线观看| 欧美人在线视频| 亚洲国产精品视频| 亚洲欧洲精品一区二区三区| 久久久成人精品| 欧美成人a视频| 亚洲夫妻自拍| 亚洲免费观看高清完整版在线观看熊 | 麻豆91精品91久久久的内涵| 久久人人爽人人爽| 国内精品美女在线观看| 欧美一区影院| 久久综合99re88久久爱| 国内一区二区在线视频观看| 欧美一区日韩一区| 久热精品视频在线| 在线观看中文字幕不卡| 久久免费国产精品| 亚洲激情偷拍| 亚洲天堂成人在线视频| 国产精品久久久久久久久久尿| 亚洲午夜激情免费视频| 久久av老司机精品网站导航| 国产亚洲欧美日韩日本| 久久久国产精品亚洲一区 | 亚洲淫片在线视频| 国产日韩亚洲欧美综合| 久久久久久一区| 亚洲高清在线观看一区| 亚洲午夜成aⅴ人片| 国产老女人精品毛片久久| 久久成人免费| 亚洲丶国产丶欧美一区二区三区| 亚洲伦理精品| 国产日韩在线不卡| 欧美福利电影在线观看| 亚洲一区二区精品在线观看| 久久久久中文| 在线亚洲观看| 国产亚洲毛片在线| 欧美日韩国产精品专区| 亚洲自拍偷拍麻豆| 亚洲高清不卡一区| 欧美一级电影久久| 亚洲精品一区二区在线| 国产精品丝袜白浆摸在线| 卡一卡二国产精品| 亚洲线精品一区二区三区八戒| 久久一区二区视频| 国产精品99久久久久久白浆小说| 国产一区二区三区久久| 欧美精品黄色| 久久中文字幕导航| 亚洲欧美精品在线| 日韩一区二区高清| 欧美mv日韩mv国产网站| 欧美一区二区在线免费播放| 亚洲全部视频| 激情久久久久久| 国产日韩三区| 国产精品美女在线| 欧美精品一区二区三区四区| 久久岛国电影| 亚洲一区二区免费视频| 亚洲国产中文字幕在线观看| 久久香蕉国产线看观看网| 亚洲欧美春色| 一区二区三欧美| 亚洲精品在线观| 亚洲国产日韩欧美在线动漫 | 亚洲私拍自拍| 欧美freesex交免费视频| 99国产精品久久|