法线原理

 

// 法相贴图.cpp : 定义应用程序的入口点。
//

#include "stdafx.h"
#include "法相贴图.h"
#include<d3d9.h>
#include<d3dx9.h>
#include<mmsystem.h>
#include<windows.h>

#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")

HWND g_hWnd ;

LPDIRECT3D9              g_pD3D         = NULL ;
LPDIRECT3DDEVICE9        g_pd3dDevice   = NULL ;
LPDIRECT3DVERTEXBUFFER9  g_pVB          = NULL ;
LPDIRECT3DTEXTURE9       g_pTexDiffuse  = NULL ; //纹理壁画
LPDIRECT3DTEXTURE9       g_pTexNormal   = NULL ; //纹理法线贴画
LPDIRECT3DVERTEXBUFFER9  g_pVB1          = NULL ;

 

D3DXMATRIXA16            g_matAni        ;   
D3DXVECTOR3              g_vLighter      ;  //光源

 

struct CUSTOMVERTEX
{
 FLOAT x,y,z;
 DWORD color;
 FLOAT u,v;   //纹理坐标
};

#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ |D3DFVF_DIFFUSE|D3DFVF_TEX1|D3DFVF_TEXCOORDSIZE2(0))

 

HRESULT InitD3D (HWND hWnd )
{
 //创建D3D对象
 if(NULL == ( g_pD3D =Direct3DCreate9 ( D3D_SDK_VERSION ) ))
  return E_FAIL;
 //创建设备的结构体
 D3DPRESENT_PARAMETERS d3dpp;
 ZeroMemory(&d3dpp ,sizeof(d3dpp));
 d3dpp.Windowed                 = TRUE;
 d3dpp.SwapEffect               = D3DSWAPEFFECT_DISCARD;
 d3dpp.BackBufferFormat         = D3DFMT_UNKNOWN;
 d3dpp.EnableAutoDepthStencil   = TRUE;
 d3dpp.AutoDepthStencilFormat   = D3DFMT_D16;

  if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
                                      D3DCREATE_SOFTWARE_VERTEXPROCESSING,
                                      &d3dpp, &g_pd3dDevice ) ) )
     return E_FAIL;

  //实现卷起功能
  g_pd3dDevice->SetRenderState(D3DRS_CULLMODE , D3DCULL_NONE);
 

  //起到z缓冲的功能
  g_pd3dDevice->SetRenderState(D3DRS_ZENABLE , TRUE );

  //顶点具有颜色,能起到光源的功能
  g_pd3dDevice->SetRenderState(D3DRS_LIGHTING ,FALSE);

  return S_OK;
}

 

HRESULT InitVB()
{
 CUSTOMVERTEX vertices[]=
 {
  {-0.5, 0.5,0,0xffffffff,0,0},    //v0
  { 0.5, 0.5,0,0xffffffff,1,0},    //v1
  {-0.5,-0.5,0,0xffffffff,0,1},    //v2
  { 0.5,-0.5,0,0xffffffff,1,1}     //v3
 };


 if(FAILED (g_pd3dDevice->CreateVertexBuffer( 4*sizeof(CUSTOMVERTEX),0,D3DFVF_CUSTOMVERTEX,
  D3DPOOL_DEFAULT ,&g_pVB ,NULL)))
  return E_FAIL;

 void *pVertices;
 if(FAILED (g_pVB->Lock(0, sizeof(CUSTOMVERTEX), (void **) &pVertices, 0 )))
  return E_FAIL;
 memcpy(pVertices ,vertices ,sizeof(vertices));
 g_pVB->Unlock();

 return S_OK;
}


HRESULT InitTexture()
{
 //壁面纹理
 if(FAILED( D3DXCreateTextureFromFile(g_pd3dDevice , L"env2.bmp",&g_pTexDiffuse )))
  return E_FAIL;

 //然后我们现在写法线贴图初始化
 if(FAILED( D3DXCreateTextureFromFile(g_pd3dDevice , L"normal.bmp",&g_pTexNormal )))
  return E_FAIL;

 return S_OK;

}

 

 

 

HRESULT InitGeometry()
{
 if(FAILED(InitVB()))       return E_FAIL;
 if(FAILED(InitTexture()))  return E_FAIL;

 g_vLighter = D3DXVECTOR3(0.0f ,0.0f ,1.0f);   //这个是在写光源的初始化
 return S_OK;
}


