分享
 
 
 

在DirectX9.0中使用Mesh(2)

王朝other·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

11. Mesh Part Two

本文译自《Introduction to 3D Game Programming with DirectX 9.0》第十一章“Mesh Part Two”,敬请斧正。

本章介绍D3DX库提供的与Mesh有关的接口、结构、函数。通过本章的学习,将能够加载复杂的3D模型,能够控制Mesh对象的精细程度。本章要达到的目标:

l 学习加载.x文件

l 理解使用渐进Mesh(Progressive Mesh)的好处和学习如何使用渐进Mesh接口ID3DXPMesh。将原文中的Progressive Mesh翻译为渐进网格,不知是否恰当

l 学习边界范围(Bounding Volume),以及如何使用D3DX函数创建边界范围

11.1. 关于ID3DXBuffer

这个接口贯穿整个D3DX库,需要对该接口有大体上的认识。ID3DXBuffer是D3DX用来管理连续内存块的结构,他只有两个方法:

l LPVOID GetBufferPointer(); --返回数据块的首地址

l DWORD GetBufferSize(); --返回缓冲区的大小,以字节为单位

例如,D3DXLoadMeshFromX函数就使用ID3DXBuffer返回Mesh对象的邻接信息。因邻接信息是DWORD数组,所以需要进行类型转换。如:

DWORD* info =(DWORD*)adjacencyInfo->GetBufferPointer();

D3DXMATERIAL* mtrls = (D3DXMATERIAL*)mtrlBuffer->GetBufferPointer();

又因为ID3DXBuffer是一个COM对象,所以,用完后,需要进行释放。

adjacencyInfo->Release();

mtrlBuffer->Release();

也可以使用如下函数创建一个空的ID3DXBuffer对象:

HRESULT WINAPI D3DXCreateBuffer(

DWORD NumBytes,

LPD3DXBUFFER *ppBuffer

);

其中参数的含义显而易见。例如,创建一个包含四个整型数的缓冲区:

ID3DXBuffer* buffer = 0;

D3DXCreateBuffer( 4 * sizeof(int), &buffer );

11.2. X文件

使用D3DXCreate*函数,可以创建一些简单的几何体,如球、圆柱、立方体等。如果想通过手动设定顶点的方式创建较复杂的3D对象,你会发现这太麻烦了,简直无法做到!现在,可以使用很多种3D建模工具软件来完成这项枯燥工作,如3DS MAX,LightWave 3D,Maya等。使用这样的建模工具,可以在可视化的、交互的环境中设计复杂、逼真的模型,而且还有丰富的工具可用,使整个建模过程相当简单。这里的简单是相对于在“程序中手动设定顶点的方式建模”,实际上,这些建模工具还是相当复杂的,想得心应手的使用,可不是一朝一夕之功。

这些建模工具可以将所建立的模型的数据(几何信息,材质,动画等)保存到文件。我们需要从文件中分析提取需要的数据,然后应用到自己的3D程序中。有一种常用的文件格式,XFile,其扩展名为.x,较为简单,是Direct3D定义的文件格式,D3DX库提供了完整的支持,可满足一般的需要。

11.2.1. 加载一个.x文件

使用下面的函数加载存储在.x文件中的Mesh数据。它创建一个ID3DXMesh对象,然后从.x文件中读取Mesh的几何信息。

HRESULT WINAPI D3DXLoadMeshFromX(

LPCTSTR pFilename,

DWORD Options,

LPDIRECT3DDEVICE9 pD3DDevice,

LPD3DXBUFFER *ppAdjacency,

LPD3DXBUFFER *ppMaterials,

LPD3DXBUFFER *ppEffectInstances,

DWORD *pNumMaterials,

LPD3DXMESH *ppMesh

);

l pFileName –.x文件的文件名

l Options –创建Mesh的标志。详情可参考SDK文档中的D3DXMESH枚举类型。常用的几个标志如下:

n D3DXMESH_32BIT –使用32位的顶点索引,默认为16位

n D3DXMESH_MANAGED –使用受控的内存缓冲池

n D3DXMESH_WRITEONLY –缓冲区只可执行写操作

n D3DXMESH_DYNAMIC –使用动态内存缓冲池

