本文由zhangbaochong原创,转载请注明出处http://www.cnblogs.com/zhangbaochong/p/5827714.html

  在前面我们曾经实现过简单的地形(Directx11学习笔记【十三】 实现一个简单地形),只不过原来使用一个固定的函数获得地形高度,这样跟真实的地形差距比较大。接下来让我们学习使用高度图来进行三维地形模拟。

1.高度图

  高度图其实就是一组连续的数组,这个数组中的元素与地形网格中的顶点一一对应,且每一个元素都指定了地形网格的某个顶点的高度值。高度图最常用的使用灰度图实现,灰度图中亮度越大对应的地形高度越高。下面就是一幅灰度图:

  

  灰度图格式通常为.raw,google一下高度图保存图片改为raw格式就可以了。高度图每个元素通常只分配一个字节,即数值在0~255之间。但在实际使用的时候经常要对高度进行比例变换,因此需要将byte转为float,然后通过一个缩放系数进行缩放,这样就不必拘泥于0~255这么一个范围了。

2.读取高度图

  读取高度图很简单,用二进制读取文件就好了。

 //读取高度图信息
bool TerrainDemo::ReadRawFile(std::string filePath)
{
std::ifstream inFile;
//二进制方式打开文件
inFile.open(filePath.c_str(), std::ios::binary);
//文件指针移动到末尾
inFile.seekg(, std::ios::end);
//大小为当前缓冲区大小
std::vector<BYTE> inData(inFile.tellg());
//文件指针移动到开头
inFile.seekg(std::ios::beg);
//读取高度信息
inFile.read((char*)&inData[], inData.size());
inFile.close(); m_heightInfos.resize(inData.size());
for (int i = ; i < inData.size(); ++i)
{
m_heightInfos[i] = inData[i];
} return true;
}

3.顶点和索引的计算

  顶点和索引的计算同Directx11学习笔记【十三】 实现一个简单地形类似,这里就不再详细说明了。不一样的由于采用了纹理光照渲染,所以需要得到法线,在计算索引的同时需要把顶点法线计算出来:

 //计算法线
void TerrainDemo::ComputeNomal(Vertex& v1, Vertex& v2, Vertex& v3, XMFLOAT3& normal)
{
XMFLOAT3 f1(v2.pos.x - v1.pos.x, v2.pos.y - v1.pos.y, v2.pos.z - v1.pos.z);
XMFLOAT3 f2(v3.pos.x - v1.pos.x, v3.pos.y - v1.pos.y, v3.pos.z - v1.pos.z);
XMVECTOR vec1 = XMLoadFloat3(&f1);
XMVECTOR vec2 = XMLoadFloat3(&f2);
XMVECTOR temp = XMVector3Normalize(XMVector3Cross(vec1, vec2));
XMStoreFloat3(&normal, temp);
}

  计算顶点和索引:

 bool TerrainDemo::InitTerrain(float width, float height, UINT m, UINT n,float scale)
{
m_cellsPerRow = m;
m_cellsPerCol = n;
m_verticesPerRow = m + ;
m_verticesPerCol = n + ;
m_numsVertices = m_verticesPerRow*m_verticesPerCol;
m_width = width;
m_height = height;
m_heightScale = scale; //得到缩放后的高度
for (auto& item : m_heightInfos)
{
item *= m_heightScale;
} //起始x z坐标
float oX = -width * 0.5f;
float oZ = height * 0.5f;
//每一格坐标变化
float dx = width / m;
float dz = height / n; m_vertices.resize(m_numsVertices);
//计算顶点
for (UINT i = ; i < m_verticesPerCol; ++i)
{
float tempZ = oZ - dz * i;
for (UINT j = ; j < m_verticesPerRow; ++j)
{
UINT index = m_verticesPerRow * i + j;
m_vertices[index].pos.x = oX + dx * j;
m_vertices[index].pos.y = m_heightInfos[index];
m_vertices[index].pos.z = tempZ; m_vertices[index].tex = XMFLOAT2(dx*i, dx*j);
}
} //计算索引和法线
//总格子数量:m * n
//因此总索引数量: 6 * m * n
UINT nIndices = m * n * ;
m_indices.resize(nIndices);
UINT tmp = ;
for (UINT i = ; i < n; ++i)
{
for (UINT j = ; j < m; ++j)
{
m_indices[tmp] = i * m_verticesPerRow + j;
m_indices[tmp + ] = i * m_verticesPerRow + j + ;
m_indices[tmp + ] = (i + ) * m_verticesPerRow + j; //计算法线
XMFLOAT3 temp;
ComputeNomal(m_vertices[m_indices[tmp]], m_vertices[m_indices[tmp + ]],
m_vertices[m_indices[tmp + ]], temp);
m_vertices[m_indices[tmp]].normal = temp;
m_vertices[m_indices[tmp + ]].normal = temp;
m_vertices[m_indices[tmp + ]].normal = temp; m_indices[tmp + ] = i * m_verticesPerRow + j + ;
m_indices[tmp + ] = (i + ) * m_verticesPerRow + j + ;
m_indices[tmp + ] = (i + ) * m_verticesPerRow + j; ComputeNomal(m_vertices[m_indices[tmp + ]], m_vertices[m_indices[tmp + ]],
m_vertices[m_indices[tmp + ]], temp);
m_vertices[m_indices[tmp + ]].normal = temp;
m_vertices[m_indices[tmp + ]].normal = temp;
m_vertices[m_indices[tmp + ]].normal = temp; tmp += ;
}
} return true;
}