void SetupCamera()
{
 //创建一个世界矩阵
 D3DXMATRIXA16  matWorld;
 D3DXMatrixIdentity( &matWorld );
 g_pd3dDevice->SetTransform( D3DTS_WORLD , &matWorld );
 
 //创建视图矩阵
 D3DXVECTOR3 vEyePt   ( 0.0f , 0.0f , -4.0f );
 D3DXVECTOR3 vLookatPt( 0.0f , 0.0f , 0.0f  );
 D3DXVECTOR3 vUpVec   ( 0.0f , 1.0f , 0.0f  );
 //视图矩阵
 D3DXMATRIXA16  matView ;
 D3DXMatrixLookAtLH(&matView , &vEyePt , &vLookatPt , &vUpVec);
 g_pd3dDevice->SetTransform( D3DTS_VIEW , &matView );

 //创建投影矩阵
 D3DXMATRIXA16  matProj ;
 D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4,1.0f , 1.0f ,100.0f );    //近裁面和远裁面都是1.0
 g_pd3dDevice->SetTransform( D3DTS_PROJECTION , &matProj );

}

//光源设置
void Animate()
{
 D3DXMatrixIdentity( &g_matAni);

 POINT pt;
 GetCursorPos( &pt);
 ScreenToClient( g_hWnd , &pt);

 g_vLighter.x = -((2.0 *pt.x)/500.0-1);
 g_vLighter.y = -((2.0 *pt.y)/500.0-1);
 g_vLighter.z = 0.0f;

 if(D3DXVec3Length(&g_vLighter)>1.0f)
  D3DXVec3Normalize( &g_vLighter ,&g_vLighter );
 else
  g_vLighter.z =sqrtf(1.0f - g_vLighter.x *g_vLighter.x -g_vLighter.y* g_vLighter.y);   //sqrt是更号

}

 

void CleanUp()
{
 if(g_pVB !=NULL)
  g_pVB->Release();
 if(g_pD3D!=NULL)
  g_pD3D->Release();
 if(g_pd3dDevice!=NULL)
  g_pd3dDevice->Release();
}

void DrawMesh(D3DXMATRIXA16 * pMat)
{
 g_pd3dDevice->SetTransform(D3DTS_WORLD ,pMat);
 g_pd3dDevice->SetStreamSource( 0 ,g_pVB , 0, sizeof(CUSTOMVERTEX));
    g_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
 g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP , 0 , 2 ); 
}


DWORD VectortoRGBA(D3DXVECTOR3 *v,FLOAT fHeight)
{
 DWORD r = (DWORD)(127.0f *v->x +128.0f);
 DWORD g = (DWORD)(127.0f *v->y +128.0f);
 DWORD b = (DWORD)(127.0f *v->z +128.0f);
 DWORD a = (DWORD)(255.0f *fHeight);

 return ((a<<24L)+(r<<16L)+(g<<8L)+(b<<0L));
}

 

void Render()
{
 D3DXMATRIXA16 matWorld;

 //后置缓冲和Z缓冲以及背景初始化
 g_pd3dDevice->Clear(0 , NULL , D3DCLEAR_TARGET |D3DCLEAR_ZBUFFER , D3DCOLOR_XRGB(0,0,255),1.0f,0);

 //创建动画矩阵,设定灯光的位置
 Animate();

 if(SUCCEEDED(g_pd3dDevice->BeginScene()))
 {
  g_pd3dDevice->SetTexture(0,g_pTexNormal);
  //法线贴图
  g_pd3dDevice->SetTexture(1,g_pTexDiffuse);
  //壁画贴图
  g_pd3dDevice->SetSamplerState(0 ,D3DSAMP_MAGFILTER ,D3DTEXF_LINEAR);
  //0号纹理的放大滤镜
  g_pd3dDevice->SetSamplerState(1 ,D3DSAMP_MAGFILTER ,D3DTEXF_LINEAR);
  //1号纹理的放大滤镜
  g_pd3dDevice->SetTextureStageState( 0 , D3DTSS_TEXCOORDINDEX , 0);
  //0号纹理使用0号纹理索引
  g_pd3dDevice->SetTextureStageState( 1 , D3DTSS_TEXCOORDINDEX , 0);
  //1号纹理使用0号纹理索引

  DWORD dwFactor = VectortoRGBA(&g_vLighter ,0.0f);
    g_pd3dDevice->SetRenderState( D3DRS_TEXTUREFACTOR, dwFactor ); /// 变换为RGB的向量登录为TextureFactor值

  g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );  /// 纹理的RGB和光源向量内积运算
  g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_DOTPRODUCT3 ); /// 运算中使用内积
  g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_TFACTOR );

  g_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLOROP,   D3DTOP_MULTIPLYADD ); /// 合成壁面贴图纹理和法线贴图后输出
  g_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_TEXTURE );
  g_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLORARG2, D3DTA_CURRENT );
  g_pd3dDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP,   D3DTOP_SELECTARG1 );
  g_pd3dDevice->SetTextureStageState( 1, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );

  DrawMesh(&g_matAni);
  g_pd3dDevice->EndScene();
 }
 g_pd3dDevice->Present(NULL ,NULL , NULL , NULL );
}

 