l pD3DDevice –D3D设备指针

l ppAdjacency –使用ID3DXBuffer返回Mesh的邻接信息,这是一个DWORD数组

l ppMaterials –使用ID3DXBuffer返回Mesh的材质数据,这是一个D3DXMATERIAL类型数组

l ppEffectInstances –使用ID3DXBuffer返回一个D3DXEFFECTINSTANCE结构数组

l pNumMaterials –返回Mesh对象的材质数量,也就是通过ppMaterials返回的D3DXMATERIAL数组的元素数

l ppMesh –返回ID3DXMesh对象

11.2.2. XFile材质

函数D3DXLoadMeshFromX的第七个参数返回Mesh对象的材质数量,第五个参数是D3DXMATERIAL的数组,包含Mesh的材质数据。D3DXMATERIAL结构的定义如下:

typedef struct D3DXMATERIAL {

D3DMATERIAL9 MatD3D;

LPSTR pTextureFilename;

} D3DXMATERIAL;

这个结构很简单,包含一个D3DMATERIAL9结构和一个以0字符结束的字符串的指针,表示相关联的纹理文件。. x文件并不包含纹理数据,只包含纹理文件的文件名。使用该函数加载.x文件后,还需要根据纹理文件的文件名手动加载纹理。

函数D3DXLoadMeshFromX返回的D3DXMATERIAL数组正好与Mesh对象的子集相对应。也就是说,第I个子集的材质纹理信息就存储在ppMaterials[I]中。

11.2.3. X文件的应用实例

这个例子相当的简单,它加载bigship1.x文件,这是DirectX SDK中的一个文件。这里只列出代码的主要框架。

ID3DXMesh* Mesh = 0;

vector<D3DMATERIAL9> Mtrls(0);

vector<IDirect3DTexture9*> Textures(0);

bool Setup()

{

HRESULT hr = 0;

//

// Load the XFile data.

//

ID3DXBuffer* adjBuffer = 0;

ID3DXBuffer* mtrlBuffer = 0;

DWORD numMtrls = 0;

hr = D3DXLoadMeshFromX(

"bigship1.x",

D3DXMESH_MANAGED,

Device,

&adjBuffer,

&mtrlBuffer,

0,

&numMtrls,

&Mesh);

if(FAILED(hr))

{

::MessageBox(0, "D3DXLoadMeshFromX() - FAILED", 0, 0);

return false;

}

//

// Extract the materials, load textures.

//

if( mtrlBuffer != 0 && numMtrls != 0 )

{

D3DXMATERIAL* mtrls=(D3DXMATERIAL*)mtrlBuffer->GetBufferPointer();

for(int i = 0; i < numMtrls; i++)

{

// the MatD3D property doesn't have an ambient value

// set when it’s loaded, so set it now:

mtrls[i].MatD3D.Ambient = mtrls[i].MatD3D.Diffuse;

// save the ith material

Mtrls.push_back( mtrls[i].MatD3D );

// check if the ith material has an associative

// texture

if( mtrls[i].pTextureFilename != 0 )

{

// yes, load the texture for the ith subset

IDirect3DTexture9* tex = 0;

D3DXCreateTextureFromFile(

Device,

mtrls[i].pTextureFilename,

&tex);

// save the loaded texture

Textures.push_back( tex );

}

else

{

// no texture for the ith subset

Textures.push_back( 0 );

}

}

}

Release<ID3DXBuffer*>(mtrlBuffer); // done w/ buffer

.

. // Snipped irrelevant code to this chapter (e.g., setting up lights,

. // view and projection matrices, etc.)

.

return true;

}

最后,渲染Mesh对象:

Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,0xffffffff, 1.0f, 0);

Device->BeginScene();

for(int i = 0; i < Mtrls.size(); i++)

{

Device->SetMaterial( &Mtrls[i] );

Device->SetTexture(0, Textures[i]);

Mesh->DrawSubset(i);

}

Device->EndScene();

Device->Present(0, 0, 0, 0);

11.2.4. 创建顶点的法向量

有时.x文件不包含顶点的法向量,这时,如果使用光照,则需要手动计算顶点的法向量。对于接口ID3DXMesh和其父接口ID3DXBaseMesh,可以使用如下函数计算顶点的法向量:

