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

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) 評論(0)  編輯 收藏 引用 所屬分類: 2.OpenCASCADE

Surface Normal Averaging

eryar@163.com

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

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

一、引言 Introduction

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

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

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即可。其中每個三角面的法向計(jì)算也是直接根據(jù)兩個向量的叉乘得來。

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的三角剖分算法生成。如果將每個三角面的法向作為每個頂點(diǎn)的法向,則渲染效果如下圖所示:

wps_clip_image-31623

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

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

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

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

wps_clip_image-28615

Figure 3.1 Jagged surface with the usual surface normals

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

wps_clip_image-19581

Figure 3.2 Averaging the normals will make sharp corners appear softer

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

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

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的模式,通過遍歷場景中的幾何體,生成頂點(diǎn)的法向量。對于上面同一個球的網(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來生成面的法向都是無奈之舉,因?yàn)槎际窃陔x散的三角網(wǎng)格上找出法向,不精確,在光照下渲染效果都不是很理想。但是OpenCascade作為幾何造型內(nèi)核,提供了計(jì)算曲面法向的功能,因此有能力計(jì)算出頂點(diǎn)處的法向的精確值。

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

對頂點(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ì)算的面的法向在渲染時效果很好。

五、程序示例 Putting It All Together

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

 

/*
*    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,在有光照的情況下,渲染效果最差。使用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>
            蜜桃精品一区二区三区| 欧美屁股在线| 亚洲欧美国产高清va在线播| 一区二区在线不卡| 欧美高清视频在线观看| 在线性视频日韩欧美| 久久久久九九九九| 9l国产精品久久久久麻豆| 一区二区91| 午夜国产精品视频| 亚洲人成77777在线观看网| 中文av一区二区| 亚洲激情电影在线| 亚洲一级黄色片| 一区二区三区日韩欧美精品| 国产视频不卡| 国产精品色午夜在线观看| 亚洲成人自拍视频| 欧美激情久久久久| 亚洲免费在线观看视频| 亚洲第一网站| 国产真实乱偷精品视频免| 欧美色123| 牛牛影视久久网| 国产精品va在线播放| 欧美日韩精品一区二区天天拍小说| 久久国产精品电影| 亚洲美女视频在线观看| 亚洲伦理在线免费看| 女仆av观看一区| 国产精品看片资源| 欧美日韩色一区| 欧美激情精品久久久久久免费印度| 久久国产福利国产秒拍| 欧美激情一区二区三区在线视频观看 | 亚洲欧美日韩精品久久久| 久久九九精品| 欧美无乱码久久久免费午夜一区| 欧美精品电影| 欧美精品一区在线播放| 欧美国产精品| 欧美日韩和欧美的一区二区| 一色屋精品亚洲香蕉网站| 狠狠综合久久| 亚洲精品中文字幕女同| 一区二区三区精品| 在线成人小视频| 亚洲国产精品一区在线观看不卡 | 午夜精品久久久久久久久久久| 欧美freesex8一10精品| 亚洲男人第一av网站| 欧美日韩八区| 99re66热这里只有精品3直播| 久久精品在线| 欧美一区二区成人6969| 国产伦精品一区二区三区视频黑人| 亚洲最快最全在线视频| 亚洲激情在线激情| 久久在线播放| 亚洲电影毛片| 欧美激情亚洲国产| 久久在线视频在线| 亚洲国产人成综合网站| 欧美成人午夜激情在线| 免费亚洲一区| 一本综合精品| 99ri日韩精品视频| 国产精品午夜在线观看| 欧美亚洲一区三区| 欧美在线一级va免费观看| 国内外成人免费激情在线视频| 久久精品在线免费观看| 久久乐国产精品| 91久久精品一区| 国产日韩精品在线观看| a91a精品视频在线观看| 最近中文字幕日韩精品| 欧美精品三级| 午夜天堂精品久久久久| 午夜精品成人在线视频| 在线观看日韩| 亚洲精品自在久久| 国产亚洲精品久久久久久| 久久亚洲私人国产精品va媚药| 久久青草福利网站| 一本高清dvd不卡在线观看| 亚洲午夜激情| 亚洲国产cao| 亚洲精品久久久久久下一站 | 欧美激情性爽国产精品17p| 亚洲一区久久| 午夜国产精品视频| 亚洲人成人一区二区三区| 一本一本久久| 激情懂色av一区av二区av| 欧美国产日韩视频| 国产精品女同互慰在线看| 久久九九国产精品| 欧美精品一区二区三区视频| 性视频1819p久久| 免费亚洲电影| 久久精品在线| 欧美美女福利视频| 久久综合九色欧美综合狠狠| 欧美三区视频| 欧美福利视频在线| 国产精品久久久久久久久动漫| 久久激情视频免费观看| 欧美日韩视频在线第一区| 久久亚洲综合色一区二区三区| 欧美日韩一区二区三区高清| 久久久天天操| 国产伦精品一区二区三区| 亚洲精品在线免费| 91久久国产自产拍夜夜嗨| 久久精品一区中文字幕| 一区二区欧美在线观看| 老司机精品导航| 久久夜色精品国产亚洲aⅴ| 国产精品羞羞答答| av成人免费在线观看| 裸体一区二区三区| 欧美一区亚洲二区| 欧美午夜精品久久久久久浪潮| 欧美福利电影在线观看| 一区二区三区我不卡| 亚洲欧美国产高清va在线播| 亚洲美女中出| 欧美激情久久久| 欧美aaaaaaaa牛牛影院| 国产一区在线免费观看| 亚洲欧美日韩在线不卡| 欧美在线二区| 国产裸体写真av一区二区| 中文在线资源观看网站视频免费不卡| 欧美精品乱码久久久久久按摩 | 亚洲美女视频在线观看| 91久久精品美女| 欧美aa在线视频| 亚洲大胆在线| 欧美在线免费看| 国语自产精品视频在线看一大j8 | 欧美黄在线观看| 亚洲国产天堂网精品网站| 亚洲成人在线免费| 久久久久久久网| 亚洲高清av在线| 一本一本久久a久久精品综合麻豆| 欧美日韩国产欧| 亚洲永久精品大片| 久久人人97超碰精品888| 经典三级久久| 欧美二区不卡| 亚洲精品日本| 欧美日韩在线影院| 久久手机精品视频| 亚洲国产天堂久久综合| 欧美日韩卡一卡二| 亚洲欧美日韩国产中文| 蜜臀va亚洲va欧美va天堂| 1769国产精品| 欧美精品一区二区精品网| 亚洲精品视频在线播放| 午夜在线精品偷拍| 在线欧美亚洲| 欧美日韩国产电影| 在线性视频日韩欧美| 香蕉久久夜色| 亚洲人在线视频| 欧美视频一区在线观看| 亚洲免费在线电影| 免费观看成人鲁鲁鲁鲁鲁视频| 亚洲另类黄色| 国产欧美一二三区| 欧美成人69| 欧美亚洲在线观看| 亚洲人成亚洲人成在线观看图片 | 亚洲一区精品视频| 免费成人性网站| 亚洲欧美在线另类| 在线成人亚洲| 国产日韩在线一区二区三区| 男人的天堂亚洲| 欧美一区二区三区在线观看视频| 亚洲承认在线| 久久久久99| 亚洲影院色在线观看免费| 在线欧美影院| 国产日韩1区| 欧美色综合天天久久综合精品| 久久久久久网| 欧美伊人久久久久久久久影院| 亚洲国产裸拍裸体视频在线观看乱了中文 | 美女图片一区二区| 亚洲一区二区三区色| 亚洲国产欧美精品| 亚洲精品久久久久久下一站| 国产午夜精品美女视频明星a级| 欧美精品色综合| 久久综合国产精品台湾中文娱乐网|