热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

3D游戏从入门到精通1115

************************************作者:蔡军生*出处:http:blog.csdn.netcaimouse****

  /***********************************
 *作者:蔡军生
 *出处:http://blog.csdn.net/caimouse/
 ************************************/
 
 
 3D游戏从入门到精通-11
 
 
2.10.1索引缓冲区
上面已经学习了最简单的三角形显示,了解了整个3D物体的显示流程,下面来学习一个复杂一点的物体显示,使用12个三角形构造成的正方体显示。并且通过个例子学会使用索引缓冲区,提高图形绘制的速度和效率。
1、             使用三角形构造立方体
由前面可知,任何复杂的物体,都是由三角形组成的。现在就用12三角形构造一个正方体。先创建12点个顶点的缓冲区,然后再往里填写合适的数据,然后显示它出来。下面来仔细分析这段代码:
在函数HRESULT CCAICube::Init(IDirect3DDevice9* pd3dDevice)里,先创建12顶点数据。
const int nVTCount = 6*2*3;
 // 创建顶点缓冲区。
 if( FAILED( hr = m_pd3dDevice->CreateVertexBuffer( nVTCount * sizeof(VT_CAICUBE),
       0, VT_CAICUBE::dwFVF,
       D3DPOOL_MANAGED, &m_pVB, NULL ) ) )
 {
       //创建顶点缓冲区失败。
       return DXTRACE_ERR( "CreateVertexBuffer", hr );
 }
           这段代码,跟以前的代码一样创建顶点缓冲区。
接着下来就指明所有三角形的坐标:
// 用三角形填充顶点缓冲区。
 VT_CAICUBE* pVertices;
 
 if( FAILED( hr = m_pVB->Lock( 0, 0, (VOID**)&pVertices, 0 ) ) )
 {
       //锁住顶点缓冲区。
       return DXTRACE_ERR( "Lock", hr );
 }
 
 // 三角形组成的立方体表面。
 //第一个面
 pVertices[0].vPosition = D3DXVECTOR3( -1.0f, -1.0f, -1.0f );
 pVertices[1].vPosition = D3DXVECTOR3( -1.0f, 1.0f, -1.0f );
 pVertices[2].vPosition = D3DXVECTOR3( 1.0f, 1.0f, -1.0f );
 
 //
 pVertices[3].vPosition = D3DXVECTOR3( -1.0f, -1.0f, -1.0f );
 pVertices[4].vPosition = D3DXVECTOR3( 1.0f, 1.0f, -1.0f );
 pVertices[5].vPosition = D3DXVECTOR3( 1.0f, -1.0f, -1.0f );
 
 
 //第二个面
 pVertices[6].vPosition = D3DXVECTOR3( -1.0f, 1.0f, -1.0f );
 pVertices[7].vPosition = D3DXVECTOR3( -1.0f, 1.0f, 1.0f );
 pVertices[8].vPosition = D3DXVECTOR3( 1.0f, 1.0f, -1.0f );
 
 //
 pVertices[9].vPosition = D3DXVECTOR3(   -1.0f, 1.0f, 1.0f );
 pVertices[10].vPosition = D3DXVECTOR3( 1.0f, 1.0f, 1.0f );
 pVertices[11].vPosition = D3DXVECTOR3( 1.0f, 1.0f, -1.0f );
 
 
 //第三个面
 pVertices[12].vPosition = D3DXVECTOR3( -1.0f, 1.0f, 1.0f );
 pVertices[13].vPosition = D3DXVECTOR3( -1.0f, -1.0f, 1.0f );
 pVertices[14].vPosition = D3DXVECTOR3( 1.0f, 1.0f, 1.0f );
 
 //
 pVertices[15].vPosition = D3DXVECTOR3( 1.0f, 1.0f, 1.0f );
 pVertices[16].vPosition = D3DXVECTOR3( -1.0f, -1.0f, 1.0f );
 pVertices[17].vPosition = D3DXVECTOR3( 1.0f, -1.0f, 1.0f );
 
 //第四个面
 pVertices[18].vPosition = D3DXVECTOR3( -1.0f, -1.0f, 1.0f );
 pVertices[19].vPosition = D3DXVECTOR3( 1.0f, -1.0f, -1.0f );
 pVertices[20].vPosition = D3DXVECTOR3( 1.0f, -1.0f, 1.0f );
 
 //
 pVertices[21].vPosition = D3DXVECTOR3( -1.0f, -1.0f, 1.0f );   
 pVertices[22].vPosition = D3DXVECTOR3( -1.0f, -1.0f, -1.0f );
 pVertices[23].vPosition = D3DXVECTOR3( 1.0f, -1.0f, -1.0f );
 
 
 //第五个面
 pVertices[24].vPosition = D3DXVECTOR3( 1.0f, 1.0f, 1.0f );   
 pVertices[25].vPosition = D3DXVECTOR3( 1.0f, -1.0f, -1.0f );
 pVertices[26].vPosition = D3DXVECTOR3( 1.0f, 1.0f, -1.0f );
 
 //
 pVertices[27].vPosition = D3DXVECTOR3( 1.0f, -1.0f, -1.0f );   
 pVertices[28].vPosition = D3DXVECTOR3( 1.0f, 1.0f, 1.0f );
 pVertices[29].vPosition = D3DXVECTOR3( 1.0f, -1.0f, 1.0f );
 
 //第六个面
 pVertices[30].vPosition = D3DXVECTOR3( -1.0f, 1.0f, -1.0f );
 pVertices[31].vPosition = D3DXVECTOR3( -1.0f, -1.0f, -1.0f );    
 pVertices[32].vPosition = D3DXVECTOR3( -1.0f, 1.0f, 1.0f );
 
 //
 pVertices[33].vPosition = D3DXVECTOR3( -1.0f, 1.0f, 1.0f );    
 pVertices[34].vPosition = D3DXVECTOR3( -1.0f, -1.0f, -1.0f );
 pVertices[35].vPosition = D3DXVECTOR3( -1.0f, -1.0f, 1.0f );
 
 //解锁顶点缓冲区。
 m_pVB->Unlock();
