Direct-X学习笔记--X模型导入

一.介绍

经历了之前手写立方体的痛苦过程,终于到了网格模型这一步。我们做游戏的时候肯定不能只用立方体呀,想要复杂的人物模型肯定是需要美工同学们使用专业的工具才能创建出来的,这些模型文件中定义好了网格模型的形状以及材质纹理等信息,我们所要做的只是读取这个文件,然后就可以根据文件中的信息创建复杂的模型啦!然而说白了,这些东东DX已经为我们定义好了,我们背一背API就行啦!

创建这些模型一般用3DMAX或者Maya软件,然而我作为一个程序都写不太明白的人,并不需要过多的了解这个东东,只需要知道它导出的格式就好啦。通常建模软件导出的格式为3ds,.max, .obj,.mb等,而.X为DX自带的一种格式,我们在学习阶段使用.X文件足够了。至于其他的,只是换了个识别的工具罢了,功能都是一样的。还是老套路,背API。

我们使用.X文件时,一般都是.X文件配上若干张图片,.X文件中记录了这些纹理怎么用,这个我们不需要关心。

二.过程

1.根据.X文件名读取并创建Mesh:

该函数原型如下:

HRESULT  D3DXLoadMeshFromX(
  __in   LPCTSTR pFilename,<span style="white-space:pre">			</span>//.X文件名
  __in   DWORD Options,<span style="white-space:pre">				</span>//一般为D3DXMESH_MANAGED
  __in   LPDIRECT3DDEVICE9 pD3DDevice,<span style="white-space:pre">		</span>//设备指针
  __out  LPD3DXBUFFER *ppAdjacency,<span style="white-space:pre">		</span>//网格临接信息缓冲区指针
  __out  LPD3DXBUFFER *ppMaterials,<span style="white-space:pre">		</span>//网格材质以及纹理信息缓冲区指针
  __out  LPD3DXBUFFER *ppEffectInstances,<span style="white-space:pre">	</span>//网格特效缓冲区指针
  __out  DWORD *pNumMaterials,<span style="white-space:pre">			</span>//材质信息个数
  __out  LPD3DXMESH *ppMesh<span style="white-space:pre">			</span>//Mesh指针的指针
);

这里面有个新的数据类型LPD3DXBUFFER类型,我们看到好几种信息都是存在这种类型的指针所指向的缓冲区中了。如果我们想要获得特定类型的信息要肿么办呢?

DX为我们提供了一个函数:GetBufferPointer();例如,我们想要获得材质信息,就可以这样写:

D3DXMATERIAL *pMtrl = (D3DXMATERIAL*)pMtrlBuffer->GetBufferPointer();

例如:

	D3DXLoadMeshFromX(TEXT("tiger.X"), D3DXMESH_MANAGED, g_pDevice, &pAdjBuffer, &pMtrlBuffer, NULL, &g_dwNumMtrls, &g_pMesh);

从tiger.X中创建了一个Mesh模型,相关信息都存储在我们传入的参数所指向的缓冲区中啦。

2.载入材质和纹理信息:

通过上面的函数,我们获得了材质以及纹理信息,这些信息都存储在pMtrlBuffer所指向的缓冲区中,这些材质信息是使用D3DXMATERIAL结构体存储的,该结构体的定义如下:

typedef struct D3DXMATERIAL {
  D3DMATERIAL9 MatD3D;<span style="white-space:pre">				</span>//材质信息
  LPSTR        pTextureFilename;<span style="white-space:pre">		</span>//纹理贴图文件名
} D3DXMATERIAL, *LPD3DXMATERIAL;

这样,我们就可以从这pMtrlBuffer指针指向的缓冲区中提取Mesh模型的材质以及纹理信息,并将之用到我们要绘制的对象中去。而这个结构体的数量就存储在g_dwNumMtrls中,我们只需要遍历一下,就可以将纹理材质设置好。

例如:

<span style="white-space:pre">	</span>LPD3DXBUFFER pAdjBuffer = NULL;				//临时缓冲区指针,存储对象模型信息
	LPD3DXBUFFER pMtrlBuffer = NULL;			//临时缓冲区指针,存储对象纹理材质信息
	//根据.X文件创建Mesh模型
	D3DXLoadMeshFromX(TEXT("tiger.X"), D3DXMESH_MANAGED, g_pDevice, &pAdjBuffer, &pMtrlBuffer, NULL, &g_dwNumMtrls, &g_pMesh);

	//读取材质和纹理数据
	D3DXMATERIAL *pMtrl = (D3DXMATERIAL*)pMtrlBuffer->GetBufferPointer();
	//真正存储材质以及纹理的缓冲区,动态申请内存
	g_pMaterials = new D3DMATERIAL9[g_dwNumMtrls];
	g_pTextures = new LPDIRECT3DTEXTURE9[g_dwNumMtrls];
	//根据材质纹理数遍历,设置材质纹理信息
	for (int i = 0; i < g_dwNumMtrls; i++)
	{
		g_pMaterials[i] = pMtrl[i].MatD3D;					//设置材质
		g_pMaterials[i].Ambient = g_pMaterials[i].Diffuse;	//设置环境光

		g_pTextures[i] = NULL;
		D3DXCreateTextureFromFileA(g_pDevice, pMtrl[i].pTextureFilename, &g_pTextures[i]);		//根据获得的纹理文件名创建纹理
	}
	//释放刚才传递给D3DXLoadMeshFromX函数的两个指针所指向的缓冲区
	SAFE_RELEASE(pAdjBuffer);
	SAFE_RELEASE(pMtrlBuffer);

这样,我们的Mesh模型就创建好了,东东都存在g_pMesh中啦,我们用的时候只需要通过g_pMesh就可以绘制啦。

3.绘制网格模型:

终于到最后一步了,好激动!终于要看到模型了!

绘制的时候,也是需要分部分的,因为有好几个纹理材质信息,所以就要绘制几次,这个次数当然就存在那个g_dwNumMtrls里啦,还是一样,遍历一下:

绘制之前,需要先设置材质,材质存在我们的g_pMaterials数组中,再设置纹理信息,纹理信息存在我们的g_pTexture数组中。

最后就用g_pMesh的DrawSubset()方法,只有一个参数,就是遍历的i。

例子:

	for (int i = 0; i < g_dwNumMtrls; i++)
	{
		g_pDevice->SetMaterial(&g_pMaterials[i]);
		g_pDevice->SetTexture(0, g_pTextures[i]);
		g_pMesh->DrawSubset(i);
	}

三.例子

大功告成!赶快run了一下,一只老虎就粗线了....

这样,我们就可以很简单滴绘制一个漂亮的模型,而不是痛苦滴手绘正方体....不过,凡事都是先苦后甜的,没有之前的痛苦的打基础的阶段,直接使用过于高端的技术,只会让我们更加轻浮。

完整的Demo:

素材使用的是DX自带的tiger.X

// D3DDemo.cpp : 定义应用程序的入口点。
//

#include "stdafx.h"
#include "D3DDemo.h"

#define MAX_LOADSTRING 100
#define SAFE_RELEASE(p) {if(p) {(p)->Release(); (p) = NULL;}}  

// 全局变量:
HINSTANCE hInst;								// 当前实例
TCHAR szTitle[MAX_LOADSTRING];					// 标题栏文本
TCHAR szWindowClass[MAX_LOADSTRING];			// 主窗口类名

// 此代码模块中包含的函数的前向声明:
HWND                g_hWnd;
ATOM				MyRegisterClass(HINSTANCE hInstance);
BOOL				InitInstance(HINSTANCE, int);
LRESULT CALLBACK	WndProc(HWND, UINT, WPARAM, LPARAM);

//---------改造3D窗口需要的内容------------
LPDIRECT3D9 g_pD3D = NULL; //D3D接口指针
LPDIRECT3DDEVICE9 g_pDevice = NULL;//D3D设备指针

//创建网格对象所需内容
LPD3DXMESH g_pMesh = NULL;						//网格对象
LPDIRECT3DTEXTURE9* g_pTextures = NULL;			//网格纹理信息
D3DMATERIAL9* g_pMaterials = NULL;				//网格材质信息
DWORD g_dwNumMtrls = 0;							//网格材质数目