4.效果截图

5.详细源码

TerrainDemo.h

 #pragma once
#include <string>
#include <vector>
#include "Dx11Base.h"
#include "Camera.h"
#include "Input.h"
#include "Utility.h"
#include "LightHelper.h" class TerrainDemo : public Dx11Base
{
public:
TerrainDemo(HINSTANCE hInst, std::wstring title = L"TerrainDemo", int width = , int height = );
~TerrainDemo(); //顶点结构 位置、法线、uv坐标
struct Vertex
{
Vertex() {}
Vertex(const XMFLOAT3 _pos, XMFLOAT3 _normal, XMFLOAT2 _tex) :
pos(_pos), normal(_normal), tex(_tex) {} XMFLOAT3 pos;
XMFLOAT3 normal;
XMFLOAT2 tex;
}; bool Init() override;
void Update(float dt);
void Render(); bool OnResize() override;
private:
bool BuildBuffers();
bool BuildSRVs();
bool BuildInputLayouts();
void UpdateCamera(float dt);
private:
bool ReadRawFile(std::string filePath); //从高度图读取高度信息
bool InitTerrain(float width, float height, UINT m, UINT n, float scale); //初始化地形
void ComputeNomal(Vertex& v1, Vertex& v2, Vertex& v3, XMFLOAT3& normal); //计算法线
private:
std::vector<float> m_heightInfos; //高度图高度信息
int m_cellsPerRow; //每行单元格数
int m_cellsPerCol; //每列单元格数
int m_verticesPerRow; //每行顶点数
int m_verticesPerCol; //每列顶点数
int m_numsVertices; //顶点总数
float m_width; //地形宽度
float m_height; //地形高度
float m_heightScale; //高度缩放系数 std::vector<Vertex> m_vertices; //顶点集合
std::vector<UINT> m_indices; //索引集合 private:
ID3D11Buffer* m_pVertexBuffer;
ID3D11Buffer* m_pIndexBuffer;
ID3D11InputLayout* m_pInputLayout;
ID3D11ShaderResourceView* m_pSRVTerrain; Lights::DirectionalLight m_dirLights[]; //3个平行光源
Lights::Material m_materialTerrain; //材质 Camera m_camera; XMFLOAT4X4 m_world; //世界变换矩阵
XMFLOAT4X4 m_worldViewProj; //世界视角投影矩阵
XMFLOAT4X4 m_worldInvTranspose; //世界逆矩阵的转置,用于法线变换
XMFLOAT4X4 m_texTrans; //纹理坐标变换矩阵 POINT m_lastMousePos;
};

TerrainDemo.cpp

 #include <fstream>