HRESULT WINAPI D3DXComputeNormals(

LPD3DXBASEMESH pMesh,

const DWORD *pAdjacency

);

该函数将使用法向量的平均值作为顶点的法向量。如果提供了Mesh对象的邻接信息,则重复的顶点会被忽略;如果没有邻接信息,重复的顶点也会被重复计算。另外一点更加重要,需要计算法向量的Mesh对象的顶点格式必须包含D3DFVF_NORMAL标志。

如果.x文件中没有法向量数据,通过D3DXLoadMeshFromX函数创建的ID3DXMesh对象的顶点格式就不包含D3DFVF_NORMAL标志。因此,在计算法向量之前,必须使用D3DFVF_NORMAL标志复制Mesh对象。

// does the mesh have a D3DFVF_NORMAL in its vertex format?

if ( !(pMesh->GetFVF() & D3DFVF_NORMAL) )

{

// no, so clone a new mesh and add D3DFVF_NORMAL to its format:

ID3DXMesh* pTempMesh = 0;

pMesh->CloneMeshFVF(

D3DXMESH_MANAGED,

pMesh->GetFVF() | D3DFVF_NORMAL, // add it here

Device,

&pTempMesh );

// compute the normals:

D3DXComputeNormals( pTempMesh, 0 );

pMesh->Release(); // get rid of the old mesh

pMesh = pTempMesh; // save the new mesh with normals

}

11.3. 渐进模型(Progressive Mesh)

渐进Mesh是ID3DXPMesh接口的对象,可以简化边缩减转换(Edge Collapse Transformations (ECT))。每次ECT都回减少一个顶点和一两个面。由于ECT过程是可逆的(他的逆过程叫顶点分裂),所以,可以通过逆过程将Mesh恢复到原始状态。当然,我们也无法得到比原始状态更精细的Mesh对象,最多只能将其恢复到原始状态。

Progressive Mesh和纹理中的mipmap十分相似。在较小的和远距离的对象上使用高分辨率的纹理纯粹是浪费,因为纹理的细节根本就表现不出来。对于Mesh对象也是一样,较小的距离较远的Mesh不需要太多的三角形,多了纯粹是浪费。所以,在渲染时,实在没有必要在这些根本表现不出来的地方浪费时间。

一种方法是,根据Mesh对象距离视点的距离调整其精细水准(LOD,Level Of Detail)。当距离增加时,可降低LOD;反之,则增加LOD。

这里只讨论ID3DXPMesh接口的用法,不讨论其实现细节。如果你感兴趣,可参考其它资料。

11.3.1. 生成一个渐进Mesh

使用下面的函数创建ID3DXPMesh对象:

HRESULT WINAPI D3DXGeneratePMesh(

LPD3DXMESH pMesh,

const DWORD *pAdjacency,

const D3DXATTRIBUTEWEIGHTS *pVertexAttributeWeights,

const FLOAT *pVertexWeights,

DWORD MinValue,

DWORD Options,

LPD3DXPMESH *ppPMesh

);

l pMesh –输入的普通的Mesh对象

l pAdjacency –Mesh对象的邻接信息,这是一个DWORD数组

l pVertexAttributeWeights –结构D3DXATTRIBUTEWEIGHTS的数组,元素个数为pMesh->GetNumVertices(),表示顶点的属性的权。在简化Mesh对象时,权值决定一个顶点被删除的可能性大小。该参数可以设为NULL,这时顶点使用默认的权值。

l pVertexWeights –顶点的权,是float数组,元素个数是pMesh->GetNumVertices(),用于决定顶点在简化时被删除的可能性的大小。该参数也可设为NULL,这时,顶点默认的权值为1.0f。

l MinValue –在简化Mesh时,顶点或者三角形数的最小个数。该参数是必要的,而且与顶点权值和顶点属性权值有关系,最终也许达不到该数值。

l Options –只能取D3DXMESHSIMP枚举类型中的一个值:

n D3DXMESHSIMP_VERTEX –上一个参数MinValue指顶点数

n D3DXMESHSIMP_FACE –上一个参数MinValue指三角形数