上面从第一个面开始,就每个面两个三角形地填写,并且是按左中手坐标系的方向来填写三角形的顶点。
接着修改渲染的代码,改为渲染12个三角形,代码如下:
// 渲染顶点缓冲区的内容。
 m_pd3dDevice->SetStreamSource( 0, m_pVB, 0, sizeof(VT_CAICUBE) );
 m_pd3dDevice->SetFVF( VT_CAICUBE::dwFVF );
 m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, 12 );
这样显示出来的立方体是那个面都可以看得到的,如果不按左手坐标系填写,就会有一些面看不到的。
 
通过上面的代码,是否看到要显示一个简单的立方体,就需要复杂地填写顶点了,并且要小心翼翼地写代码,一不小心写错了,就看不见了。因此,再复杂的物体,一般是通过使用3D建模软件来构造的。通过上面的代码,也发现了一个问题,就是整个正方体,其实只有8个顶点,而上面的三角形列表里有很多顶点是重复的,对于只有12个三角形来说,也许不是很重要。但是对于数以万计的三角形来说,这样的重复顶点就会浪费很多内存,浪费系统的带宽,并且需要重复渲染顶点。有没有更好的方法来解决这个问题呢?答案是肯定的,下面接着就来学习索引缓冲区。
 3D游戏从入门到精通-12
 
1、             使用索引缓冲区
什么是索引缓冲区呢?其实索引缓冲区,就像指针一样的工具。顶点缓冲区里保存的是真实的顶点,而索引缓冲区只记录顶点缓冲区的顶点编号。比如顶点缓冲区里有4个顶点,而这4个顶点就可以构成两个三角形来显示。如果直接使用顶点缓冲区的话,就需要写6个顶点。这样就可以使用索引缓冲区,指明第一个三角形是由顶点编号1、2、3构成一个三角形,而第二个三角形就是1、3、4组成。

现在把上面的立方体改为使用索引缓冲区,先创建8个顶点,如下:
pVertices[0].vPosition = D3DXVECTOR3(    -1.0f, -1.0f, -1.0f );
pVertices[1].vPosition = D3DXVECTOR3(    -1.0f, 1.0f, -1.0f );   
pVertices[2].vPosition = D3DXVECTOR3(    1.0f, 1.0f, -1.0f );    
pVertices[3].vPosition = D3DXVECTOR3(    1.0f, -1.0f, -1.0f );   
 
