青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

天行健 君子當自強而不息

創(chuàng)建3D圖形引擎(4)

 

本篇是創(chuàng)建3D圖形引擎(3)的續(xù)篇,3D圖形引擎的代碼以創(chuàng)建游戲內(nèi)核中編寫的代碼為基礎進行開發(fā)。

 

下載源碼和工程

 

將三維物體添加到世界中

盲目地繪制成千的物體而沒有執(zhí)行任何的剪切,是導致在圖形-渲染通道中時間延遲的一個主要原因。需要再次使用視錐以快速確定哪些物體位于視野中,為了確定哪些物體是可見的,可將每個三維物體包圍到一個可見的球體中,稱之為框界球體(bounding sphere)。

下圖演示了框界球體和視錐的運用,它展示了一個場景,其中有三個物體和一個視錐,每個網(wǎng)格模型都有一個可見的框界球體圍繞著它。當一個球體位于構成視錐的6個平面前時,它就被認為是可見的。 可以看出僅兩個位于視錐中的物體是可見的,而另一個物體完全位于視錐外,繪制時能完全跳過那個位于視錐之外的物體。為了實現(xiàn)這一點,必須計算每個物體的框界球體,然后檢測球體是否位于視錐之內(nèi)。

 

網(wǎng)格模型的碰撞

為了檢測一個多邊形是否堵塞了節(jié)點之間的路徑,可以在兩個節(jié)點發(fā)射一條想象中的射線,以檢測它們是否與一個平面相交。如下圖所示:

有一個功能函數(shù)負責執(zhí)行交集的測試,以確保射線與平面的相交點位于多邊形內(nèi),并給出那個相交點的確切坐標,同時顯示從射線的開始點到相交點的距離長度,它是一個非常有用的功能函數(shù)。

Determines if a ray intersects with a mesh.

HRESULT D3DXIntersect(
LPD3DXBASEMESH pMesh,
CONST D3DXVECTOR3 * pRayPos,
CONST D3DXVECTOR3 * pRayDir,
BOOL * pHit,
DWORD * pFaceIndex,
FLOAT * pU,
FLOAT * pV,
FLOAT * pDist,
LPD3DXBUFFER * ppAllHits,
DWORD * pCountOfHits
);

Parameters

pMesh
[in] Pointer to an ID3DXBaseMesh interface, representing the mesh to be tested.
pRayPos
[in] Pointer to a D3DXVECTOR3 structure, specifying the point where the ray begins.
pRayDir
[in] Pointer to a D3DXVECTOR3 structure, specifying the direction of the ray.
pHit
[out] Pointer to a BOOL. If the ray intersects a triangular face on the mesh, this value will be set to TRUE. Otherwise, this value is set to FALSE.
pFaceIndex
[out] Pointer to an index value of the face closest to the ray origin, if pHit is TRUE.
pU
[out] Pointer to a barycentric hit coordinate, U.
pV
[out] Pointer to a barycentric hit coordinate, V.
pDist
[out] Pointer to a ray intersection parameter distance.
ppAllHits
[out] Pointer to an ID3DXBuffer object, containing an array of D3DXINTERSECTINFO structures.
pCountOfHits
[out] Pointer to a DWORD that contains the number of entries in the ppAllHits array.

Return Values

If the function succeeds, the return value is D3D_OK. If the function fails, the return value can be: E_OUTOFMEMORY.

Remarks

The D3DXIntersect function provides a way to understand points in and around a triangle, independent of where the triangle is actually located. This function returns the resulting point by using the following equation: V1 + U(V2 - V1) + V(V3 - V1).

Any point in the plane V1V2V3 can be represented by the barycentric coordinate (U,V). The parameter U controls how much V2 gets weighted into the result, and the parameter V controls how much V3 gets weighted into the result. Lastly, the value of [1 - (U + V)] controls how much V1 gets weighted into the result.

Barycentric coordinates are a form of general coordinates. In this context, using barycentric coordinates represents a change in coordinate systems. What holds true for Cartesian coordinates holds true for barycentric coordinates.

Barycentric coordinates define a point inside a triangle in terms of the triangle's vertices. For a more in-depth description of barycentric coordinates, see Mathworld's Barycentric Coordinates Description.

我們編寫一個函數(shù)來檢測一條線段是否與一個網(wǎng)格中的三角形面相交。