l ppPMesh –返回生成的渐进Mesh

11.3.2. 顶点的属性权

typedef struct _D3DXATTRIBUTEWEIGHTS {

FLOAT Position;

FLOAT Boundary;

FLOAT Normal;

FLOAT Diffuse;

FLOAT Specular;

FLOAT Texcoord[8];

FLOAT Tangent;

FLOAT Binormal;

} D3DXATTRIBUTEWEIGHTS, *LPD3DXATTRIBUTEWEIGHTS;

通过这个结构,可以为顶点的每个属性指定一个权值,0.0表示属性没有权。权值越高,在简化时,越不易被删除。默认的权值如下:

D3DXATTRIBUTEWEIGHTS AttributeWeights;

AttributeWeights.Position = 1.0;

AttributeWeights.Boundary = 1.0;

AttributeWeights.Normal = 1.0;

AttributeWeights.Diffuse = 0.0;

AttributeWeights.Specular = 0.0;

AttributeWeights.Tex[8] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};

一般情况下,推荐使用默认的权值,除非你认为非常有必要使用不同的权值。

11.3.3. ID3DXPMesh的方法

接口ID3DXPMesh继承自ID3DXBaseMesh,下面介绍一些常用的方法。

l DWORD GetMaxFaces(VOID); --返回Mesh的最大三角形数

l DWORD GetMaxVertices(VOID); --返回Mesh的最大顶点数

l DWORD GetMinFaces(VOID); --返回Mesh的最少三角形数

l DWORD GetMinVertices(VOID); --返回Mesh的最少顶点数

l HRESULT SetNumFaces(DWORD Faces); --设置Mesh的三角形数。例如,假定Mesh现在有50个三角形,而想将其简化为30个三角形,则调用pmesh->SetNumFaces(30)。调整后的三角形数可能并不是我们设定的个数,因为PMesh的三角形数还有最大和最少的限制。

l HRESULT SetNumVertices(DWORD Vertices); --设置PMesh的顶点个数。例如,假设现在PMesh有20个顶点,而为了增加其精细程度将顶点数增为40个,则只需调用pmesh->SetNumVertices(40)。与三角形数一样,最终的结果可能不是我们指定的数值,同样有最大最少个数的限制。

l HRESULT TrimByFaces(

DWORD NewFacesMin,

DWORD NewFacesMax,

DWORD *rgiFaceRemap,

DWORD *rgiVertRemap

); --该方法设定PMesh三角形数的最大最小值。新的最大最小值必须在当前的最大最小值之间,即必须在[GetMinFaces(),GetMaxFaces()]内。同时,该方法还将返回三角形和顶点的重影射信息。

l HRESULT TrimByVertices(

DWORD NewVerticesMin,

DWORD NewVerticessMax,

DWORD *rgiFaceRemap,

DWORD *rgiVertRemap

); --该方法与上面的方法相似。

11.3.4. 应用举例:Progressive Mesh

这个例子与前面的XFile例子相似,只是其中使用ID3DXPMesh接口。

与前例相似,我们使用如下的全局变量:

ID3DXMesh* SourceMesh = 0;

ID3DXPMesh* PMesh = 0; // progressive mesh

vector<D3DMATERIAL9> Mtrls(0);

vector<IDirect3DTexture9*> Textures(0);

在创建Progressive Mesh之前,需要使用ID3DXMesh接口加载.x文件:

HRESULT hr = 0;

// ...Load XFile data into SourceMesh snipped.

//

// ...Extracting materials and textures snipped.

//

// Generate the progressive mesh.

//

hr = D3DXGeneratePMesh(

SourceMesh,

(DWORD*)adjBuffer->GetBufferPointer(), // adjacency

0, // default vertex attribute weights

0, // default vertex weights

1, // simplify as low as possible

D3DXMESHSIMP_FACE, // simplify by face count

&PMesh);

Release<ID3DXMesh*>(SourceMesh); // done w/ source mesh

Release<ID3DXBuffer*>(adjBuffer); // done w/ buffer

if(FAILED(hr))

{

::MessageBox(0, "D3DXGeneratePMesh() - FAILED", 0, 0);

return false;

}