//----------绘制图形步骤3.声明一个顶点缓冲区指针&一个索引缓冲区指针
LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL;
LPDIRECT3DINDEXBUFFER9 g_pIB = NULL;

void onCreatD3D()
{
	g_pD3D = Direct3DCreate9(D3D_SDK_VERSION);
	if (!g_pD3D)
		return;

	//检测硬件设备能力的方法
	/*D3DCAPS9 caps;
	ZeroMemory(&caps, sizeof(caps));
	g_pD3D->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps);*/

	//获得相关信息,屏幕大小,像素点属性
	D3DDISPLAYMODE d3ddm;
	ZeroMemory(&d3ddm, sizeof(d3ddm));

	g_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm);

	//设置全屏模式
	D3DPRESENT_PARAMETERS d3dpp;
	ZeroMemory(&d3dpp, sizeof(d3dpp));
	/*d3dpp.Windowed = false;
	d3dpp.BackBufferWidth = d3ddm.Width;
	d3dpp.BackBufferHeight = d3ddm.Height;*/

	d3dpp.Windowed = true;
	d3dpp.BackBufferFormat = d3ddm.Format;
	d3dpp.BackBufferCount = 1;

	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;//交换后原缓冲区数据丢弃

	//是否开启自动深度模板缓冲
	d3dpp.EnableAutoDepthStencil = true;
	//当前自动深度模板缓冲的格式
	d3dpp.AutoDepthStencilFormat = D3DFMT_D16;//每个像素点有16位的存储空间,存储离摄像机的距离

	g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, g_hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pDevice);

	if (!g_pDevice)
		return;

	//设置渲染状态,设置启用深度值
	g_pDevice->SetRenderState(D3DRS_ZENABLE, true);

	//设置渲染状态,关闭灯光
	g_pDevice->SetRenderState(D3DRS_LIGHTING, false);

	//设置渲染状态,裁剪模式
	g_pDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);

	//g_pDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE) ;

}

void CreateMesh()
{
	LPD3DXBUFFER pAdjBuffer = NULL;				//临时缓冲区指针,存储对象模型信息
	LPD3DXBUFFER pMtrlBuffer = NULL;			//临时缓冲区指针,存储对象纹理材质信息
	//根据.X文件创建Mesh模型
	D3DXLoadMeshFromX(TEXT("tiger.X"), D3DXMESH_MANAGED, g_pDevice, &pAdjBuffer, &pMtrlBuffer, NULL, &g_dwNumMtrls, &g_pMesh);

	//读取材质和纹理数据
	D3DXMATERIAL *pMtrl = (D3DXMATERIAL*)pMtrlBuffer->GetBufferPointer();
	//真正存储材质以及纹理的缓冲区,动态申请内存
	g_pMaterials = new D3DMATERIAL9[g_dwNumMtrls];
	g_pTextures = new LPDIRECT3DTEXTURE9[g_dwNumMtrls];
	//根据材质纹理数遍历,设置材质纹理信息
	for (int i = 0; i < g_dwNumMtrls; i++)
	{
		g_pMaterials[i] = pMtrl[i].MatD3D;					//设置材质
		g_pMaterials[i].Ambient = g_pMaterials[i].Diffuse;	//设置环境光

		g_pTextures[i] = NULL;
		D3DXCreateTextureFromFileA(g_pDevice, pMtrl[i].pTextureFilename, &g_pTextures[i]);		//根据获得的纹理文件名创建纹理
	}
	//释放刚才传递给D3DXLoadMeshFromX函数的两个指针所指向的缓冲区
	SAFE_RELEASE(pAdjBuffer);
	SAFE_RELEASE(pMtrlBuffer);
}

void onInit()
{
	//初始化D3D
	onCreatD3D();

	//创建Mesh模型
	CreateMesh();
}

void onDestroy()
{
	if (!g_pDevice)
		g_pDevice->Release();
	g_pDevice = NULL;
}

void onLogic(float fElapsedTime)
{

}

