彩神vi官網-追求健康,你我一起成長
時間: 2025-12-01
1.123時時彩
2.123彩票聯盟閃電KAI彩
3.123賽車彩票官網
4.123彩票聯盟閃電KAI彩
5.彩虹多多官網
6.雙贏彩票
7.樂彩匯-welcome
8.123時時彩
9.www.49159cm查詢開獎號碼
10.賓果彩票大廳
11.啟航彩app下載
12.閃電123開彩網
13.香港六合彩
14.彩樂園
15.飛艇彩票app
16.123pc蛋蛋
17.455770祥彩網
18.彩匠彩票
19.閃電123開彩網
20.大發彩神vII
21.啟航彩app下載
22.盛世app下載
23.49159.cσm查詢澳彩開獎記錄
24.welcome大眾彩神
25.123閃電APP
26.123彩票所有版本
27.久發365
28.閃電體育app下載官網
29.閃電app官方下載安裝
30.123彩票閃電實時結果體彩網
31.永盈彩票app
32.123閃電彩票官方下載入口
33.閃電123開彩網
34.123彩票app下載
35.DIII彩票樂園
36.123賽車彩票官網
37.體彩排列5
38.壹號娛樂
39.彩匠彩票
40.123飛艇體彩開獎結果
41.2816cc萬彩網
42.123快3
43.閃電下載app官方版
44.123閃電KAI獎網
45.多彩聯盟信譽平臺
46.閃電app官方下載安裝
47.大滿貫app
48.大發彩神lV
49.彩票123下載app官方版
50.123賽車彩票官網
51.閃電123開彩網
52.閃電app官方下載安裝
53.123時時彩
54.彩8VIII
55.彩聯盟官方網站
56.123彩票app下載手機版
57.飛艇彩票app
58.123彩票所有版本
59.縱橫聯盟彩票
60.123閃電彩票app下載安裝
61.易彩堂
62.香港六合彩
63.123賽車開獎體彩官網
64.叮叮彩票
65.樂發III
66.叮叮彩票
67.全民樂Vll
68.非凡娛樂
69.快盈v3
70.123時時彩
71.金彩匯
72.樂盈welcome
73.彩票聯盟123平臺入口
74.123閃電彩票官方下載入口
75.彩票123下載app官方版
76.uu快3
77.e77.cow樂彩
78.2816cc萬彩網
79.DIII彩票樂園
80.彩虹多多官網
81.123閃電彩票app下載安裝
82.極速塞車開獎直播歷史記錄
83.123彩票所有版本
84.快樂8六合彩
85.9198匯彩網
86.開云電競
87.全民樂Vll
88.博眾快3
89.金彩匯
90.永盈彩票app
91.樂彩匯-welcome
92.快樂8六合彩
93.9198匯彩網
94.彩票123下載app官方版
95.DIII彩票樂園
96.多彩聯盟平臺
97.彩票123下載app官方版
98.彩神8iii
99.永盛彩
100.彩票123手機版安卓版下載
101.123閃電彩票官方下載入口
102.123飛艇結果體彩查詢網歷史
103.123彩票app下載
104.匯彩網
105.彩神8iii
106.極速快3app
107.123十一選五
108.盛世app下載
109.多彩聯盟平臺
110.雙贏彩票
111.彩虹多多官網
112.123賽車彩票官網
113.彩虹多多官網
114.455770祥彩網
115.聯盟彩票app下載
116.123閃電官方版下載
117.123閃電彩票官方下載入口
118.盛世app下載
119.彩票123下載app官方版
120.大發快盈500
121.大發快盈500
122.123閃電app官方入口
123.e77.cow樂彩
124.455770祥彩網
125.博大彩票app官方下載
126.123十一選五
127.永盛彩票ys005.cm
128.快樂8六合彩
129.北京k10賽車
130.123聯盟賽車彩票官方網站
131.123閃電飛艇
132.全民樂Vll
133.極速快3app
134.123飛艇體彩開獎結果
135.閃電123開彩網
136.永盈彩票app
137.大發彩神vII
138.彩票聯盟
139.彩神8iii
140.123閃電APP
141.123六合彩
142.123飛艇體彩開獎結果
143.123賽車開獎體彩官網
144.福彩3D
145.博大彩票app官方下載
146.永盈彩票app
147.123閃電KAI獎網
148.123PC蛋蛋
149.123閃電彩票app下載安裝
150.體彩排列5
151.123閃電彩票APP下載官網
152.123賽車彩票官網
153.彩票聯盟APP
154.全民樂Vll
155.樂發III
156.動物運動會彩
157.123賽車
158.123彩票app下載手機版
159.新澳門六合彩
160.welcome大眾彩神
161.彩聯盟官方網站
162.123彩票聯盟閃電KAI彩
163.彩聯盟官方網站
164.www.49159cm查詢開獎號碼
165.永盛彩票ys005.cm
166.123彩票聯盟閃電KAI彩
167.123聯盟賽車彩票官方網站
168.彩8VIII
169.雙贏彩票
170.彩聯盟官方網站
171.123閃電官方版下載
172.123六合彩
173.易彩堂
174.455770祥彩網
175.彩票聯盟
176.閃電下載app官方版
177.快樂8六合彩
178.全民彩
179.123賽車彩票官網
180.叮叮彩票
181.123十一選五
182.123彩票app下載
183.贏樂67
184.123閃電飛艇
185.彩8VIII
186.DIII彩票樂園
187.e77.cow樂彩
188.聯盟彩票app下載
189.123彩票聯盟閃電KAI彩
190.樂盈welcome
191.全民彩
192.123六合彩
193.永盈彩票app
194.匯彩網
195.易彩堂
196.123飛艇結果體彩查詢網歷史
197.福彩3D
198.123飛艇彩票app官網
199.123聯盟賽車彩票官方網站
200.8258cc彩票app下載
一個簡單圖形學項目的介紹
涼州10 小時前本文系用戶投稿,不代表機核網觀點項目簡介
這是單的地形一個由C++編寫的,基于OpenGL圖形庫等實現的渲染一個簡單地形渲染器。可以實現自定義地形類型,個簡通過修正不同地塊類型之間的單的地形硬邊角,實現不同地形之間的渲染平滑過渡,并且將其渲染出來。個簡渲染器展示
實現流程
一、引擎部分
1. 組件結構
簡單來說:
這個引擎的渲染框架實現依靠于C++- 借助Opengl等圖形庫得以渲染圖像
- 編寫游戲物體和組件來創作內容
- 游戲的進行依托于每個組件的Awake、Update等函數的個簡運行
2. 引擎運行
int main(void){ Application::set_data_path("../data/");//設置資源目錄 Application::InitOpengl();//初始化引擎? GameObject* go=new GameObject("LoginSceneGo"); go->AddComponent("Transform"); go->AddComponent("LoginScene"); Application::Run();//開始引擎主循環}通過添加LoginScene腳本作為組件,渲染添加到游戲物體上,來加載游戲場景游戲場景內存放著所有游戲物體,相當于Unity里的Scene,是引擎運行的基礎結構:- Scene組件執行Awake函數時,將需要的游戲物體創建出來
- Scene組件也會執行Update函數,負責移動相機,接收輸入等
3. 具體實現
Application類
負責引擎運行的底層驅動,包括:- 初始化OpenGL服務,設置數據下載地址,更新窗口大小
- 在初始化時調用所有組件的Awake函數,每幀調用所有物體的Update函數,來進行邏輯運算
- 每幀調用所有物體的Render函數來實現渲染
class Application {public: static const std::string& data_path(){return data_path_;} static void set_data_path(std::string data_path){data_path_=data_path;}? /// 初始化OpenGL static void InitOpengl();? static void Run();? static void UpdateScreenSize();? /// 每一幀內邏輯代碼。 static void Update();? /// 邏輯代碼執行后,應用到渲染。 static void Render();?private: static std::string data_path_;//資源目錄? static GLFWwindow* glfw_window_;?};GameObject類
GameObject是組件的載體,同時可以設定為其他物體的父物體或者子物體,就這么多class GameObject {public: GameObject(std::string name); ~GameObject();? std::string& name(){return name_;} void set_name(std::string name){name_=name;}? /// 添加組件 Component* AddComponent(std::string component_type_name); /// 添加父物體 GameObject* SetParent(GameObject* parent); /// 添加子物體 GameObject* AddChildObject(std::string child_type_name, GameObject* child); /// 獲取組件 Component* GetComponent(std::string component_type_name); /// 獲取所有同名組件 std::vector<Component*>& GetComponents(std::string component_type_name); /// 獲取子物體 GameObject* GetChildObject(std::string child_type_name); /// 遍歷自身所有Component void ForeachComponent(std::function<void(Component* component)> func);? /// 遍歷所有GameObject static void Foreach(std::function<void(GameObject* game_object)> func); unsigned char layer(){return layer_;} void set_layer(unsigned char layer){layer_=layer;}private: std::string name_; unsigned char layer_;//將物體分不同的層,用于相機分層、物理碰撞分層等。 GameObject* parent_; std::unordered_map<std::string,std::vector<Component*>> component_type_instance_map_; std::unordered_map<std::string,GameObject*> childrenObjects_instance_map;? static std::list<GameObject*> game_object_list_;//存儲所有的GameObject。};Component類
引擎的基礎,所有組件腳本都要繼承自Component,通過Awake和Update函數來發揮作用class Component {public: Component(bool active = true); virtual ~Component();? GameObject* game_object(){return game_object_;} void set_game_object(GameObject* game_object){game_object_=game_object;}? void set_isActive(bool active); virtual void Awake(); virtual void Update();protected: bool isActive;private: GameObject* game_object_;};二、渲染部分
1. MeshFilt=er&模型文件.mesh
mesh格式的文件存儲模型數據,主要包含:- 頂點:存儲單個頂點的位置、顏色、uv
- 頂點數組:存儲模型所有的頂點
- 頂點索引數組:根據頂點數組組成面的指導
- 頂點數組長度,頂點索引數組長度
struct Vertex{ glm::vec3 pos_; glm::vec4 color_; glm::vec2 uv_;};?//Mesh文件頭struct MeshFileHead{ char type_[4]; unsigned short vertex_num_;//頂點個數 unsigned short vertex_index_num_;//索引個數};?//Mesh數據struct Mesh{ unsigned short vertex_num_;//頂點個數 unsigned short vertex_index_num_;//頂點索引個數 Vertex* vertex_data_;//頂點數據 unsigned short* vertex_index_data_;//頂點索引數據};而MeshFilter類,繼承自Component組件類,負責從.mesh文件中讀取頂點數據讀取頂點數據使用C++的IO系統:- 創建Mesh結構體對象
- 先讀取頂點數和索引數,再依次讀取頂點數組和索引數組的內容,并存入Mesh
class MeshFilter:public Component{public: MeshFilter(bool active = true); ~MeshFilter();public: void LoadMesh(string mesh_file_path);//加載Mesh文件 Mesh* mesh(){return mesh_;};//Mesh對象private: Mesh* mesh_;//Mesh對象};2. Shader
頂點著色器
接收mvp矩陣和頂點位置,賦值給gl_Position接收頂點顏色和uv坐標并傳遞給片元著色器#version 330 core?uniform mat4 u_mvp;?layout(location = 0) in vec3 a_pos;layout(location = 1) in vec4 a_color;layout(location = 2) in vec2 a_uv;?out vec4 v_color;out vec2 v_uv;?void main(){ gl_Position = u_mvp * vec4(a_pos, 1.0); v_color = a_color; v_uv = a_uv;}?片元著色器
由于這次項目并未使用到貼圖,所以只需傳遞顏色,而無需處理uv#version 330 core?uniform sampler2D u_diffuse_texture;?in vec4 v_color;in vec2 v_uv;layout(location = 0) out vec4 o_fragColor;void main(){ o_fragColor = v_color;}3. Material類&材質文件.mat
.mat格式的文件保存著著色器程序、貼圖文件的保存地址,通過rapidxml來解析文件這次的渲染流程只通過OpenGL對頂點顏色數據的自動插值來渲染顏色,無需用到貼圖Material類的實例都保存了一個.mat文件,并且會將其解析獲得shader文件和材質文件,同樣這里只放上shader部分和使用過程//tile.mat?<material shader="shader/tile"> <texture name="None" image="None"/></material>
//Material.cpp?void Material::Parse(string material_path) { //解析xml rapidxml::file<> xml_file((Application::data_path()+material_path).c_str()); rapidxml::xml_document<> document; document.parse<0>(xml_file.data());? //根節點 rapidxml::xml_node<>* material_node=document.first_node("material"); if(material_node == nullptr){ return; }? rapidxml::xml_attribute<>* material_shader_attribute=material_node->first_attribute("shader"); if(material_shader_attribute == nullptr){ return; } shader_=Shader::Find(material_shader_attribute->value()); ...}4. 單個物體渲染&MeshRenderer
Render()方法,這是MeshRenderer的主體,也是渲染的主要流程,基本上分為這么幾步:- MeshRenderer會保存Material類的引用,使用其解析.mat文件的功能
- 之后獲取自身MeshFilter組件的.mesh文件,使用其導入頂點數據的功能
- 最后上傳這些數據,完成渲染
class MeshRenderer:public Component{public: MeshRenderer(bool active = true); ~MeshRenderer();? void SetMaterial(Material* material);//設置Material Material* material(){return material_;}? void Render();//渲染private: Material* material_;? unsigned int vertex_buffer_object_=0;//頂點緩沖區對象 unsigned int element_buffer_object_=0;//索引緩沖區對象 unsigned int vertex_array_object_=0;//頂點數組對象};5. 啟用渲染
在Appication類中,Render()函數被每幀調用,并且獲取所有物體的MeshRenderer組件,執行一次Render這里值得一提的是,可以把深度緩沖的清除也放在這個函數里邊,這樣每幀只被執行一次即可深度緩沖必須要打開,否則物體的渲染順序會影響前后遮擋關系//Application.cpp?void Application::Render(){ //每幀清除顏色和深度緩沖 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);? //遍歷所有相機,每個相機的View Projection,都用來做一次渲染。 Camera::Foreach([&](){ GameObject::Foreach([](GameObject* game_object){ auto component=game_object->GetComponent("MeshRenderer"); if (!component){ return; } auto mesh_renderer=dynamic_cast<MeshRenderer*>(component); if(!mesh_renderer){ return; } mesh_renderer->Render(); }); });}三、TileMap系統
這里引用B站的一位Up主的視頻視頻,我從此視頻中了解到的這個系統:[給種田游戲添加程序化生成] https://www.bilibili.com/video/BV1WaH9eTEPU/?spm_id_from=333.999.0.0&amp;vd_source=4a26dbc01fe9994125e4362834171eb21. 原理
用普通的TileMap來來創建地形時,我們會做這幾件事:- 將需要繪制的地形切割成瓦片
- 將瓦片貼到地圖上
- Tile邊角的模型
- 去掉一個邊角的磚塊模型
- 去掉兩個相對邊角的磚塊模型
- 四分之一大小的磚塊模型
2. 模型創建及導入
所有Tile的建模均在Blender中完成,并且通過腳本創建文件導出頂點數據這就是上文提到的四種模型3. 實現
TileMap類
這個類不是組件,而是只用來存儲導入的TileMap數據:- Map的長寬
- 所有Tile的Tile類型
- 所有Tile組件的引用
class TileMap {? public: TileMap(int width, int height); ~TileMap();? unsigned int GetMapHeight() const {return height_data;} unsigned int GetMapWidth() const {return width_data;} const vector<vector<unsigned short>>& GetMap_Data() const {return tileMap_data;} const vector<vector<Tile*>>& GetMap_Instance() const {return tileMap_instance;}? unordered_map<unsigned short,int> TileMap::GetTile_Data(pair<int,int> position); void SetMap_Data(const vector<vector<unsigned short>>& map); void SetMap_Instance(const vector<vector<Tile*>>& map);? private: vector<vector<unsigned short>> tileMap_data; vector<vector<Tile*>> tileMap_instance; unsigned int width_data; unsigned int height_data; unsigned int width_instance; unsigned int height_instance;?};TileCreater組件
- 加載地圖文件,并存儲在二維數組中
- 根據地圖文件,創建Tile對象,為它們添加Tile組件
- 開啟每個Tile的初始化,開啟渲染
class TileCrater: public Component {? public: TileCrater(){}; ~TileCrater(){};? void LoadTileMap(const std::string& filename); void CreateTiles(); void InitTiles() const;? private: TileMap* tileMap;?};Tile組件
- 創建子瓦片,添加渲染組件
- 獲得渲染類型,確定渲染方式
- 開啟子瓦片渲染
class Tile: public Component {?public: Tile(){}; ~Tile(){}; void SetMap(TileMap* map){tileMap = map;}; void TileCreate(float x, float z); void TileInitialize(pair<int,int> tilePos);?private: TileMap* tileMap; /// Tile在TileMap中的相對位置 pair<int,int> tile_orientation; /// 存儲Tile子塊的Tile類型 std::unordered_map<unsigned short,int> childTiles_data_map; /// 存儲子塊位置和引用的map std::unordered_map<unsigned short,GameObject*> childTiles_instance_map;? GameObject* SetChildTile(unsigned short childPos, GameObject* childTile); vector<pair<unsigned short,unsigned short>> GetTileRenderLine();};