//------------------------------------------------------------------------------
// Check if a polygon blocks path from start to end.
//------------------------------------------------------------------------------
BOOL is_ray_intersect_mesh(LPD3DXBASEMESH mesh,
                           
float x_start, float y_start, float z_start,
                           
float x_end, float y_end, float z_end,
                           
float* distance)
{
    
float x_diff, y_diff, z_diff;

    x_diff = x_end - x_start;
    y_diff = y_end - y_start;
    z_diff = z_end - z_start;

    D3DXVECTOR3 ray_pos(x_start, y_start, z_start);

    D3DXVECTOR3 ray_dir;
    D3DXVec3Normalize(&ray_dir, &D3DXVECTOR3(x_diff, y_diff, z_diff));

    BOOL is_hit;
    
float u, v, dist;
    DWORD face_index;

    
// determins if a ray intersects with a mesh
    D3DXIntersect(mesh, &ray_pos, &ray_dir, &is_hit, &face_index, &u, &v, &dist, NULL, NULL);

    
if(is_hit)
    {
        
float ray_length = (float) sqrt(x_diff * x_diff + y_diff * y_diff + z_diff * z_diff);

        
if(dist > ray_length)
            
return FALSE;
        
else
        {
            
if(distance != NULL)
                *distance = dist;
        }
    }

    
return TRUE;
}

在一個多邊形層次中運用碰撞檢測的另一個好處就是可以使物體隨著其下多邊形變化的高度而變化。換句話說,可以使物體永遠在多邊形上移動,這樣就能在一個三維建模軟件里繪制層次,而不用定義哪些區(qū)域是物體可以“行走”的,因為多邊形就是那些區(qū)域,這使得四叉樹和八叉樹網(wǎng)格模型的處理更加容易。

可通過下面這三個函數(shù)來執(zhí)行物體與多邊形的相交測試:

//------------------------------------------------------------------------------
// Get closest height above or below point.
//------------------------------------------------------------------------------
float get_closest_height(LPD3DXBASEMESH mesh, float x_pos, float y_pos, float z_pos)
{
    
float y_above, y_below;

    y_above = get_closest_height_above(mesh, x_pos, y_pos, z_pos);
    y_below = get_closest_height_below(mesh, x_pos, y_pos, z_pos);

    
if(fabs(y_above - y_pos) < fabs(y_below - y_pos))
        
return y_above;

    
return y_below;
}

//------------------------------------------------------------------------------
// Get closet height below point.
//------------------------------------------------------------------------------
float get_closest_height_below(LPD3DXBASEMESH mesh, float x_pos, float y_pos, float z_pos)
{
    BOOL is_hit;
    
float u, v, dist;
    DWORD face_index;

    D3DXVECTOR3 ray_pos(x_pos, y_pos, z_pos);
    D3DXVECTOR3 ray_dir(0.0f, -1.0f, 0.0f);

    D3DXIntersect(mesh, &ray_pos, &ray_dir, &is_hit, &face_index, &u, &v, &dist, NULL, NULL);

    
if(is_hit)
        
return y_pos - dist;

    
return y_pos;
}

//------------------------------------------------------------------------------
// Get closet height above point.
//------------------------------------------------------------------------------
float get_closest_height_above(LPD3DXBASEMESH mesh, float x_pos, float y_pos, float z_pos)
{
    BOOL is_hit;
    
float u, v, dist;
    DWORD face_index;

    D3DXVECTOR3 ray_pos(x_pos, y_pos, z_pos);
    D3DXVECTOR3 ray_dir(0.0f, 1.0f, 0.0f);

    D3DXIntersect(mesh, &ray_pos, &ray_dir, &is_hit, &face_index, &u, &v, &dist, NULL, NULL);

    
if(is_hit)
        
return y_pos + dist;

    
return y_pos;
}

為了方便,在NODE_TREE_MESH類中繼續(xù)封裝這些函數(shù):

//------------------------------------------------------------------------------
// Get closest height above or below point.
//------------------------------------------------------------------------------
float NODE_TREE_MESH::get_closest_height(float x_pos, float y_pos, float z_pos)
{
    
return ::get_closest_height(m_root_mesh->m_mesh, x_pos, y_pos, z_pos);
}