void Transform()
{
	//WorldTransform:世界变换
	D3DXMATRIXA16 matWorld;
	D3DXMATRIXA16 matScaling;
	//生成缩放矩阵
	D3DXMatrixScaling(&matScaling, 3.0f, 3.0f, 3.0f);
	//生成绕Y轴旋转矩阵,存储于矩阵中
	D3DXMatrixRotationY(
		&matWorld,		        //输出矩阵
		10.0f	//角度
		);
	matWorld = matScaling * matWorld;
	g_pDevice->SetTransform(D3DTS_WORLD, &matWorld);

	//ViewTransform:取景变换

	D3DXVECTOR3 vEyePt(0.0f, 0.0f, -30.0f);		//摄像机世界坐标
	D3DXVECTOR3 vLookatPt(0.0f, 0.0f, 0.0f);	//观察点世界坐标
	D3DXVECTOR3 vUpVec(0.0f, 1.0f, 0.0f);		//摄像机的上向量,通常为(0.0f, 1.0f, 0.0f)
	D3DXMATRIXA16 matView;						//View变换的矩阵
	//根据上面的结果计算出矩阵,存入矩阵中
	D3DXMatrixLookAtLH(&matView, &vEyePt, &vLookatPt, &vUpVec);
	//进行取景变换
	g_pDevice->SetTransform(D3DTS_VIEW, &matView);

	//ProjectionTransform:投影变换

	D3DXMATRIXA16 matProj;					//投影变换矩阵
	//生成投影变换矩阵,存入上面的矩阵中
	D3DXMatrixPerspectiveFovLH(
		&matProj,	     //输出结果矩阵
		D3DX_PI / 4,	 //视域角度,一般为PI/4
		1.0f,			 //显示屏的长宽比
		1.0f,			 //视截体中近截面距离摄像机的位置
		100.0f			 //视截体中远截面距离摄像机的位置
		);
	//进行投影变换
	g_pDevice->SetTransform(D3DTS_PROJECTION, &matProj);

}

void onRender(float fElasedTime)
{
	//前两个参数是0和NULL时,清空整个游戏窗口的内容(清的是后台)
	//第三个是清除的对象:前面表示清除颜色缓冲区,后面表示清除深度缓冲区,D3DCLEAR_STENCIL清空模板缓冲区
	g_pDevice->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,100,100), 1.0f, 0);

	g_pDevice->BeginScene();

	Transform();

	////----------绘制图形步骤6.设置数据源,设置灵活顶点格式,绘制图元

	//	//设置数据流来源
	//g_pDevice->SetStreamSource(
	//	0,						//数据流管道号(0-15)
	//	g_pVB,					//数据来源
	//	0,						//数据流偏移量
	//	sizeof(stVertex)		//每个数据的字节数大小
	//	);

	//	//通知系统数据格式,以便解析数据
	//g_pDevice->SetFVF(D3DFVF_CUSTOMVERTEX);

	//////绘制图元
	////g_pDevice->DrawPrimitive(
	////	D3DPT_TRIANGLESTRIP,     //三角形列
	////	0,						//起始点编号
	////	15						//图元数量
	////	);

	////设置索引缓存
	//g_pDevice->SetIndices(g_pIB);

	//

	////使用索引缓存绘制图形
	//g_pDevice->DrawIndexedPrimitive(
	//	D3DPT_TRIANGLELIST, //三角形列
	//	0,				    //顶点起点,从那个顶点开始做为索引
	//	0,					//最小索引值,通常为0
	//	24,					//索引顶点的个数
	//	0,					//起点索引,从第几个索引处开始绘制图元
	//	12					//图元个数
	//	);

	for (int i = 0; i < g_dwNumMtrls; i++)
	{
		g_pDevice->SetMaterial(&g_pMaterials[i]);
		g_pDevice->SetTexture(0, g_pTextures[i]);
		g_pMesh->DrawSubset(i);
	}

	g_pDevice->EndScene();

	g_pDevice->Present(NULL, NULL, NULL, NULL);
}