pVertices[4].vPosition = D3DXVECTOR3(    -1.0f, 1.0f, 1.0f );    
pVertices[5].vPosition = D3DXVECTOR3(    1.0f, 1.0f, 1.0f );
pVertices[6].vPosition = D3DXVECTOR3(    1.0f, -1.0f, 1.0f );    
pVertices[7].vPosition = D3DXVECTOR3(    -1.0f, -1.0f, 1.0f );
这样,就可省下许多顶点占用的内存了,然后创建36个索引点的缓冲区,如下:
 
//创建索引缓冲区。
 hr = m_pd3dDevice->CreateIndexBuffer( 12*3 *sizeof(WORD),
       0, D3DFMT_INDEX16, D3DPOOL_DEFAULT,
       &m_pIB, NULL );
 
 if( FAILED( hr ) )
 {
       return E_FAIL;
 }   
 
上面创建了36个WORD大小的索引点,这样省了很多内存空间。由于顶点是由3个浮点数和其它值组成,肯定比两个字节索引值占用空间大。接着下来就是设置索引缓冲区,如下:
 
void* pIndices;
 
 if( FAILED( m_pIB->Lock( 0, sizeof(WORD)*12*3, &pIndices,0 ) ) )          
 {
       m_pIB->Release();
       m_pIB = NULL;
       return E_FAIL;
 }
 
 //
 WORD* pIndex = reinterpret_cast(pIndices);
 int nPos = 0;
 
 //1
 pIndex[nPos++] = 0;
 pIndex[nPos++] = 1;
 pIndex[nPos++] = 2;
 
 pIndex[nPos++] = 0;
 pIndex[nPos++] = 2;
 pIndex[nPos++] = 3;
 
 
 //2
 pIndex[nPos++] = 1;
 pIndex[nPos++] = 4;
 pIndex[nPos++] = 2;
 
 pIndex[nPos++] = 2;
 pIndex[nPos++] = 4;
 pIndex[nPos++] = 5;
 
 //3
 pIndex[nPos++] = 2;
 pIndex[nPos++] = 5;
 pIndex[nPos++] = 3;
 
 pIndex[nPos++] = 3;
 pIndex[nPos++] = 5;
 pIndex[nPos++] = 6;
 
 //4
 pIndex[nPos++] = 0;
 pIndex[nPos++] = 7;
 pIndex[nPos++] = 1;
 
 pIndex[nPos++] = 1;
 pIndex[nPos++] = 7;
 pIndex[nPos++] = 4;
 
 //5
 pIndex[nPos++] = 0;
 pIndex[nPos++] = 3;
 pIndex[nPos++] = 7;
 
 pIndex[nPos++] = 3;
 pIndex[nPos++] = 6;
 pIndex[nPos++] = 7;
 
 
 //6
 pIndex[nPos++] = 4;
 pIndex[nPos++] = 7;
 pIndex[nPos++] = 5;
 
 pIndex[nPos++] = 5;
 pIndex[nPos++] = 7;
 pIndex[nPos++] = 6;
 //
 m_pIB->Unlock();
 
上面这段代码,先Lock函数取得索引缓冲区地址,然后依次设置索引值,这里使用三角形列表,所以顶点顺序一样是按顺时针方向来设置的,也就是按左手坐标系来设置的。
接着下来,就需要渲染这个立方体了,如下:
m_pd3dDevice->SetStreamSource( 0, m_pVB, 0, sizeof(VT_CAICUBE) );
 m_pd3dDevice->SetFVF( VT_CAICUBE::dwFVF );
 
m_pd3dDevice->SetIndices(m_pIB);
m_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,0,8,0,12);
上面代码先设置了8个顶点缓冲区到管道里,然后再调用SetIndices设置索引缓冲区,最后调用DrawIndexedPrimitive函数来显示所有三角形列表。DrawIndexedPrimitive函数的第一个参数是索引列表里的类型,第二个参数是索引缓冲区在顶点缓冲区里的起始位置,比如顶点缓区是0,1,3的,当设置这个值为50时,那么相当于访问了50,51,53的顶点值。第三个参数是最小索引值。第四个参数是有多少个顶点会使用。第五个参数是从那个索引值开始。第六个参数是基本图形个数。
 
通过这样学习,就学会使用了索引缓冲区,如果有很多顶点,有很多三角形,就需要使用优化的算法,以便有最少的顶点,使用最多的索引,这样有利于减少内存占用,提高带宽利用,提高显示卡显示更多图形,提高游戏的性能。
 
 
 3D游戏从入门到精通-13