//------------------------------------------------------------------------------
// Get closest height below point.
//------------------------------------------------------------------------------
float NODE_TREE_MESH::get_closest_height_below(float x_pos, float y_pos, float z_pos)
{
    
return ::get_closest_height_below(m_root_mesh->m_mesh, x_pos, y_pos, z_pos);
}

//------------------------------------------------------------------------------
// Get closest height above point.
//------------------------------------------------------------------------------
float NODE_TREE_MESH::get_closest_height_above(float x_pos, float y_pos, float z_pos)
{
    
return ::get_closest_height_above(m_root_mesh->m_mesh, x_pos, y_pos, z_pos);
}

//------------------------------------------------------------------------------
// Check if a polygon blocks path from start to end.
//------------------------------------------------------------------------------
BOOL NODE_TREE_MESH::is_ray_intersect_mesh(float x_start, float y_start, float z_start,
                                     
float x_end, float y_end, float z_end,
                                     
float* distance)
{
    
return ::is_ray_intersect_mesh(m_root_mesh->m_mesh, 
                             x_start, y_start, z_start,
                             x_end, y_end, z_end,
                             distance);
}

 

當網(wǎng)格模型發(fā)生碰撞時

除了檢測物體網(wǎng)格模型與構造世界的網(wǎng)格模型之間的碰撞,還需要知道較小網(wǎng)格模型碰撞的情況。舉個例子,如果不希望角色穿透其他的角色,就需要結合物體和物體之間(object-to-object)的碰撞檢測。進行操作前需要了解一些事情,包括框界球體使用的知識。如下圖所示,其顯示了兩個怪物,它們都有長長的尾巴,那些尾巴影響了網(wǎng)格模型的框界球體的整體尺寸,為了包圍住整個網(wǎng)格模型(包括尾巴),球體將會很大。如果將這兩個怪物移動到下圖所示的位置,會看到這兩個框界球體相交,但怪物并沒有那么靠近。

盡管有許多辦法解決大型框界球體問題,但有一種快速執(zhí)行的方法。取代使用網(wǎng)格模型的框界球體,而是為每個網(wǎng)格模型計算自己的框界球體半徑,通過計算框界球體的半徑,可以快速調(diào)節(jié)它以覆蓋網(wǎng)格模型確實需要的空間。

我們編寫一個函數(shù)來檢測兩個框界球體是否相交:

//------------------------------------------------------------------------------
// Check if two spheres intersect.
//------------------------------------------------------------------------------
BOOL is_tow_sphere_intersect(float x_center_1, float y_center_1, float z_center_1,
                             
float radius1,
                             
float x_center_2, float y_center_2, float z_center_2,
                             
float radius2)
{
    
float x_diff, y_diff, z_diff, dist;
    
    
// calculate distance between two sphere center]
    
    x_diff = fabs(x_center_2 - x_center_1);
    y_diff = fabs(y_center_2 - y_center_1);
    z_diff = fabs(z_center_2 - z_center_1);

    dist = (
float) sqrt(x_diff * x_diff + y_diff * y_diff + z_diff * z_diff); 

    
// if two spheres intersect, retuen TRUE.
    if(dist <= radius1 + radius2)
        
return TRUE;

    
return FALSE;
}

 

天框的使用

天框(sky box)是一種圍繞觀察者進行紋理映射的三維立方體的圖形技術,渲染一個天框時,觀察點總是定于中心位置,以便用戶始終能夠看到方框內(nèi)部紋理映射的表面,這種技術能夠制造出一種世界圍繞用戶的效果,如下圖所示:

天框是非常容易是實現(xiàn),只需一個立方體網(wǎng)格模型(其表面朝向里面)即可,通過一個頂點緩沖區(qū)存儲立方體網(wǎng)格模型會非常不錯。至于紋理,可以使用多達6個的紋理,每個表面一個紋理。網(wǎng)格模型并不需要很大,僅20.0單元大小的立方體就行了。紋理大小應該為256 x 256或者更高,較小的紋理將出現(xiàn)拉伸而且不生動。

 

創(chuàng)建一個天框類

SKY_BOX負責控制天框的每個方面,從創(chuàng)建渲染盒子所使用的頂點緩沖區(qū),到渲染時所使用的紋理。

定義:

enum SKY_BOX_SIDES  { TOP = 0, BOTTOM, LEFT, RIGHT, FRONT, BACK };