#include <memory>
#include "TerrainDemo.h"
#include "Utility.h"
#include "WICTextureLoader.h"
#include "d3dx11effect.h"
#include "Effects.h" TerrainDemo::TerrainDemo(HINSTANCE hInst, std::wstring title, int width, int height)
:Dx11Base(hInst, title, width, height)
{
//"三点式"照明
//主光源
m_dirLights[].ambient = XMFLOAT4(0.3f, 0.3f, 0.3f, 1.0f);
m_dirLights[].diffuse = XMFLOAT4(0.5f, 0.5f, 0.5f, 1.0f);
m_dirLights[].specular = XMFLOAT4(0.5f, 0.5f, 0.5f, 1.0f);
m_dirLights[].direction = XMFLOAT3(0.57735f, -0.57735f, 0.57735f);
//侧光源
m_dirLights[].ambient = XMFLOAT4(0.0f, 0.0f, 0.0f, 1.0f);
m_dirLights[].diffuse = XMFLOAT4(0.20f, 0.20f, 0.20f, 1.0f);
m_dirLights[].specular = XMFLOAT4(0.25f, 0.25f, 0.25f, 1.0f);
m_dirLights[].direction = XMFLOAT3(-0.57735f, -0.57735f, 0.57735f);
//背光源
m_dirLights[].ambient = XMFLOAT4(0.0f, 0.0f, 0.0f, 1.0f);
m_dirLights[].diffuse = XMFLOAT4(0.2f, 0.2f, 0.2f, 1.0f);
m_dirLights[].specular = XMFLOAT4(0.0f, 0.0f, 0.0f, 1.0f);
m_dirLights[].direction = XMFLOAT3(0.0f, -0.707f, -0.707f); //材质
m_materialTerrain.ambient = XMFLOAT4(0.5f, 0.5f, 0.5f, 1.0f);
m_materialTerrain.diffuse = XMFLOAT4(.f, .f, .f, 1.0f);
m_materialTerrain.specular = XMFLOAT4(0.3f, 0.3f, 0.3f, 16.0f); //设置相机
m_lastMousePos = { , };
XMVECTOR Eye = XMVectorSet(0.0f, 50.0f, 0.1f, 0.0f);
XMVECTOR At = XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f);
XMVECTOR Up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
m_camera.LookAtXM(Eye, At, Up);
//设置投影矩阵
m_camera.SetLens(XM_PIDIV4, AspectRatio(), 0.1f, .f); //初始化世界矩阵 逆转置矩阵 及纹理坐标矩阵
//这些每一帧不改变
XMMATRIX I = XMMatrixIdentity();
XMStoreFloat4x4(&m_world, I);
XMVECTOR det = XMMatrixDeterminant(I);
XMMATRIX worldInvTranspose = XMMatrixTranspose(XMMatrixInverse(&det,I));
XMStoreFloat4x4(&m_worldInvTranspose, worldInvTranspose);
XMStoreFloat4x4(&m_texTrans, I);
} TerrainDemo::~TerrainDemo()
{
SafeRelease(m_pVertexBuffer);
SafeRelease(m_pIndexBuffer);
SafeRelease(m_pInputLayout);
SafeRelease(m_pSRVTerrain);
Effects::ReleaseAll();
} bool TerrainDemo::Init()
{
if (!Dx11Base::Init())
return false;
if (!Effects::InitAll(m_pd3dDevice))
return false;
if (!ReadRawFile("Texture\\heightmap.raw"))
return false;
if (!InitTerrain(, , , , 0.2f))
return false;
if (!BuildBuffers())
return false;
if (!BuildSRVs())
return false;
if (!BuildInputLayouts())
return false;
} void TerrainDemo::Update(float dt)
{
UpdateCamera(dt);
XMMATRIX world = XMLoadFloat4x4(&m_world);
XMMATRIX worldViewProj = world * m_camera.GetViewProj();
XMStoreFloat4x4(&m_worldViewProj, worldViewProj); //设置灯光
Effects::ms_pBasicEffect->m_pFxDirLights->SetRawValue(&m_dirLights, ,
* sizeof(Lights::DirectionalLight));
Effects::ms_pBasicEffect->m_pFxEyePos->SetRawValue(&m_camera.GetPosition(), ,
sizeof(m_camera.GetPosition()));
} void TerrainDemo::Render()
{
m_pImmediateContext->ClearRenderTargetView(m_pRenderTargetView, Colors::Silver);
m_pImmediateContext->ClearDepthStencilView(m_pDepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, );
m_pImmediateContext->IASetInputLayout(m_pInputLayout); UINT stride = sizeof(Vertex);
UINT offset = ;
m_pImmediateContext->IASetVertexBuffers(, , &m_pVertexBuffer, &stride, &offset);
m_pImmediateContext->IASetIndexBuffer(m_pIndexBuffer, DXGI_FORMAT_R32_UINT, offset);
m_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); D3DX11_TECHNIQUE_DESC desc;
ID3DX11EffectTechnique* tech = Effects::ms_pBasicEffect->m_pFxLight3TexTech;
tech->GetDesc(&desc); for (UINT i = ; i < desc.Passes; ++i)
{
//设置着色器变量
Effects::ms_pBasicEffect->m_pFxWorld->SetMatrix(reinterpret_cast<const float*>(&m_world));
Effects::ms_pBasicEffect->m_pFxWorldViewProj->SetMatrix(reinterpret_cast<const float*>(
&m_worldViewProj));
Effects::ms_pBasicEffect->m_pFxWorldInvTranspose->SetMatrix(reinterpret_cast<const float*>(
&m_worldInvTranspose));
Effects::ms_pBasicEffect->m_pFxTexTrans->SetMatrix(reinterpret_cast<const float*>(
&m_texTrans));
Effects::ms_pBasicEffect->m_pFxMaterial->SetRawValue(&m_materialTerrain, , sizeof(m_materialTerrain));
Effects::ms_pBasicEffect->m_pFxSR->SetResource(m_pSRVTerrain);
tech->GetPassByIndex(i)->Apply(, m_pImmediateContext);
m_pImmediateContext->DrawIndexed(m_indices.size(), , );
} m_pSwapChain->Present(, );
} bool TerrainDemo::OnResize()
{
if (!Dx11Base::OnResize())
return false;
//更新camera参数
m_camera.SetLens(XM_PIDIV4, AspectRatio(), .f, .f); return true;
} bool TerrainDemo::BuildBuffers()
{
//创建顶点缓冲区
D3D11_BUFFER_DESC vertexDesc;
ZeroMemory(&vertexDesc, sizeof(vertexDesc));
vertexDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vertexDesc.ByteWidth = sizeof(Vertex) * m_numsVertices;
vertexDesc.Usage = D3D11_USAGE_IMMUTABLE; D3D11_SUBRESOURCE_DATA vertexData;
vertexData.pSysMem = &m_vertices[];
vertexData.SysMemPitch = ;
vertexData.SysMemSlicePitch = ;
if (FAILED(m_pd3dDevice->CreateBuffer(&vertexDesc, &vertexData, &m_pVertexBuffer)))
{
MessageBox(nullptr, L"Create Vertex Buffer failed!", L"Error", MB_OK);
return false;
} //创建索引缓冲区
D3D11_BUFFER_DESC indexDesc;
ZeroMemory(&indexDesc, sizeof(indexDesc));
indexDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
indexDesc.ByteWidth = sizeof(UINT) * m_indices.size();
indexDesc.Usage = D3D11_USAGE_IMMUTABLE; D3D11_SUBRESOURCE_DATA indexData;
indexData.pSysMem = &m_indices[];
indexData.SysMemPitch = ;
indexData.SysMemSlicePitch = ;
if (FAILED(m_pd3dDevice->CreateBuffer(&indexDesc, &indexData, &m_pIndexBuffer)))
{
MessageBox(nullptr, L"Create Index Buffer failed!", L"Error", MB_OK);
return false;
} return true;
} bool TerrainDemo::BuildSRVs()
{
if (FAILED(CreateWICTextureFromFile(m_pd3dDevice, L"Texture\\desert.bmp", nullptr, &m_pSRVTerrain)))
{
MessageBox(nullptr, L"create texture failed!", L"error", MB_OK);
return false;
}
return true;
} bool TerrainDemo::BuildInputLayouts()
{
D3D11_INPUT_ELEMENT_DESC layout[] =
{
{ "POSITION", , DXGI_FORMAT_R32G32B32_FLOAT, , , D3D11_INPUT_PER_VERTEX_DATA, },
{ "NORMAL", , DXGI_FORMAT_R32G32B32_FLOAT, , ,D3D11_INPUT_PER_VERTEX_DATA, },
{ "TEXCOORD", , DXGI_FORMAT_R32G32_FLOAT, , ,D3D11_INPUT_PER_VERTEX_DATA, }
}; UINT numLayoutElements = ARRAYSIZE(layout);
D3DX11_PASS_DESC passDesc;
Effects::ms_pBasicEffect->m_pFxLight3TexTech->GetPassByIndex()->GetDesc(&passDesc);
if (FAILED(m_pd3dDevice->CreateInputLayout(layout, numLayoutElements, passDesc.pIAInputSignature,
passDesc.IAInputSignatureSize, &m_pInputLayout)))
{
MessageBox(nullptr, L"create inputLayout failed!", L"error", MB_OK);
return false;
}
return true;
} void TerrainDemo::UpdateCamera(float dt)
{
//前后左右行走
if (Input::GetInstance()->IsKeyDown('A'))
{
m_camera.Strafe(-.f*dt);
}
else if (Input::GetInstance()->IsKeyDown('D'))
{
m_camera.Strafe(.f*dt);
}
if (Input::GetInstance()->IsKeyDown('W'))
{
m_camera.Walk(.f*dt);
}
else if (Input::GetInstance()->IsKeyDown('S'))
{
m_camera.Walk(-.f*dt);
} if (Input::GetInstance()->IsMouseMove())
{
float mouseX = Input::GetInstance()->GetMouseX();
float mouseY = Input::GetInstance()->GetMouseY();
if (Input::GetInstance()->IsLMouseDown())
{
float dx = XMConvertToRadians(0.25f*(mouseX - m_lastMousePos.x));
float dy = XMConvertToRadians(0.25f*(mouseY - m_lastMousePos.y)); OutputDebugString(L"left btn click");
m_camera.Pitch(dy);
m_camera.RotateY(dx);
}
m_lastMousePos.x = mouseX;
m_lastMousePos.y = mouseY;
} m_camera.UpdateViewMatrix();
} //读取高度图信息
bool TerrainDemo::ReadRawFile(std::string filePath)
{
std::ifstream inFile;
//二进制方式打开文件
inFile.open(filePath.c_str(), std::ios::binary);
//文件指针移动到末尾
inFile.seekg(, std::ios::end);
//大小为当前缓冲区大小
std::vector<BYTE> inData(inFile.tellg());
//文件指针移动到开头
inFile.seekg(std::ios::beg);
//读取高度信息
inFile.read((char*)&inData[], inData.size());
inFile.close(); m_heightInfos.resize(inData.size());
for (int i = ; i < inData.size(); ++i)
{
m_heightInfos[i] = inData[i];
} return true;
} bool TerrainDemo::InitTerrain(float width, float height, UINT m, UINT n,float scale)
{
m_cellsPerRow = m;
m_cellsPerCol = n;
m_verticesPerRow = m + ;
m_verticesPerCol = n + ;
m_numsVertices = m_verticesPerRow*m_verticesPerCol;
m_width = width;
m_height = height;
m_heightScale = scale; //得到缩放后的高度
for (auto& item : m_heightInfos)
{
item *= m_heightScale;
} //起始x z坐标
float oX = -width * 0.5f;
float oZ = height * 0.5f;
//每一格坐标变化
float dx = width / m;
float dz = height / n; m_vertices.resize(m_numsVertices);
//计算顶点
for (UINT i = ; i < m_verticesPerCol; ++i)
{
float tempZ = oZ - dz * i;
for (UINT j = ; j < m_verticesPerRow; ++j)
{
UINT index = m_verticesPerRow * i + j;
m_vertices[index].pos.x = oX + dx * j;
m_vertices[index].pos.y = m_heightInfos[index];
m_vertices[index].pos.z = tempZ; m_vertices[index].tex = XMFLOAT2(dx*i, dx*j);
}
} //计算索引和法线
//总格子数量:m * n
//因此总索引数量: 6 * m * n
UINT nIndices = m * n * ;
m_indices.resize(nIndices);
UINT tmp = ;
for (UINT i = ; i < n; ++i)
{
for (UINT j = ; j < m; ++j)
{
m_indices[tmp] = i * m_verticesPerRow + j;
m_indices[tmp + ] = i * m_verticesPerRow + j + ;
m_indices[tmp + ] = (i + ) * m_verticesPerRow + j; //计算法线
XMFLOAT3 temp;
ComputeNomal(m_vertices[m_indices[tmp]], m_vertices[m_indices[tmp + ]],
m_vertices[m_indices[tmp + ]], temp);
m_vertices[m_indices[tmp]].normal = temp;
m_vertices[m_indices[tmp + ]].normal = temp;
m_vertices[m_indices[tmp + ]].normal = temp; m_indices[tmp + ] = i * m_verticesPerRow + j + ;
m_indices[tmp + ] = (i + ) * m_verticesPerRow + j + ;
m_indices[tmp + ] = (i + ) * m_verticesPerRow + j; ComputeNomal(m_vertices[m_indices[tmp + ]], m_vertices[m_indices[tmp + ]],
m_vertices[m_indices[tmp + ]], temp);
m_vertices[m_indices[tmp + ]].normal = temp;
m_vertices[m_indices[tmp + ]].normal = temp;
m_vertices[m_indices[tmp + ]].normal = temp; tmp += ;
}
} return true;
} //计算法线
void TerrainDemo::ComputeNomal(Vertex& v1, Vertex& v2, Vertex& v3, XMFLOAT3& normal)
{
XMFLOAT3 f1(v2.pos.x - v1.pos.x, v2.pos.y - v1.pos.y, v2.pos.z - v1.pos.z);
XMFLOAT3 f2(v3.pos.x - v1.pos.x, v3.pos.y - v1.pos.y, v3.pos.z - v1.pos.z);
XMVECTOR vec1 = XMLoadFloat3(&f1);
XMVECTOR vec2 = XMLoadFloat3(&f2);
XMVECTOR temp = XMVector3Normalize(XMVector3Cross(vec1, vec2));
XMStoreFloat3(&normal, temp);
} int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR cmdLine, int cmdShow)
{
std::shared_ptr<Dx11Base> bd(new TerrainDemo(hInstance));
if (!bd->Init())
return -;
return bd->Run();
}