LRESULT WINAPI MsgProc(HWND hWnd , UINT msg, WPARAM wParam ,LPARAM lParam)
{
 switch(msg)
 {
 case WM_DESTROY:
  CleanUp();
  PostQuitMessage(0);
  return 0;
 }

 return DefWindowProc(hWnd ,msg,wParam,lParam);
}

 

 

 

INT WINAPI WinMain( HINSTANCE hInst , HINSTANCE ,LPSTR ,INT )
{
 WNDCLASSEX wc = { sizeof(WNDCLASSEX) , CS_CLASSDC , MsgProc , 0L ,0L,
 GetModuleHandle(NULL), NULL , NULL , NULL , NULL,
 L"BasicFrame", NULL};
 
 RegisterClassEx(&wc);
 HWND hWnd = CreateWindow( L"BasicFrame", L"LightMappint",WS_OVERLAPPEDWINDOW,
  100,100,500,500 ,GetDesktopWindow() ,NULL ,wc.hInstance,NULL);

 g_hWnd = hWnd ;

 

 MSG msg;
 ZeroMemory (&msg ,sizeof (msg));
 if( SUCCEEDED( InitD3D(hWnd ) ) )
  if(SUCCEEDED (InitGeometry()))
 {
   SetupCamera();
         ShowWindow(hWnd , SW_SHOWDEFAULT );
         UpdateWindow(hWnd);
     while(msg.message!=WM_QUIT)
   {
    if (PeekMessage (&msg,NULL,0U ,0U, PM_REMOVE))
    {
      TranslateMessage(&msg);
            DispatchMessage(&msg);
    }
    else
     Render();
   }
 UnregisterClass(L"D3D Tutorial",wc.hInstance);
 return 0;
 }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
NormalEstimation模块是PCL(Point Cloud Library)中用于点云法线估计的模块,它采用了最小二乘法(Least Squares)来计算点云中每个点的法线向量。 NormalEstimation模块的原理如下: 1. 首先,选择每个点的邻域。可以根据需要选择一个固定的半径或邻域大小,以确定每个点的邻域范围。 2. 对于每个点,获取其邻域内的所有点。这些点将用于进行法线估计。 3. 计算邻域内点的协方差矩阵。协方差矩阵描述了邻域内点的分布情况。通过将邻域内点的坐标减去该邻域的中心点坐标,可以使协方差矩阵的计算在局部坐标系中进行。 4. 进行协方差矩阵的特征值分解。特征值分解将给出协方差矩阵的特征值和对应的特征向量。 5. 选择最小特征值对应的特征向量作为该点的法线向量。最小特征值对应的特征向量表示了该点在局部曲面上最小曲率方向的法线方向。 重复以上步骤,可以计算点云中每个点的法线向量。 NormalEstimation模块还提供了一些参数,例如邻域搜索方法(如球形邻域或K近邻),协方差矩阵的计算方式(如是否考虑点的权重),以及特征值分解的方法等,可以根据具体需求进行设置和调整。 总结起来,NormalEstimation模块使用最小二乘法来计算点云中每个点的法线向量。它通过选择邻域、计算协方差矩阵、进行特征值分解,并选择最小特征值对应的特征向量来实现法线估计。这种方法可以帮助我们理解点云数据中曲面的局部几何特征。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值