//=====================================================================================
// This calss encapsulate how to make sky box.
//=====================================================================================
typedef class SKY_BOX
{
private:
    typedef 
struct SKY_BOX_VERTEX
    {
        
float x, y, z;
        
float u, v;
    } *SKY_BOX_VERTEX_PTR;

    
#define SKY_BOX_FVF (D3DFVF_XYZ | D3DFVF_TEX1)

private:
    GRAPHICS_PTR    m_graphics;         
// parent GRAPHICS object
    TEXTURE         m_textures[6];      // face texture (0 - 5)
    VERTEX_BUFFER   m_vertex_buffer;    // mesh vertex buffer
    WORLD_POSITION  m_pos;              // sky box position

public:
    SKY_BOX();
    ~SKY_BOX();

    BOOL create(GRAPHICS_PTR graphics);
    
void free();

    BOOL load_texture(
short side, pcstr filename, D3DCOLOR transparent = 0, D3DFORMAT format = D3DFMT_UNKNOWN);

    
void rotate(float x_rot, float y_rot, float z_rot);
    
void rotate_rel(float x_rot, float y_rot, float z_rot);

    BOOL render(CAMERA_PTR camera, BOOL alpha_blend = FALSE);
} *SKY_BOX_PTR;

實現(xiàn):

//----------------------------------------------------------------------------------
// Constructor, initialize member data.
//----------------------------------------------------------------------------------
SKY_BOX::SKY_BOX()
{
    m_graphics = NULL;
}

//----------------------------------------------------------------------------------
// Destructor, release allocated resource.
//----------------------------------------------------------------------------------
SKY_BOX::~SKY_BOX()
{
    free();
}

//----------------------------------------------------------------------------------
// Release allocated resource.
//----------------------------------------------------------------------------------
void SKY_BOX::free()
{
    m_graphics = NULL;

    
for(short i = 0; i < 6; i++)
        m_textures[i].free();

    m_vertex_buffer.free();
}

//----------------------------------------------------------------------------------
// Create a sky box class object.
//----------------------------------------------------------------------------------
BOOL SKY_BOX::create(GRAPHICS_PTR graphics)
{
    SKY_BOX_VERTEX verts[24] = {
        { -10.0f,  10.0f, -10.0f, 0.0f, 0.0f },  
// Top
        {  10.0f,  10.0f, -10.0f, 1.0f, 0.0f },
        { -10.0f,  10.0f,  10.0f, 0.0f, 1.0f },
        {  10.0f,  10.0f,  10.0f, 1.0f, 1.0f },

        { -10.0f, -10.0f,  10.0f, 0.0f, 0.0f },  
// Bottom
        {  10.0f, -10.0f,  10.0f, 1.0f, 0.0f },
        { -10.0f, -10.0f, -10.0f, 0.0f, 1.0f },
        {  10.0f, -10.0f, -10.0f, 1.0f, 1.0f },

        { -10.0f,  10.0f, -10.0f, 0.0f, 0.0f },  
// Left
        { -10.0f,  10.0f,  10.0f, 1.0f, 0.0f },
        { -10.0f, -10.0f, -10.0f, 0.0f, 1.0f },
        { -10.0f, -10.0f,  10.0f, 1.0f, 1.0f },

        {  10.0f,  10.0f,  10.0f, 0.0f, 0.0f },  
// Right
        {  10.0f,  10.0f, -10.0f, 1.0f, 0.0f },
        {  10.0f, -10.0f,  10.0f, 0.0f, 1.0f },
        {  10.0f, -10.0f, -10.0f, 1.0f, 1.0f },

        { -10.0f,  10.0f,  10.0f, 0.0f, 0.0f },  
// Front
        {  10.0f,  10.0f,  10.0f, 1.0f, 0.0f },
        { -10.0f, -10.0f,  10.0f, 0.0f, 1.0f },
        {  10.0f, -10.0f,  10.0f, 1.0f, 1.0f },
        
        {  10.0f,  10.0f, -10.0f, 0.0f, 0.0f },  
// Back
        { -10.0f,  10.0f, -10.0f, 1.0f, 0.0f },
        {  10.0f, -10.0f, -10.0f, 0.0f, 1.0f },
        { -10.0f, -10.0f, -10.0f, 1.0f, 1.0f },
    };

    free();     
// free a prior sky box

    // error checking
    if((m_graphics = graphics) == NULL)
        
return FALSE;

    
// create the vertex buffer (and copy over sky box vertices)
    if(m_vertex_buffer.create(m_graphics, 24, sizeof(SKY_BOX_VERTEX), SKY_BOX_FVF))
        m_vertex_buffer.
set(0, 24, (void*)verts);

    
// rotate the sky box into default orientation
    rotate(0.0f, 0.0f, 0.0f);

    
return TRUE;
}