int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPTSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
	UNREFERENCED_PARAMETER(hPrevInstance);
	UNREFERENCED_PARAMETER(lpCmdLine);

 	// TODO: 在此放置代码。
	MSG msg;
	HACCEL hAccelTable;

	// 初始化全局字符串
	LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
	LoadString(hInstance, IDC_D3DDEMO, szWindowClass, MAX_LOADSTRING);
	MyRegisterClass(hInstance);

	// 执行应用程序初始化:
	if (!InitInstance (hInstance, nCmdShow))
	{
		return FALSE;
	}

	hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_D3DDEMO));

	ZeroMemory(&msg, sizeof(msg));
	while (msg.message != WM_QUIT)
	{
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else
		{
			static DWORD dwTime = timeGetTime();
			DWORD dwCurrentTime = timeGetTime();
			DWORD dwElapsedTime = dwCurrentTime - dwTime;
			float fElapsedTime = dwElapsedTime * 0.001f;

			//------------渲染和逻辑部分代码----------
			onLogic(fElapsedTime);
			onRender(fElapsedTime);
			//-----------------------------------------
			if (dwElapsedTime < 1000 / 60)
			{
				Sleep(1000/ 60 - dwElapsedTime);
			}
			dwTime = dwCurrentTime;
		}
	}

	onDestroy();
	return (int) msg.wParam;
}

//
//  函数: MyRegisterClass()
//
//  目的: 注册窗口类。
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
	WNDCLASSEX wcex;

	wcex.cbSize = sizeof(WNDCLASSEX);

	wcex.style			= CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc	= WndProc;
	wcex.cbClsExtra		= 0;
	wcex.cbWndExtra		= 0;
	wcex.hInstance		= hInstance;
	wcex.hIcon			= LoadIcon(hInstance, MAKEINTRESOURCE(IDI_D3DDEMO));
	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
	wcex.lpszMenuName	= MAKEINTRESOURCE(IDC_D3DDEMO);
	wcex.lpszClassName	= szWindowClass;
	wcex.hIconSm		= LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

	return RegisterClassEx(&wcex);
}

//
//   函数: InitInstance(HINSTANCE, int)
//
//   目的: 保存实例句柄并创建主窗口
//
//   注释:
//
//        在此函数中,我们在全局变量中保存实例句柄并
//        创建和显示主程序窗口。
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{

   hInst = hInstance; // 将实例句柄存储在全局变量中

   g_hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

   if (!g_hWnd)
   {
      return FALSE;
   }

   SetMenu(g_hWnd, NULL);
   ShowWindow(g_hWnd, nCmdShow);
   UpdateWindow(g_hWnd);

   onInit();

   return TRUE;
}

//
//  函数: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  目的: 处理主窗口的消息。
//
//  WM_COMMAND	- 处理应用程序菜单
//  WM_PAINT	- 绘制主窗口
//  WM_DESTROY	- 发送退出消息并返回
//
//
LRESULT CALLBACK WndProc(HWND g_hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
	case WM_KEYDOWN:
		if (wParam == VK_ESCAPE)
			PostQuitMessage(0);
		break;
	case WM_CLOSE:
		DestroyWindow(g_hWnd);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(g_hWnd, message, wParam, lParam);
	}
	return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-15 05:24:42

Direct-X学习笔记--X模型导入的相关文章

学习笔记-CIFAR10模型理解简述

