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

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| 日韩视频不卡| 亚洲午夜精品网| 久久精品国产亚洲精品| 久久精品国产一区二区三区 | 亚洲国产成人精品久久久国产成人一区| 午夜精品久久久久久久99水蜜桃 | 久久精品视频99| 欧美xx69| 日韩小视频在线观看专区| 亚洲天堂av电影| 久久精品人人爽| 欧美看片网站| 国产视频在线观看一区二区三区| 亚洲小说春色综合另类电影| 久久久久久久综合狠狠综合| 久久不射2019中文字幕| 久久久www成人免费无遮挡大片 | 午夜精品久久久久久久久久久| 久久久www免费人成黑人精品| 亚洲成人在线视频播放 | 媚黑女一区二区| 亚洲精品一线二线三线无人区| 午夜精品视频在线观看一区二区| 久久网站免费| 国产精品日韩电影| 亚洲国内自拍| 久久国产精品久久久久久电车| 亚洲国产你懂的| 久久成人国产精品| 国产精品99免视看9| 亚洲国产经典视频| 欧美一区综合| 亚洲一区二区网站| 欧美日本三级| 亚洲国产日韩欧美| 久久精品综合网| 中文一区在线| 欧美日本在线| 99国产精品久久| 你懂的视频欧美| 欧美一区影院| 国产精品一级二级三级| 亚洲精品资源| 欧美成人资源| 久久综合综合久久综合| 国产一区香蕉久久| 欧美在线视频网站| 亚洲小视频在线观看| 欧美精品一级| 一区二区久久| 99热在线精品观看| 欧美精品一区二区三区蜜臀| 亚洲欧洲精品天堂一级| 麻豆freexxxx性91精品| 久久久久久久久岛国免费| 国产一区二区三区四区老人| 欧美在线观看视频一区二区三区 | 中文亚洲字幕| 国产精品入口麻豆原神| 亚洲宅男天堂在线观看无病毒| 99精品视频一区二区三区| 欧美人成网站| 亚洲视频在线视频| 在线亚洲免费| 国产日产欧产精品推荐色| 亚洲国产天堂久久综合网| 小嫩嫩精品导航| 国产一区二区黄| 免费不卡亚洲欧美| 奶水喷射视频一区| 在线一区视频| 亚洲欧美综合v| 国产亚洲福利社区一区| 久久久中精品2020中文| 麻豆视频一区二区| 一本色道久久88综合亚洲精品ⅰ | 欧美激情一区二区三区在线视频 | 91久久久久久| 亚洲美女色禁图| 国产精品v欧美精品v日韩精品 | 鲁大师成人一区二区三区| 久久欧美中文字幕| 日韩天堂av| 午夜国产不卡在线观看视频| 国外成人性视频| 亚洲黄网站黄| 国产精品社区| 欧美搞黄网站| 欧美色图麻豆| 久久视频这里只有精品| 欧美电影在线播放| 欧美一区二区三区免费在线看| 久久色在线观看| 一区二区三区精密机械公司| 欧美一区国产二区| 夜夜爽www精品| 欧美一区国产在线| 亚洲免费高清| 久久精品九九| 中文亚洲欧美| 久久久久看片| 亚洲欧美区自拍先锋| 欧美中文在线免费| 一区二区三区精品在线| 久久精品一区二区国产| 中文精品一区二区三区| 久久偷看各类wc女厕嘘嘘偷窃| 亚洲一区二区免费视频| 久久深夜福利免费观看| 欧美伊人影院| 国产精品久久久久久av下载红粉| 欧美国产日韩a欧美在线观看| 欧美亚洲成人免费| 亚洲黄色一区| 在线观看亚洲视频| 亚洲欧美日本视频在线观看| 宅男噜噜噜66一区二区| 免费欧美日韩| 欧美gay视频| 黑人巨大精品欧美黑白配亚洲 | 亚洲高清色综合| 亚洲一本大道在线| 蜜桃久久精品乱码一区二区| 久久精品国产999大香线蕉| 欧美午夜不卡视频| 日韩亚洲精品在线| 亚洲精品一区在线观看香蕉| 久久精品视频导航| 久久精品综合一区| 国产一区在线视频| 欧美在线免费播放| 久久国产视频网站| 国产午夜亚洲精品理论片色戒| 亚洲一区二区三区四区中文 | 亚洲性视频h| 欧美日韩亚洲91| 亚洲伦理一区| 亚洲自拍偷拍视频| 欧美视频一区| 亚洲在线观看| 久久久综合免费视频| 国内精品久久久久久影视8| 久久精品国产视频| 欧美国产欧美亚州国产日韩mv天天看完整| 在线观看亚洲精品视频| 美女国产一区| 亚洲精品小视频| 亚洲一区二区三区777| 国产精品久久久久秋霞鲁丝| 亚洲一区一卡| 毛片精品免费在线观看| 91久久精品一区二区三区| 欧美国产高清| 亚洲一区二区三区影院| 久久激情视频久久| 亚洲二区免费| 欧美性做爰猛烈叫床潮| 欧美一区二区三区男人的天堂| 免费亚洲一区二区| 一区二区三区高清视频在线观看| 国产精品高潮呻吟久久av无限 | 欧美日韩亚洲一区三区 | 欧美一区二视频| 在线观看亚洲精品| 欧美新色视频| 久久精品在线视频| 亚洲精品国产品国语在线app| 亚洲欧美日韩一区二区三区在线| 国产亚洲一区二区三区在线播放 | 国产精品久久久久久久久久久久久 | 欧美日韩p片| 亚洲欧美成人一区二区三区| 六月天综合网| 99精品国产在热久久| 国产欧美日韩三区| 另类图片综合电影| 久久日韩精品| 9l视频自拍蝌蚪9l视频成人| 国产精品老牛| 欧美成人午夜影院| 亚洲欧美色婷婷| 亚洲精品一区二区三区蜜桃久| 久久精品国产免费看久久精品| 亚洲精选一区| 国产一二三精品| 欧美日韩在线视频一区| 可以免费看不卡的av网站| 在线中文字幕一区| 亚洲激情偷拍| 美女任你摸久久| 久久国产精品黑丝| 亚洲欧美国产高清va在线播| 亚洲精品国产精品国自产观看| 好吊色欧美一区二区三区四区| 国产精品婷婷|