//----------------------------------------------------------------------------------
// Set a specific side's texture map, allow for transparent and storage format changes.
//----------------------------------------------------------------------------------
BOOL SKY_BOX::load_texture(short side, pcstr filename, D3DCOLOR transparent, D3DFORMAT format)
{
    
// error checking
    if(m_graphics == NULL || side < 0 || side > 5)
        
return FALSE;

    m_textures[side].free();    
// free prior texture

    
return m_textures[side].load(m_graphics, filename, transparent, format);
}

//----------------------------------------------------------------------------------
// Rotate box to an absolute rotation.
//----------------------------------------------------------------------------------
void SKY_BOX::rotate(float x_rot, float y_rot, float z_rot)
{
    m_pos.rotate(x_rot, y_rot, z_rot);
}

//----------------------------------------------------------------------------------
// Rotate box to an relative rotation.
//----------------------------------------------------------------------------------
void SKY_BOX::rotate_rel(float x_rot, float y_rot, float z_rot)
{
    m_pos.rotate_rel(x_rot, y_rot, z_rot);
}

//----------------------------------------------------------------------------------
// Render the sky box (using optional alpha-blending) and using current view 
// transformation from Camera.
//----------------------------------------------------------------------------------
BOOL SKY_BOX::render(CAMERA_PTR camera, BOOL alpha_blend)
{
    
// error checking
    if(m_graphics == NULL || camera == NULL)
        
return FALSE;

    
// position sky box around viewer
    m_pos.move(camera->get_x_pos(), camera->get_y_pos(), camera->get_z_pos());
    m_graphics->set_world_position(&m_pos);

    
// enable alpha testing and alpha blending

    m_graphics->enable_alpha_blending(TRUE);

    
if(alpha_blend)
        m_graphics->enable_alpha_blending(TRUE, D3DBLEND_SRCCOLOR, D3DBLEND_DESTCOLOR);

    
// draw each layer
    for(short i = 0; i < 6; i++)
    {
        
if(m_textures[i].is_loaded())
        {
            m_graphics->set_texture(0, &m_textures[i]);
            m_vertex_buffer.render(i * 4, 2, D3DPT_TRIANGLESTRIP);
        }
    }

    
// disable alpha testing and alpha blending

    m_graphics->enable_alpha_blending(FALSE);

    
if(alpha_blend)
        m_graphics->enable_alpha_blending(FALSE);

    
return TRUE;
}

測試代碼:

/************************************************************************************
PURPOSE:
     node tree mesh test.
************************************************************************************/


#include "core_global.h"
#include "frustum.h"
#include "node_tree.h"
#include "sky_box.h"

class APP : public APPLICATION
{
public:
    APP()
    {
        _width  = 640;
        _height = 480;
        
        APPLICATION::_x_pos = (get_screen_width()  - _width) / 2;
        APPLICATION::_y_pos = (get_screen_height() - _height) / 4;

        _style = WS_BORDER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU;

        strcpy(_class_name, "node tree class");
        strcpy(_caption, "node tree demo");
    }

    BOOL init()
    {
        
// initialize graphics and set display mode
        _graphics.init();
        _graphics.set_mode(get_hwnd(), TRUE, TRUE);
        _graphics.set_perspective(D3DX_PI / 4, 1.3333f, 1.0f, 10000.0f);

        show_mouse(TRUE);
    
        
// enable lighting and setup light

        _graphics.enable_lighting(TRUE);
        _graphics.set_ambient_light(24, 24, 24);
        _graphics.enable_light(0, TRUE);
        
        _light.set_attenuation_0(0.4f);
        _light.set_range(1000.0f);

        
// initialize input and input device
        _input.init(get_hwnd(), get_inst());
        _keyboard.create(&_input, KEYBOARD);
        _mouse.create(&_input, MOUSE, TRUE);

        
// load the mesh and create a nodetree mesh from it

        
if(! _mesh.load(&_graphics, "..\\Data\\Level.x", "..\\Data\\"))
            
return FALSE;

        _node_tree_mesh.create(&_graphics, &_mesh, QUADTREE);

        
// position view at origin
        _x_pos = _y_pos = _z_pos = 0.0f;

        
// setup sky box
        _sky_box.create(&_graphics);

        
for(short i = 0; i < 6; i++)
            _sky_box.load_texture(i, "..\\data\\stars.bmp");

        
// initialize the sound system to play with
        _sound.init(get_hwnd());
        _sound_data.load_wav("..\\data\\cricket.wav");

        
for(short i = 0; i < 3; i++)
            _sound_channel[i].create(&_sound, &_sound_data);

        
return TRUE;
    }