2.10.1基本图形显示
在D3D里只有几种基本图形可以显示的,它们分别是:
点列表、线列表、线带列表、三角形列表、三角形带列表、三角形扇形列表。
其它任何的图形,都可以由这向这几种基本图形组合出来。上面已经介绍了三角形显示了,所以这里就不再具体地说明它了。
1、             点列表
点列表主要显示为一个个像素点的集合,每个点都是单独显示,分离的。点列表作用是用来显示点元素,或者显示点线的。如下图所示:
上面这个图就是使用点列表来显示一条正弦曲线。其实它们都是由分理的点组成,每个点可显示为不同的颜色。
现在就看看怎么样用代码显示这条正弦曲线的。
 
HRESULT hr;
 
 // 创建顶点缓冲区。
 if( FAILED( hr = m_pd3dDevice->CreateVertexBuffer(
       m_nPointListCount * sizeof(VT_CAIPRIMITIVE),
       0, VT_CAIPRIMITIVE::dwFVF,
       D3DPOOL_MANAGED, &m_pvbPointList, NULL ) ) )
 {
       //创建顶点缓冲区失败。
       return DXTRACE_ERR( "CreateVertexBuffer", hr );
 }
 
 //
 VT_CAIPRIMITIVE* pVertices;
 if( FAILED( hr = m_pvbPointList->Lock( 0, 0, (VOID**)&pVertices, 0 ) ) )
 {
       //锁住顶点缓冲区。
       return DXTRACE_ERR( "Lock", hr );
 }
 
 for (int i = 0; i  {
       float fX = -10.0f + (float)i * 0.1f;
       float fY = sinf(fX);
       pVertices[i].vPosition = D3DXVECTOR3( fX, fY, 0.0f );    
       pVertices[i].crDiffuse = D3DCOLOR_COLORVALUE( 1.0, 0.0, 0.0, 1.0 );
 }
 
 
 //解锁顶点缓冲区。
 m_pvbPointList->Unlock();
 
上面这段代码,先创建点列表的顶点缓冲区,然后使用正弦函数计算点坐标的值,并把它们设置到顶点缓冲区里。接着就需要调用渲染函数:
m_pd3dDevice->SetStreamSource( 0, m_pvbPointList, 0, sizeof(VT_CAIPRIMITIVE) );
m_pd3dDevice->SetFVF( VT_CAIPRIMITIVE::dwFVF );
m_pd3dDevice->DrawPrimitive( D3DPT_POINTLIST, 0, m_nPointListCount );  
先设置顶点缓冲区,然后调用DrawPrimitive函数来显示,这里第一个参数不一样,使用了D3DPT_POINTLIST类型,这个类型就是显示为点列表方式。
如果使用直线或者三角形不能显示的图形,就可以使用它来显示了。
 
 
 3D游戏从入门到精通-14
 
2、             线列表
D3D还提供直线的显示,由于很多自然现现象需要它来显示。比如大雨,就需要使用直线来模拟出来。如下图所示:
这里显示三条红、绿、蓝的直线。它的代码如下:
pVertices[0].vPosition = D3DXVECTOR3( -2.0f, 0.0f, 0.0f );    
 pVertices[0].crDiffuse = D3DCOLOR_COLORVALUE( 1.0, 0.0, 0.0, 1.0 );
 
 pVertices[1].vPosition = D3DXVECTOR3( 2.0f, 0.0f, 0.0f );    
 pVertices[1].crDiffuse = D3DCOLOR_COLORVALUE( 1.0, 0.0, 0.0, 1.0 );
 
 //
 pVertices[2].vPosition = D3DXVECTOR3( 0.0f, -2.0f, 0.0f );   
 pVertices[2].crDiffuse = D3DCOLOR_COLORVALUE( 0.0, 1.0, 0.0, 1.0 );
 
 pVertices[3].vPosition = D3DXVECTOR3( 0.0f, 2.0f, 0.0f );    
 pVertices[3].crDiffuse = D3DCOLOR_COLORVALUE( 0.0, 1.0, 0.0, 1.0 );
 
 //
 pVertices[4].vPosition = D3DXVECTOR3( -2.0f, -2.0f, 0.0f );
 pVertices[4].crDiffuse = D3DCOLOR_COLORVALUE( 0.0, 0.0, 1.0, 1.0 );
 
 pVertices[5].vPosition = D3DXVECTOR3( 2.0f, 2.0f, 0.0f );    
 pVertices[5].crDiffuse = D3DCOLOR_COLORVALUE( 0.0, 0.0, 1.0, 1.0 );
 
上面的代码分别设置了三条直线的向量和颜色值。然后调用下面函数显示:
 
m_pd3dDevice->DrawPrimitive( D3DPT_LINELIST, 0, m_nLineListCount );
第一个参数设置为D3DPT_LINELIST类型,就是直线列表的方式。
 
 3D游戏从入门到精通-15
 
3、             线带列表
在D3D里还提供线带列表显示,这种显示方式是把所有直线顺着顶点连接显示出来。如下图所示:
采用线带列表显示的方式,可以减少顶点占用内存空间,提高显示效率。下面这段代码就是显示6个顶点的直线。
 
m_nLineStripCount = 3;
 
HRESULT hr;
 
 // 创建顶点缓冲区。
 if( FAILED( hr = m_pd3dDevice->CreateVertexBuffer(
       m_nLineStripCount*2 * sizeof(VT_CAIPRIMITIVE),
       0, VT_CAIPRIMITIVE::dwFVF,
       D3DPOOL_MANAGED, &pVB, NULL ) ) )
 {
       //创建顶点缓冲区失败。
       return DXTRACE_ERR( "CreateVertexBuffer", hr );
 }
 
 //
 VT_CAIPRIMITIVE* pVertices;
 if( FAILED( hr = pVB->Lock( 0, 0, (VOID**)&pVertices, 0 ) ) )
 {
       //锁住顶点缓冲区。
       return DXTRACE_ERR( "Lock", hr );
 }
 
 pVertices[0].vPosition = D3DXVECTOR3( -6.0f, -2.0f, 2.0f );
 pVertices[0].crDiffuse = D3DCOLOR_COLORVALUE( 1.0, 0.0, 0.0, 1.0 );
 
 pVertices[1].vPosition = D3DXVECTOR3( -4.0f, 2.0f, 2.0f );   
 pVertices[1].crDiffuse = D3DCOLOR_COLORVALUE( 1.0, 0.0, 0.0, 1.0 );
 
 //
 pVertices[2].vPosition = D3DXVECTOR3( -2.0f, -2.0f, 2.0f );
 pVertices[2].crDiffuse = D3DCOLOR_COLORVALUE( 0.0, 1.0, 0.0, 1.0 );
 
 pVertices[3].vPosition = D3DXVECTOR3( 0.0f, 2.0f, 0.0f );    
 pVertices[3].crDiffuse = D3DCOLOR_COLORVALUE( 0.0, 1.0, 0.0, 1.0 );
 
 //
 pVertices[4].vPosition = D3DXVECTOR3( 2.0f, -2.0f, 2.0f );   
 pVertices[4].crDiffuse = D3DCOLOR_COLORVALUE( 0.0, 0.0, 1.0, 1.0 );
 
 pVertices[5].vPosition = D3DXVECTOR3( 4.0f, 2.0f, 2.0f );    
 pVertices[5].crDiffuse = D3DCOLOR_COLORVALUE( 0.0, 0.0, 1.0, 1.0 );
 
 //解锁顶点缓冲区。
 pVB->Unlock();
 
上面的代码是先创建合适的顶点缓冲区,然后设置6个顶点的值。由这6个顶点就可以连接成为5条直线。显示的代码如下:
 
m_pd3dDevice->SetStreamSource( 0, m_pvbLineStrip, 0, sizeof(VT_CAIPRIMITIVE) );
 m_pd3dDevice->SetFVF( VT_CAIPRIMITIVE::dwFVF );
 m_pd3dDevice->DrawPrimitive( D3DPT_LINESTRIP, 0, m_nLineStripCount*2 -1 );
上面的DrawPrimitive函数设置为D3DPT_LINESTRIP显示,就是线带方式显示。最后一个参数指明了它要显示多少条直线。
 
 


推荐阅读
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • 本文介绍了Swing组件的用法,重点讲解了图标接口的定义和创建方法。图标接口用来将图标与各种组件相关联,可以是简单的绘画或使用磁盘上的GIF格式图像。文章详细介绍了图标接口的属性和绘制方法,并给出了一个菱形图标的实现示例。该示例可以配置图标的尺寸、颜色和填充状态。 ... [详细]
  • 基于Socket的多个客户端之间的聊天功能实现方法
    本文介绍了基于Socket的多个客户端之间实现聊天功能的方法,包括服务器端的实现和客户端的实现。服务器端通过每个用户的输出流向特定用户发送消息,而客户端通过输入流接收消息。同时,还介绍了相关的实体类和Socket的基本概念。 ... [详细]
  • SpringBoot uri统一权限管理的实现方法及步骤详解
    本文详细介绍了SpringBoot中实现uri统一权限管理的方法,包括表结构定义、自动统计URI并自动删除脏数据、程序启动加载等步骤。通过该方法可以提高系统的安全性,实现对系统任意接口的权限拦截验证。 ... [详细]
  • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
  • HDFS2.x新特性
    一、集群间数据拷贝scp实现两个远程主机之间的文件复制scp-rhello.txtroothadoop103:useratguiguhello.txt推pushscp-rr ... [详细]
  • 本文介绍了iOS数据库Sqlite的SQL语句分类和常见约束关键字。SQL语句分为DDL、DML和DQL三种类型,其中DDL语句用于定义、删除和修改数据表,关键字包括create、drop和alter。常见约束关键字包括if not exists、if exists、primary key、autoincrement、not null和default。此外,还介绍了常见的数据库数据类型,包括integer、text和real。 ... [详细]
  • 浏览器中的异常检测算法及其在深度学习中的应用
    本文介绍了在浏览器中进行异常检测的算法,包括统计学方法和机器学习方法,并探讨了异常检测在深度学习中的应用。异常检测在金融领域的信用卡欺诈、企业安全领域的非法入侵、IT运维中的设备维护时间点预测等方面具有广泛的应用。通过使用TensorFlow.js进行异常检测,可以实现对单变量和多变量异常的检测。统计学方法通过估计数据的分布概率来计算数据点的异常概率,而机器学习方法则通过训练数据来建立异常检测模型。 ... [详细]
  • 本文介绍了深入浅出Linux设备驱动编程的重要性,以及两种加载和删除Linux内核模块的方法。通过一个内核模块的例子,展示了模块的编译和加载过程,并讨论了模块对内核大小的控制。深入理解Linux设备驱动编程对于开发者来说非常重要。 ... [详细]
  • 上图是InnoDB存储引擎的结构。1、缓冲池InnoDB存储引擎是基于磁盘存储的,并将其中的记录按照页的方式进行管理。因此可以看作是基于磁盘的数据库系统。在数据库系统中,由于CPU速度 ... [详细]
  • 本文讨论了如何使用GStreamer来删除H264格式视频文件中的中间部分,而不需要进行重编码。作者提出了使用gst_element_seek(...)函数来实现这个目标的思路,并提到遇到了一个解决不了的BUG。文章还列举了8个解决方案,希望能够得到更好的思路。 ... [详细]
  • OpenMap教程4 – 图层概述
    本文介绍了OpenMap教程4中关于地图图层的内容,包括将ShapeLayer添加到MapBean中的方法,OpenMap支持的图层类型以及使用BufferedLayer创建图像的MapBean。此外,还介绍了Layer背景标志的作用和OMGraphicHandlerLayer的基础层类。 ... [详细]
  • 使用freemaker生成Java代码的步骤及示例代码
    本文介绍了使用freemaker这个jar包生成Java代码的步骤,通过提前编辑好的模板,可以避免写重复代码。首先需要在springboot的pom.xml文件中加入freemaker的依赖包。然后编写模板,定义要生成的Java类的属性和方法。最后编写生成代码的类,通过加载模板文件和数据模型,生成Java代码文件。本文提供了示例代码,并展示了文件目录结构。 ... [详细]
  • 本文介绍了在PostgreSQL中批量导入数据时的优化方法。包括使用unlogged表、删除重建索引、删除重建外键、禁用触发器、使用COPY方法、批量插入等。同时还提到了一些参数优化的注意事项,如设置effective_cache_size、shared_buffer等,并强调了在导入大量数据后使用analyze命令重新收集统计信息的重要性。 ... [详细]
  • 流数据流和IO流的使用及应用
    本文介绍了流数据流和IO流的基本概念和用法,包括输入流、输出流、字节流、字符流、缓冲区等。同时还介绍了异常处理和常用的流类,如FileReader、FileWriter、FileInputStream、FileOutputStream、OutputStreamWriter、InputStreamReader、BufferedReader、BufferedWriter等。此外,还介绍了系统流和标准流的使用。 ... [详细]
author-avatar
mobiledu2502881767
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有