学习笔记-CIFAR10模型理解简述 整个结构中包含三个convolution layer.三个pooling layer和两个fully connected layer. 每个层有多个Feature Map,每个Feature Map通过一种卷积滤波器提取输入的一种特征,然后每个Feature Map有多个神经元. 首先是数据层,测试数据100张为一批(batch_size),后面括号内是数据总大小.如100*32*32*3= 307200 Top shape: 100 3 32 32 (30

CSS学习笔记——盒模型,块级元素和行内元素的区别和区别

今天本来打算根据自己的计划进行前端自动化的学习的,无奈早上接到一个任务需求需要新增一个页面.自从因为工作需要转前端之后,自己的主要注意力几 乎都放在JavaScript上面了,对CSS和HTML这方面其实基础真的很差,今天在写页面的时候就被浮动啊.内外边距啊这些耽误了不少时间. 反思一下,自己确实在这些基础方面的不足很多,所以今后的学习笔记主要是我在工作中遇到的一些问题和他们的解决方法.其中可能中会有JS.CSS.HTML各方面的,我会把自己每一天学到的内容都记录一下,辅助自己打好基础. 今天在

【机器学习 第2章 学习笔记】模型评估与选择

1.训练误差:学习器在训练集上的误差,也称“经验误差” 2.泛化误差:学习器在新样本上的误差 显然,我们的目标是得到在新样本上表现更好的学习器,即泛化误差要小 3.过拟合:学习器把训练样本学的太好了,导致泛化性能下降(学过头了...让我联想到有些人死读书,读死书,僵化,不懂得变通和举一反三) 原因:学习能力过于强大,把一些不太一般的特性也学了进来 针对措施:不好解决,是机器学习面临的关键障碍 4.欠拟合:就是连训练集都没学好,更别说泛化了(有点管中窥豹,盲人摸象的意思). 原因: 学习能力低下

barabasilab-networkScience学习笔记5- Barab&#225;si-Albert 模型

第一次接触复杂性科学是在一本叫think complexity的书上,Allen博士很好的讲述了数据结构与复杂性科学,barabasi是一个知名的复杂性网络科学家,barabasilab则是他所主导的一个实验室,这里的笔记则是关于里面介绍的课程的笔记,当然别人的课程不是公开课,所以从ppt里只能看到骨干的东西了,对了补充下,slider相关的书籍在这里可以找到 这一节课有事蛮多数学推导,相比较对程序的掌握,感觉自己应该更重视数学一点. 好了不说了,这一节课讲什么呢?讲的BA模型,它解释了无标度性

Python scikit-learn 学习笔记—鸢尾花模型

鸢尾花数据是一个简易有趣的数据集.这个数据集来源于科学家在一岛上找到一种花的三种不同亚类别,分别叫做setosa,versicolor,virginica.但是这三个种类并不是很好分辩,所以他们又从花萼长度,花萼宽度,花瓣长度,花瓣宽度这四个角度测量不同的种类用于定量分析.基于这四个特征,这些数据成了一个多重变量分析的数据集.下面,我们就利用sklearn试着从不同的角度去分析一下这个数据集. 第一种思路是这样:这三种不同的品种每一种想必都会有特点或者存在一定的相似性.我们不妨先把这些杂乱无章的

【Java学习笔记】静态导入

1 package p2; 2 3 //import static java.util.Collections.max; 4 5 import java.util.ArrayList; 6 import static java.util.Collections.*; //静态导入,其实导入的是类中的静态成员 7 import java.util.List; 8 import static java.lang.System.*; 9 10 public class news { 11 12 pub

ThinkPHP学习笔记 实例化模型的四种方法

创建Action类 [php] <?php class NewObjectAction extends Action{ public function index(){ //1.创建一个基础模型 //      //一:实例化一个系统的数据库操作类 //      //new Model('User')相当于M('User'),在Model中放置一个需要操作的表 //      //1命名: //      //  thinkphp默认的有表名前缀,如果为think_user:则在Model中可

Angular2学习笔记——路由器模型(Router)

Angular2以组件化的视角来看待web应用,使用Angular2开发的web应用,就是一棵组件树.组件大致分为两类:一类是如list.table这种通放之四海而皆准的通用组件,一类是专为业务开发的业务组件.实际开发中大部分时间我们都需要处理业务组件.对于SPA应用来说,一个通用的问题就是如何控制页面的切换,解决这个问题的通用方法就是利用路由器来实现. 路由配置 现在我们先撇开Angular2来看看通用的路由器模型.通常来讲SPA应用需要路由配置信息: [ { path: '', pathMa

【python学习笔记】模块导入搜索路径的搜索顺序是什么?

搜索顺序应该是? 内置模块 ->主目录 ->PYTHONPATH环境变量 ->标准库 ->.pth文件指定的内容 所以如果主目录里有一个自定义的模块文件文件,应该会先加载,然后后面标准库的模块文件可能就不会加载了,也就是隐藏了. 还是实验一下: 创建一个sys.py在主目录下,以下是在windows的py3.5上实验的,sys.py内容: # filename sys.py in current working directory def func():     print('Th