通常,因为顶点和顶点属性权值的缘故,很难将Mesh简化到只有一个三角形的程度,但是,如果指定将Mesh简化到一个三角形的程度,则可以将Mesh简化到解析度最低的程度。

现在,渐进Mesh已经生成了,但是,如果直接渲染,则Mesh的解析度此时最低。如果想渲染全解析度的PMesh,首先需要设置其三角形数:

// set to original (full) detail

DWORD maxFaces = PMesh->GetMaxFaces();

PMesh->SetNumFaces(maxFaces);

在渲染PMesh时,我们使用键盘输入控制其解析度:A键将增加解析度,S键减小解析度。

// Get the current number of faces the pmesh has.

int numFaces = PMesh->GetNumFaces();

// Add a face, note the SetNumFaces() will automatically

// clamp the specified value if it goes out of bounds.

if( ::GetAsyncKeyState('A') & 0x8000f )

{

// Sometimes we must add more than one face to invert

// an edge collapse transformation because of the internal

// implementation details of the ID3DXPMesh interface. In

// other words, adding one face may possibly result in a

// mesh with the same number of faces as before. Thus to

// increase the face count we may sometimes have to add

// two faces at once.

PMesh->SetNumFaces(numFaces + 1);

if(PMesh->GetNumFaces() == numFaces)

PMesh->SetNumFaces(numFaces + 2);

}

// Remove a face, note the SetNumFaces() will automatically

// clamp the specified value if it goes out of bounds.

if(::GetAsyncKeyState('S') & 0x8000f)

PMesh->SetNumFaces(numFaces - 1);

上面的方法直截了当,只是增加三角形数时,有时需要增加两个来满足ECT的需要。

最后,使用和渲染ID3DXMesh同样的方法渲染ID3DXPMesh。另外,为了更加直观的观察PMesh的三角形数的变化情况,使用黄色材质在线框模式(Wireframe Mode)下渲染Mesh的三角形。

Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,0xffffffff, 1.0f, 0);

Device->BeginScene();

for(int i = 0; i < Mtrls.size(); i++)

{

Device->SetMaterial( &Mtrls[i] );

Device->SetTexture(0, Textures[i]);

PMesh->DrawSubset(i);

// draw wireframe outline

Device->SetMaterial(&d3d::YELLOW_MTRL);

Device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);

PMesh->DrawSubset(i);

Device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);

}

Device->EndScene();

Device->Present(0, 0, 0, 0);

11.4. 对象的边界范围

有时,需要计算Mesh对象的边界范围,常用的有两种类型:立方体和球。也有使用其它方法的,如圆柱体、椭球体、菱形体、太空舱形等。这里,我们只讨论立方体和球体两种边界形式。

边界盒或边界球常用来加速多物体间的可视范围测试、碰撞检测等。如果一个Mesh的边界盒/球不可见,就可认为Mesh也不可见。检测边界盒/球是否可见比检测Mesh中所有的三角形是否可见要方便得多。在碰撞检测中,如果一枚导弹点火起飞,我们需要检测他是否撞到了同一个场景中的目标。由于这些对象全是大量的三角形构成,我们可以依次检测每个对象的每个三角形,检测导弹(可以使用数学模型中的射线)是否撞到了这些三角形。这个方法需要进行多次的射线/三角形交点的运算。较好的方法是使用边界盒或边界球,计算射线与场景中的每个对象的边界盒/边界球的交点。如果射线与对象的边界范围相交,可以认为该对象被击中了。这是一个公平的近似方法,如果需要更高的精度,可以用边界范围法先去除那些明显不会相撞的对象,然后用更精确地方法检测很可能相撞的对象。如果边界范围检测发现相撞,则该对象就很有可能相撞。

D3DX库提供了计算Mesh对象边界盒/球的函数。这些函数使用顶点数组作为输入计算边界盒/球,可以使用各种顶点格式:

HRESULT WINAPI D3DXComputeBoundingSphere(

const D3DXVECTOR3 *pFirstPosition,

DWORD NumVertices,

DWORD dwStride,

D3DXVECTOR3 *pCenter,

FLOAT *pRadius

);