    BOOL frame()
    {
        
static DWORD time_now = timeGetTime();

        
// play a random cricket sound
        for(short i = 0; i< 3; i++)
        {
            
if(!_sound_channel[i].is_playing() && rand()%256 < 16)
                _sound_channel[i].play(&_sound_data, 10);
        }

        
// calculate elapsed time (plus speed boost)
        ulong time_elapsed = timeGetTime() - time_now;
        time_now = timeGetTime();

        
// read keyboard and mouse data        
        _keyboard.read();
        _mouse.read();

        
// process input and update everything, ESC quits program.

        
if(_keyboard.get_key_state(KEY_ESC))
            
return FALSE;

        
float x_move, z_move;

        
// process movement
        x_move = z_move = 0.0f;

        
if(_keyboard.get_key_state(KEY_UP) || _keyboard.get_key_state(KEY_W))
        {
            x_move = (
float) sin(_camera.get_y_rotation()) * time_elapsed;
            z_move = (
float) cos(_camera.get_y_rotation()) * time_elapsed;
        }
        
        
if(_keyboard.get_key_state(KEY_DOWN) || _keyboard.get_key_state(KEY_S))
        {
            x_move = (
float) -sin(_camera.get_y_rotation()) * time_elapsed;
            z_move = (
float) -cos(_camera.get_y_rotation()) * time_elapsed;
        }

        
if(_keyboard.get_key_state(KEY_LEFT) || _keyboard.get_key_state(KEY_A))
        {
            x_move = (
float) sin(_camera.get_y_rotation() - 1.57f) * time_elapsed;
            z_move = (
float) cos(_camera.get_y_rotation() - 1.57f) * time_elapsed;
        }

        
if(_keyboard.get_key_state(KEY_RIGHT) || _keyboard.get_key_state(KEY_D))
        {
            x_move = (
float) sin(_camera.get_y_rotation() + 1.57f) * time_elapsed;
            z_move = (
float) cos(_camera.get_y_rotation() + 1.57f) * time_elapsed;
        }

        
// check for height changes (can step up to 64 units)
        float height = _node_tree_mesh.get_closest_height_below(_x_pos, _y_pos + _above_floor, _z_pos);

        
if(_y_pos > height)
        {
            
// dropping
            if((_y_pos -= (float)time_elapsed) < height)
                _y_pos = height;
            
else
                x_move = z_move = 0.0f;
        }
        
else
        {
            
// climbing
            _y_pos = height;
        }

        
float dist;

        
// check for movement collision - can not walk past anything blocking path.
        if(_node_tree_mesh.is_ray_intersect_mesh(_x_pos, _y_pos + _above_floor, _z_pos,
                                                 _x_pos + x_move, _y_pos + _above_floor, _z_pos + z_move,
                                                 &dist))
        {
            
// adjust coordinates to be exactly 2.5 units away from target

            
float diff = dist - 2.5f;

            D3DXVECTOR2 dir;
            D3DXVec2Normalize(&dir, &D3DXVECTOR2(x_move, z_move));

            dir *= diff;

            x_move = dir.x;
            z_move = dir.y;
        }

        
// update view coordinats
        _x_pos += x_move;
        _z_pos += z_move;

        
// position camera and rotate based on mouse position

        _camera.move(_x_pos, _y_pos + 50.0f, _z_pos);

        
// _mouse.get_y_delta():
        //      get mouse's relative x movement coordinate.
        //
        // _mouse.get_x_delta():
        //      get mouse's relative y movement coordinate.
        _camera.rotate_rel((float) _mouse.get_y_delta() / 200.0f, (float) _mouse.get_x_delta() / 200.0f, 0.0f);

        
// position
        _light.move(_x_pos, _y_pos + 60.0f, _z_pos);
        _graphics.set_light(0, &_light);

        FRUSTUM frustum;

        
// set camera and calculate frustum       
        _graphics.set_camera(&_camera);
        frustum.construct(&_graphics);
        
        
// render everything
        _graphics.clear_zbuffer(1.0f);               

        
// begin render now
        if(_graphics.begin_scene())
        {
            _graphics.enable_zbuffer(FALSE);
            _graphics.enable_lighting(FALSE);
            _sky_box.render(&_camera);

            _graphics.enable_zbuffer(TRUE);
            _graphics.enable_lighting(TRUE);
            _node_tree_mesh.render(&frustum);

            _graphics.end_scene();
        }

        _graphics.display();

        
return TRUE;
    }