Directx11学习笔记【二十二】 用高度图实现地形的更多相关文章

  1. Directx11学习笔记【十二】 画一个旋转的彩色立方体

    上一次我们学习了如何画一个2D三角形,现在让我们进一步学习如何画一个旋转的彩色立方体吧. 具体流程同画三角形类似,因此不再给出完整代码了,不同的部分会再说明. 由于我们要画彩色的立方体,所以顶点结构体 ...

  2. VSTO 学习笔记(十二)自定义公式与Ribbon

    原文:VSTO 学习笔记(十二)自定义公式与Ribbon 这几天工作中在开发一个Excel插件,包含自定义公式,根据条件从数据库中查询结果.这次我们来做一个简单的测试,达到类似的目的. 即在Excel ...

  3. 汇编入门学习笔记 (十二)—— int指令、port

    疯狂的暑假学习之  汇编入门学习笔记 (十二)--  int指令.port 參考: <汇编语言> 王爽 第13.14章 一.int指令 1. int指令引发的中断 int n指令,相当于引 ...

  4. Binder学习笔记(十二)—— binder_transaction(...)都干了什么?

    binder_open(...)都干了什么? 在回答binder_transaction(...)之前,还有一些基础设施要去探究,比如binder_open(...),binder_mmap(...) ...

  5. java之jvm学习笔记六-十二(实践写自己的安全管理器)(jar包的代码认证和签名) (实践对jar包的代码签名) (策略文件)(策略和保护域) (访问控制器) (访问控制器的栈校验机制) (jvm基本结构)

    java之jvm学习笔记六(实践写自己的安全管理器) 安全管理器SecurityManager里设计的内容实在是非常的庞大,它的核心方法就是checkPerssiom这个方法里又调用 AccessCo ...

  6. Android学习笔记(十二)——实战:制作一个聊天界面

    //此系列博文是<第一行Android代码>的学习笔记,如有错漏,欢迎指正! 运用简单的布局知识,我们可以来尝试制作一个聊天界面. 一.制作 Nine-Patch 图片 : Nine-Pa ...

  7. MySQL数据库学习笔记(十二)----开源工具DbUtils的使用(数据库的增删改查)

    [声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4 ...

  8. 如鹏网学习笔记(十二)HTML5

    一.HTML5简介 HTML5是HTML语言第五次修改产生的新的HTML语言版本 改进主要包括: 增加新的HTML标签或者属性.新的CSS样式属性.新的JavaScript API等.同时删除了一些过 ...

  9. o'Reill的SVG精髓(第二版)学习笔记——第十二章

    第十二章 SVG动画 12.1动画基础 SVG的动画特性基于万维网联盟的“同步多媒体集成语言”(SMIL)规范(http://www.w3.org/TR/SMIL3). 在这个动画系统中,我们可以指定 ...

  10. Dynamic CRM 2013学习笔记(十二)实现子表合计(汇总,求和)功能的通用插件

    上一篇 Dynamic CRM 2013学习笔记(十一)利用Javascript实现子表合计(汇总,求和)功能 , 介绍了如何用js来实现子表合计功能,这种方法要求在各个表单上添加js方法,如果有很多 ...

随机推荐

  1. Oracle的dbms_output包的put()和put_line()的区别只是有没有回车换行吗?(转)

    答案是否 除了自动添加回车换行外,还有就是缓冲区最大容量的问题!! 无论如何设置serveroutput size,10g里 put() 最多只能输出 32767 个byte 而 put_line() ...

  2. Android开发四大组件概述

    这个文章主要是讲Android开发的四大组件,本文主要分为 一.Activity具体解释 二.Service具体解释 三.Broadcast Receiver具体解释 四.Content Provid ...

  3. OCA读书笔记(13) - 性能管理

    使用EM监控性能使用自动内存管理(AMM)使用Memory Advisor分配内存查看性能相关动态视图诊断无效的和不可用的对象 创建问题SQLsqlplus / as sysdbaconn scott ...

  4. Android NDK入门实例 计算斐波那契数列一生成jni头文件

    最近要用到Android NDK,调用本地代码.就学了下Android NDK,顺便与大家分享.下面以一个具体的实例计算斐波那契数列,说明如何利用Android NDK,调用本地代码.以及比较本地代码 ...

  5. Android 程序静态分析

    简介 静态分析是探索Android程序内幕的一种最常见的方法,它与动态调剂双剑合璧,帮助分析人员解决分析时遇到的各种“疑难”问题. 静态分析是指在不运行的情况下,采用词法分析.语法分析等各种技术手段对 ...

  6. 新一代自平衡电动代步工具Solo wheel!

    http://m.baidu.com/from=844b/bd_page_type=1/ssid=0/uid=3151E6C0905477A13653132D762BB6FB/pu=sz%401320 ...

  7. Uva10290 - {Sum+=i++} to Reach N

    Problem H {sum+=i++} to Reach N Input: standard input Output:  standard output Memory Limit: 32 MB A ...

  8. GDAL切割重采样遥感图像

    一个小测试程序开发全过程实录,完全新手入门级的实例,如果你还在为处理大影像而发愁,来试试这个称手的工具吧. Imagec 开发日记 2013-6-25 需求: 影像数据切割,重采样 数据切割的要求是简 ...

  9. 用XAML做网页!!—开篇

    原文:用XAML做网页!!-开篇 这几日一直没发表新文章,一来是因为事比较多,二来就是我在研究使用XAML挑战传统HTML来做网页,这很可能是在全球的首次尝试,至少我从未找到任何可供参考的相关资料. ...

  10. poj1804(归并排序求逆序数)

    逆序数.也就是说,对于n个不同的元素,先规定各元素之间有一个标准次序(比如n个 不同的自然数,可规定从小到大为标准次序),于是在这n个元素的任一排列中,当某两个元素的先后次序与标准次序不同一时候,就说 ...