l pFirstPosition –顶点数组的地址,顶点的第一个向量需要是顶点的位置坐标

l NumVertices –顶点的数目

l dwStride –顶点大小,以字节为单位。因顶点中有很多附加数据,如法向量、纹理坐标等,计算边界范围不需要这些数据,所以,需要知道跳过多少数据才能找到下一个顶点的坐标。

l pCenter –返回边界范围的中心

l pRadius –返回边界球的半径

HRESULT WINAPI D3DXComputeBoundingBox(

const D3DXVECTOR3 *pFirstPosition,

DWORD NumVertices,

DWORD dwStride,

D3DXVECTOR3 *pMin,

D3DXVECTOR3 *pMax

);

前三个参数与计算边界球的函数相同;后两个参数返回边界盒的最小和最大点。

11.4.1. 边界检测类型

为了使边界检测易于使用,我们实现几个辅助的数据结构:

struct BoundingBox

{

BoundingBox();

bool isPointInside(D3DXVECTOR3& p);

D3DXVECTOR3 _min;

D3DXVECTOR3 _max;

};

struct BoundingSphere

{

BoundingSphere();

D3DXVECTOR3 _center;

float _radius;

};

BoundingBox::BoundingBox()

{

// infinite small bounding box

_min.x = FLT_MAX;

_min.y = FLT_MAX;

_min.z = FLT_MAX;

_max.x = -FLT_MAX;

_max.y = -FLT_MAX;

_max.z = -FLT_MAX;

}

bool BoundingBox::isPointInside(D3DXVECTOR3& p)

{

// is the point inside the bounding box?

if (p.x >= _min.x && p.y >= _min.y && p.z >= _min.z &&

p.x <= _max.x && p.y <= _max.y && p.z <= _max.z)

{

return true;

}

else

{

return false;

}

}

BoundingSphere::BoundingSphere()

{

_radius = 0.0f;

}

11.4.2. 边界范围应用举例

该例子演示D3DXComputeBoundingSphere和D3DXComputeBoundingBox函数的用法。程序首先加载一个.x文件,然后计算Mesh的边界盒/球。代码中创建两个ID3DXMesh对象,分别使用边界盒和边界球。最后,分别渲染他们。

这个例子很简单,这里只给出有关边界范围的代码:

bool ComputeBoundingSphere(

ID3DXMesh* mesh, // mesh to compute bounding sphere for

BoundingSphere* sphere) // return bounding sphere

{

HRESULT hr = 0;

BYTE* v = 0;

mesh->LockVertexBuffer(0, (void**)&v);

hr = D3DXComputeBoundingSphere(

(D3DXVECTOR3*)v,

mesh->GetNumVertices(),

D3DXGetFVFVertexSize(mesh->GetFVF()),

&sphere->_center,

&sphere->_radius);

mesh->UnlockVertexBuffer();

if( FAILED(hr) )

return false;

return true;

}

bool ComputeBoundingBox(

ID3DXMesh* mesh, // mesh to compute bounding box for

BoundingBox* box) // return bounding box

{

HRESULT hr = 0;

BYTE* v = 0;

mesh->LockVertexBuffer(0, (void**)&v);

hr = D3DXComputeBoundingBox(

(D3DXVECTOR3*)v,

mesh->GetNumVertices(),

D3DXGetFVFVertexSize(mesh->GetFVF()),

&box->_min,

&box->_max);

mesh->UnlockVertexBuffer();

if( FAILED(hr) )

return false;

return true;

}

类型转换(D3DXVECTOR3*)v假定顶点坐标在顶点结构的开头位置,一般都是如此。

11.5. 总结

l 现在,我们可以用3D建模软件导出的.x文件构建复杂的Mesh对象。使用D3DXLoadMeshFromX函数取得ID3DXMesh对象,就可以在自己的应用程序中自由使用了。

l 使用ID3DXPMesh接口表示的渐进Mesh,可以控制其精细程度。可以根据对象在场景中的突出程度调整PMesh的精细程度。

l 我们可以使用D3DXComputeBoundingSphere和D3DXComputeBoundingBox函数计算Mesh对象的边界。边界范围很有用,其接近对象真实的边界,可加速碰撞检测等的计算。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有