    BOOL shutdown()
    {
        
return TRUE;
    }

private:  
    GRAPHICS        _graphics;
    CAMERA          _camera;
    LIGHT           _light;

    SOUND           _sound;
    SOUND_DATA      _sound_data;
    SOUND_CHANNEL   _sound_channel[3];

    SKY_BOX         _sky_box;

    INPUT           _input;
    INPUT_DEVICE    _keyboard;
    INPUT_DEVICE    _mouse;    

    MESH            _mesh;
    NODE_TREE_MESH  _node_tree_mesh;

    
float           _x_pos, _y_pos, _z_pos;
    
    
static const float _above_floor;
};

const float APP::_above_floor = 64.0f;

int WINAPI WinMain(HINSTANCE inst, HINSTANCE, LPSTR cmd_line, int cmd_show)
{
    APP app;

    
return app.run();
}

截圖:






posted on 2007-10-24 18:57 lovedday 閱讀(1534) 評論(1)  編輯 收藏 引用

評論

# re: 創(chuàng)建3D圖形引擎(4)[未登錄] 2009-04-16 22:41 cloud

你寫的文章都挺不錯的,至少我收獲不少,期待下一編。。。  回復  更多評論   


只有注冊用戶登錄后才能發(fā)表評論。
網(wǎng)站導航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


公告

導航

統(tǒng)計

常用鏈接

隨筆分類(178)

3D游戲編程相關鏈接

搜索

最新評論

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            欧美午夜美女看片| 米奇777在线欧美播放| 亚洲黄页一区| 久久久久久伊人| 久久精品一级爱片| 久久这里有精品15一区二区三区| 欧美主播一区二区三区美女 久久精品人| av成人免费在线观看| 99这里只有精品| 欧美亚洲日本国产| 免费成人小视频| 99在线视频精品| 亚洲欧美影音先锋| 久热精品视频在线免费观看| 欧美精品xxxxbbbb| 国产日韩欧美二区| 亚洲剧情一区二区| 久久精品夜色噜噜亚洲a∨| 亚洲国产高清在线观看视频| 亚洲欧美激情在线视频| 欧美国产国产综合| 国内欧美视频一区二区| 中文一区在线| 欧美aⅴ一区二区三区视频| 99视频+国产日韩欧美| 久久久夜夜夜| 国产欧美日韩一区| 一区二区三区偷拍| 另类酷文…触手系列精品集v1小说| 亚洲啪啪91| 狂野欧美激情性xxxx| 国产精品日韩精品| 日韩亚洲综合在线| 麻豆精品一区二区av白丝在线| 一本大道av伊人久久综合| 老司机一区二区三区| 国产亚洲精品久| 亚洲欧美日韩一区二区| 亚洲欧洲精品一区二区| 久久男女视频| 伊人久久亚洲影院| 久久精品亚洲精品| 亚洲一区二区在线播放| 欧美日韩一区二区三区在线视频 | 性娇小13――14欧美| 欧美精品不卡| 亚洲精选在线| 最新69国产成人精品视频免费| 午夜亚洲性色福利视频| 国产精品成人在线观看| 亚洲午夜精品国产| 一本大道久久精品懂色aⅴ| 欧美成人影音| 亚洲国产精品一区二区久| 久久久久www| 亚洲欧美日韩一区二区在线| 国产精品九九| 亚洲欧美美女| 亚洲欧美国内爽妇网| 国产精品毛片a∨一区二区三区| 一区二区三区精密机械公司| 亚洲精品乱码久久久久久按摩观| 欧美高清不卡在线| 一区二区三区福利| 一区二区三区不卡视频在线观看 | 在线观看一区二区精品视频| 久久久久久高潮国产精品视| 欧美一区二区视频观看视频| 国产亚洲精品高潮| 欧美gay视频激情| 欧美大片第1页| 99天天综合性| 一本色道久久综合一区| 国产精品视频自拍| 久久久www成人免费精品| 久久精品一本| 亚洲精品日韩精品| 一区二区三区欧美视频| 国产日韩亚洲欧美| 欧美成人精品福利| 欧美日韩在线观看一区二区三区| 亚洲欧美一区二区激情| 久久精品99国产精品| 亚洲精品1区| 夜夜嗨av一区二区三区免费区| 国产美女一区二区| 欧美国产日韩视频| 国产精品vip| 久久久久久久久久久一区| 免费久久99精品国产| 亚洲综合精品| 免费欧美网站| 久久精品国产亚洲a| 欧美高清免费| 久久久亚洲影院你懂的| 欧美日韩成人激情| 玖玖综合伊人| 国产精品久久久久毛片软件| 欧美freesex8一10精品| 国产欧美精品一区aⅴ影院| 亚洲国产精品一区| 国产亚洲一区精品| 一区二区免费看| 亚洲第一区在线观看| 亚洲视频欧美在线| 亚洲国产精选| 久久精品成人一区二区三区| 亚洲视频二区| 欧美不卡在线视频| 久久综合中文色婷婷| 欧美成人精品一区| 国产中文一区二区| 亚洲第一级黄色片| 国产在线精品二区| 中文一区二区| 在线一区视频| 免费观看30秒视频久久| 久久国产精品久久w女人spa| 欧美肉体xxxx裸体137大胆| 亚洲高清在线播放| 激情综合电影网| 欧美一区二区三区视频免费播放 | 欧美午夜精品久久久久久人妖 | 一本到12不卡视频在线dvd| 久久久久久久97| 久久精品国产77777蜜臀| 欧美视频一区在线观看| 最新国产の精品合集bt伙计| 91久久精品视频| 欧美成人精品在线观看| 欧美freesex8一10精品| 亚洲国产高清aⅴ视频| 久久亚洲国产精品日日av夜夜| 久久免费黄色| 亚洲第一页中文字幕| 久久久精品欧美丰满| 免费看精品久久片| 亚洲经典视频在线观看| 你懂的视频一区二区| 亚洲国产日韩美| 一区二区三区福利| 欧美午夜女人视频在线| 亚洲一区三区在线观看| 欧美在线观看视频在线| 国产一区二区三区四区在线观看 | 亚洲一区二区视频在线观看| 欧美日韩一区二区免费在线观看 | 亚洲小视频在线| 国产精品久久久| 欧美一区二区三区四区夜夜大片 | 欧美1区2区| 亚洲美女福利视频网站| 欧美特黄一级| 午夜日韩在线| 欧美福利电影网| 一区二区日韩伦理片| 国产精品视频精品| 久久久一二三| 亚洲美女一区| 久久国产免费| 亚洲人被黑人高潮完整版| 欧美日韩国产高清| 欧美亚洲三区| 久久久之久亚州精品露出| 亚洲欧美影音先锋| 国产在线观看精品一区二区三区| 久久躁日日躁aaaaxxxx| 91久久亚洲| 久久久国产精品亚洲一区 | 国产欧美日韩高清| 六月丁香综合| 亚洲一区二区三区精品视频| 久久久噜噜噜久噜久久| 日韩小视频在线观看专区| 国产精品爽爽ⅴa在线观看| 久久一区激情| 亚洲欧美日韩在线综合| 欧美激情视频网站| 欧美影院成年免费版| 亚洲三级免费电影| 国产日韩欧美电影在线观看| 欧美美女日韩| 久热国产精品| 欧美一区二区三区免费视频| 亚洲精品一区二区在线| 蜜臀a∨国产成人精品| 午夜老司机精品| 99视频精品全国免费| 在线观看一区二区视频| 国产亚洲二区| 国产精品日本一区二区| 欧美日韩在线三区| 欧美国产极速在线| 免费成人黄色片| 狼人天天伊人久久| 久久夜色精品国产亚洲aⅴ| 久久国产主播精品| 欧美一区二区三区在线观看| 亚洲午夜精品网| 一本色道精品久久一区二区三区|