游戏人生
首页
(current)
GameDevTools
登陆
|
注册
个人中心
注销
游戏引擎 浅入浅出
Introduction
Introduction
前言
前言
1. 游戏引擎框架介绍
1. 游戏引擎框架介绍
1.1 Unity的组成
1.2 游戏引擎组成
2. Opengl开发环境搭建
2. Opengl开发环境搭建
2.1 Opengl到底是什么
2.2 搭建Opengl开发环境
2.3 使用VisualStudio开发
3. 绘制多边形
3. 绘制多边形
3.1 画个三角形
3.2 画个正方形
3.3 画个立方体
4. 着色器
4. 着色器
4.1 Unity Shader和OpenGL Shader
4.2 顶点着色器
4.3 片段着色器
5. 绘制贴图
5. 绘制贴图
5.1 颜色和贴图
5.2 贴图文件介绍
5.3 CPU与GPU的通信方式
5.4 使用stb_image解析图片
5.5 绘制带贴图的立方体盒子
5.6 压缩纹理
5.7 图片压缩工具
5.8 使用压缩纹理
5.9 DXT压缩纹理扩展
6. 索引与缓冲区对象
6. 索引与缓冲区对象
6.1 顶点索引
6.2 缓冲区对象
6.3 OpenGL Core Profile
6.4 顶点数组对象
7. 绘制Mesh和材质
7. 绘制Mesh和材质
7.1 导出Mesh文件
7.2 使用Mesh文件
7.3 Shader文件创建与使用
7.4 创建材质
7.5 使用材质
7.6 MeshRenderer
8. 绘制静态模型
8. 绘制静态模型
8.1 Blender安装与配置
8.2 Blender制作模型
8.3 Blender Python设置开发环境
8.4 Blender Python创建物体
8.5 Blender Python导出顶点数据
8.6 加载导出的Mesh
9. 基于组件开发
9. 基于组件开发
9.1 基于RTTR实现反射
9.2 实现GameObject-Component
10. 相机
10. 相机
10.1 最简单的相机
10.2 多相机渲染
10.3 相机排序
10.4 CullingMask
11. 控制系统
11. 控制系统
11.1 键盘控制
11.2 鼠标控制
12. 拆分引擎和项目
12. 拆分引擎和项目
13. 绘制文字
13. 绘制文字
13.1 TrueType简介
13.2 绘制单个字符
13.3 绘制多个文字
13.4 彩色字
14. GUI
14. GUI
14.1 正交相机
14.2 UIImage
14.3 UIMask
14.4 UIText
14.5 UIButton
15. 播放音效
15. 播放音效
15.1 播放2D音效
15.2 播放3D音效
15.3 使用FMOD Studio音频引擎
16. Profiler
16. Profiler
16.1 初识easy_profiler
16.2 集成easy_profiler
17. 嵌入Lua
17. 嵌入Lua
17.1 Sol2与C++交互
17.2 更加友好的Lua框架设计
17.3 引擎集成sol2
17.4 调试Lua
18. 骨骼动画
18. 骨骼动画
18.1 Blender制作骨骼动画
18.2 Blender导出骨骼动画
18.3 解析骨骼动画
18.4 矩阵的主序
19. 骨骼蒙皮动画
19. 骨骼蒙皮动画
19.1 骨骼蒙皮动画实现
19.2 骨骼权重
19.3 Blender蒙皮刷权重
19.4 Blender导出蒙皮权重
19.5 加载权重文件
20. 解析FBX文件
20. 解析FBX文件
20.1 导出Mesh
20.2 导出骨骼动画
20.3 导出权重
20.4 渲染骨骼蒙皮动画
21. 多线程渲染
21. 多线程渲染
21.1 GLFW多线程渲染
21.2 基于任务队列的多线程渲染
21.3 完全异步的多线程模型
21.4 引擎支持多线程渲染
22. Physx物理引擎
22. Physx物理引擎
22.1 Physx实例-小球掉落
22.2 物理材质
22.3 碰撞检测
22.4 连续碰撞检测
22.5 场景查询
22.6 引擎集成Physx
23. 经典光照
23. 经典光照
23.1 环境光
23.2 漫反射光照模型
23.3 镜面高光光照模型
23.4 高光贴图
23.5 Shader结构体
23.6 Uniform Buffer Object
23.7 方向光
23.8 点光源
23.9 多光源
24. 引擎编辑器的实现
24. 引擎编辑器的实现
24.1 分析Godot引擎编辑器
24.2 FBO RenderTexture GameTurbo DLSS
24.3 ImGui介绍与使用
24.4 分离引擎核心层和应用层
24.5 使用ImGui实现引擎编辑器
24.6 Hierarchy与Inspector面板
24.7 Geometry Buffer
25. Shadow Mapping
25. Shadow Mapping
25.1 深度图
25.2 简单阴影
88. VSCode扩展开发与定制
88. VSCode扩展开发与定制
88.1 第一个VSCode扩展程序
88.2 从源码编译VSCode
88.3 打包VSCode内置扩展
88.4 打包LuaHelper到Code-OSS
89. Doxygen生成API文档
89. Doxygen生成API文档
90. GPU分析工具
90. GPU分析工具
90.1 RenderDoc分析不显示bug
98. SubstancePainter插件开发
98. SubstancePainter插件开发
98.1 SP插件开发环境
98.2 开发SP功能性插件
98.3 开发SP渲染插件
99. Toolbag插件开发
99. Toolbag插件开发
99.1 插件开发环境
99.2 API介绍
99.3 命令行调用Toolbag
99.4 更多实现
99.5 代码参考
附录1. Wwise音频引擎
附录1. Wwise音频引擎
1.1 Wwise名词概念
1.2 Wwise制作音效导出SoundBank
1.3 集成Wwise
1.4 封装Wwise播放3D音效
1.5 Wwise性能分析器介绍
1.6 猎人开发后记
代码资源下载
点我下载
Github
点赞、收藏、关注
目录
<< 17. 嵌入Lua
17.2 更加友好的Lua框架设计 >>
## 17.1 Sol2与C++交互 ```text 「游戏引擎 浅入浅出」是一本开源电子书,PDF/随书代码/资源下载: https://github.com/ThisisGame/cpp-game-engine-book ``` ```bash CLion项目文件位于 samples/integrate_lua/integrate_lua/lua_call_cpp_sol2_component ``` `sol2`是一个Lua绑定库,用于将C++的类、函数、数据映射到Lua中,这样就可以在Lua中创建C++实例、访问C++实例、调用C++函数。 也对Lua数据进行封装提供一系列接口给C++,在C++中访问Lua数据也变得很方便。 ```bash Github:https://github.com/ThePhD/sol2 文档:https://sol2.readthedocs.io/en/latest/ ``` `sol2`作为一个全能的绑定库,你想要的它都有支持。 本小节通过对`sol2`提供的一系列特性,来学习介绍`sol2`与C++交互逻辑。 ### 1.项目介绍 项目将之前章节的`GameObject`-`Component`架构提取出来,用作测试,并创建了`Animator`、`Camera`两个组件。 另外实现了Lua Component逻辑,并创建了`LoginScene` 这个Lua组件。 这一小节的项目,其实就是引擎的基础架构,在这个基础上,集成`sol2`,实现Lua Component。  ### 2.特性介绍 介绍对类、函数、数据的绑定。 #### 2.1 绑定类 下面是绑定`GameObject`的代码: ```c++ //绑定 GameObject { sol_state.new_usertype<GameObject>("GameObject",sol::call_constructor,sol::constructors<GameObject()>(), "AddComponent", &GameObject::AddComponentFromLua, "GetComponent",&GameObject::GetComponentFromLua, sol::meta_function::equal_to,&GameObject::operator== ); } ``` 上述代码执行后,就可以在lua中编写下面的代码: ```lua ---创建GameObject实例 local game_object=GameObject() --调用GameObject函数 local component=game_object:AddComponent("Camera") ``` `sol2`提供两种构造函数方式,直接带() ,或者使用`.new()` 1. 默认就是`.new()` ```c++ sol_state.new_usertype<Player>("Player",sol::constructors<Player(),Player(int)>()); ``` 这样注册后,在lua中就可以调用`.new()`实例化cpp对象。 ```lua local player=Player.new() ``` 为了和实例化cpp对象代码保持一致,实例化lua对象也通过.new() 函数来做。 ```lua setmetatable(LoginScene,{["new"]=function(table,param) local instance=setmetatable({},{__index=table}) return instance end}) ``` 2. 主动指定构造函数为sol::call_constructor,使用__call metafunction。 ```c++ sol_state.new_usertype<Player>("Player",sol::call_constructor,sol::constructors<Player(),Player(int)>()) ``` 这样注册后,在lua中就可以直接用`()`实例化cpp对象。 ```lua local player=Player() ``` 为了和实例化cpp对象代码保持一致,实例化lua对象通过`__call`函数来做。 ```lua setmetatable(LoginScene,{["__call"]=function(table,param) local instance=setmetatable({},{__index=table}) return instance end}) ``` #### 2.2 绑定基类与子类 对于有继承关系的类,则需要先绑定基类,然后再绑定子类。 参考`Camera`的注册代码: ```c++ //绑定 Component { sol_state.new_usertype<Component>("Component",sol::call_constructor,sol::constructors<Component()>(), "Awake",&Component::Awake, "Update",&Component::Update, "game_object",&Component::game_object, "set_game_object",&Component::set_game_object ); } //绑定 Camera { sol_state.new_usertype<Camera>("Camera",sol::call_constructor,sol::constructors<Camera()>(), sol::base_classes,sol::bases<Component>(), "position",&Camera::position, "set_position",&Camera::set_position ); } ``` 子类中是不用绑定基类函数的。 #### 2.3 绑定操作符重载 如果需要大量的操作符重载,那可以参考`glm::vec3`的绑定过程,代码如下: ```c++ auto glm_ns_table = sol_state["glm"].get_or_create<sol::table>(); glm_ns_table.new_usertype<glm::vec3>("vec3",sol::call_constructor,sol::constructors<glm::vec3(const float&, const float&, const float&)>(), "x", &glm::vec3::x, "y", &glm::vec3::y, "z", &glm::vec3::z, "r", &glm::vec3::r, "g", &glm::vec3::g, "b", &glm::vec3::b, sol::meta_function::to_string,[] (const glm::vec3* vec) -> std::string {return glm::to_string(*vec);}, sol::meta_function::addition,[] (const glm::vec3* vec_a,const glm::vec3* vec_b) {return (*vec_a)+(*vec_b);}, sol::meta_function::subtraction,[] (const glm::vec3* vec_a,const glm::vec3* vec_b) {return (*vec_a)-(*vec_b);}, sol::meta_function::multiplication,[] (const glm::vec3* vec,const float a) {return (*vec)*a;}, sol::meta_function::division,[] (const glm::vec3* vec,const float a) {return (*vec)/a;}, sol::meta_function::unary_minus,[] (const glm::vec3* vec) {return (*vec)*-1;}, sol::meta_function::equal_to,[] (const glm::vec3* vec_a,const glm::vec3* vec_b) {return (*vec_a)==(*vec_b);} ); ``` 上述代码中,以`sol::meta_function::`为前缀的,就是Lua提供的操作符重载元方法,只要对其赋值即可实现操作符重载。 上述代码执行后,就可以在lua中编写下面的代码: ```lua print("glm.vec3(4,5,6)+glm.vec3(4,5,6): " .. tostring(glm.vec3(4,5,6)+glm.vec3(4,5,6))) print("glm.vec3(4,5,6)-glm.vec3(4,5,6): " .. tostring(glm.vec3(4,5,6)-glm.vec3(4,5,6))) print("glm.vec3(4,5,6)*3: " .. tostring(glm.vec3(4,5,6)*3)) print("glm.vec3(4,5,6)/3: " .. tostring(glm.vec3(4,5,6)/3)) ``` #### 2.4 绑定普通函数 简单的直接绑定,例如: ```c++ GameObject* game_object_; void CompareGameObject(GameObject* a,GameObject* b){ std::cout<<"CompareGameObject a==b: "<<(a==b)<<std::endl; } ``` 对应的绑定代码如下:<a id="antiCollectorAdTxt" href="https://github.com/ThisisGame/cpp-game-engine-book">「游戏引擎 浅入浅出」是一本开源电子书,PDF/随书代码/资源下载: https://github.com/ThisisGame/cpp-game-engine-book</a> ``` //绑定普通函数 { sol_state.set_function("CompareGameObject", &CompareGameObject); } ``` 上述代码执行后,就可以在lua中编写下面的代码: ```lua print("----------- simple function ------------") local go=GameObject() CompareGameObject(go,go) ``` 对付复杂函数的绑定,需要函数重载的,可以参考对 glm 提供的API的绑定。 ```c++ auto glm_ns_table = sol_state["glm"].get_or_create<sol::table>(); glm_ns_table.set_function("rotate",sol::overload([] (const glm::mat4* m,const float f,const glm::vec3* v) {return glm::rotate(*m,f,*v);})); glm_ns_table.set_function("radians",sol::overload([] (const float f) {return glm::radians(f);})); glm_ns_table.set_function("to_string",sol::overload( [] (const glm::mat4* m) {return glm::to_string((*m));}, [] (const glm::vec3* v) {return glm::to_string((*v));} )); ``` #### 2.5 绑定常量 绑定常量直接设置到lua即可,下面代码用table模拟了NameSpace。 ```c++ const int const_value=12; auto test_ns_table = sol_state["Test"].get_or_create<sol::table>(); test_ns_table.set("const_value",const_value); ``` #### 2.6 绑定枚举 有以下枚举: ```c++ typedef enum KeyAction{ UP=0, DOWN=1, REPEAT=2 }KeyAction; ``` 下面函数返回了枚举中的一项: ```c++ KeyAction GetKeyActionUp(){ return KeyAction::UP; } ``` 如果想在lua中调用`GetKeyActionUp`,那么需要注册这个函数,以及返回的枚举。 下面代码注册枚举类型到Lua: ```c++ sol_state.new_enum<KeyAction,true>("KeyAction",{ {"UP",KeyAction::UP}, {"DOWN",KeyAction::DOWN} }); ``` 然后注册函数: ```c++ sol_state.set_function("GetKeyActionUp", &GetKeyActionUp); ``` 上述代码执行后,就可以在lua中编写下面的代码: ```lua print(GetKeyActionUp()) ``` 上述代码执行后,就可以在lua中编写下面的代码: ```lua print(GetKeyActionUp()) print(KeyAction.UP) print(GetKeyActionUp()==KeyAction.UP) ``` #### 2.7 C++调用Lua全局函数 以调用`main.lua`中的`main()`为例: ```c++ //调用lua main() sol::protected_function main_function=sol_state["main"]; result=main_function(); if(result.valid()== false){ sol::error err = result; std::cerr << "----- RUN LUA ERROR ----" << std::endl; std::cerr << err.what() << std::endl; std::cerr << "------------------------" << std::endl; } ``` #### 2.8 C++调用Lua类成员函数 以Lua组件`LoginScene`为例: ```lua --file:example/login_scene.lua line:1 LoginScene={ game_object_ } function LoginScene:game_object() return self.game_object_ end function LoginScene:set_game_object(game_object) self.game_object_=game_object end function LoginScene:Awake() print("LoginScene Awake") end function LoginScene:Update() print("LoginScene Update") end setmetatable(LoginScene,{["__call"]=function(table,param) local instance=setmetatable({},{__index=table}) return instance end}) ``` 在`GameObject::AddComponentFromLua`根据传入的组件名,创建组件实例并添加,然后调用组件成员函数。 ```c++ //file:source/game_object.h line:80 /// 根据传入的组件名,创建组件实例 /// \param component_type_name /// \return sol::table AddComponentFromLua(std::string component_type_name) { sol::protected_function component_type_construct_function=sol_state[component_type_name];//对c++的class注册为table,并实现了__call,所以可以直接带括号。 auto result=component_type_construct_function(); if(result.valid()== false){ sol::error err = result; std::cerr << "----- RUN LUA ERROR ----" << std::endl; std::cerr <<"AddComponentFromLua call type construct error,type:"<<component_type_name<< std::endl; std::cerr << err.what() << std::endl; std::cerr << "------------------------" << std::endl; } sol::table new_table=result; result=new_table["set_game_object"](new_table,this); if(result.valid()== false){ sol::error err = result; std::cerr << "----- RUN LUA ERROR ----" << std::endl; std::cerr <<"AddComponentFromLua call set_game_object error,type:"<<component_type_name<< std::endl; std::cerr << err.what() << std::endl; std::cerr << "------------------------" << std::endl; } ...... return new_table; } ``` `sol_state[component_type_name]`以组件名获取到全局Table后,直接以括号调用就可以创建实例对象`new_table`。 然后以`new_table["set_game_object"]`就可以获取到成员函数`set_game_object`的引用。 然后直接调用函数即可。 记得要传入`self`,即要传入`new_table`。
<< 17. 嵌入Lua
17.2 更加友好的Lua框架设计 >>
12
代码资源下载
点我下载
Github
点赞、收藏、关注
目录
Introduction
Introduction
前言
前言
1. 游戏引擎框架介绍
1. 游戏引擎框架介绍
1.1 Unity的组成
1.2 游戏引擎组成
2. Opengl开发环境搭建
2. Opengl开发环境搭建
2.1 Opengl到底是什么
2.2 搭建Opengl开发环境
2.3 使用VisualStudio开发
3. 绘制多边形
3. 绘制多边形
3.1 画个三角形
3.2 画个正方形
3.3 画个立方体
4. 着色器
4. 着色器
4.1 Unity Shader和OpenGL Shader
4.2 顶点着色器
4.3 片段着色器
5. 绘制贴图
5. 绘制贴图
5.1 颜色和贴图
5.2 贴图文件介绍
5.3 CPU与GPU的通信方式
5.4 使用stb_image解析图片
5.5 绘制带贴图的立方体盒子
5.6 压缩纹理
5.7 图片压缩工具
5.8 使用压缩纹理
5.9 DXT压缩纹理扩展
6. 索引与缓冲区对象
6. 索引与缓冲区对象
6.1 顶点索引
6.2 缓冲区对象
6.3 OpenGL Core Profile
6.4 顶点数组对象
7. 绘制Mesh和材质
7. 绘制Mesh和材质
7.1 导出Mesh文件
7.2 使用Mesh文件
7.3 Shader文件创建与使用
7.4 创建材质
7.5 使用材质
7.6 MeshRenderer
8. 绘制静态模型
8. 绘制静态模型
8.1 Blender安装与配置
8.2 Blender制作模型
8.3 Blender Python设置开发环境
8.4 Blender Python创建物体
8.5 Blender Python导出顶点数据
8.6 加载导出的Mesh
9. 基于组件开发
9. 基于组件开发
9.1 基于RTTR实现反射
9.2 实现GameObject-Component
10. 相机
10. 相机
10.1 最简单的相机
10.2 多相机渲染
10.3 相机排序
10.4 CullingMask
11. 控制系统
11. 控制系统
11.1 键盘控制
11.2 鼠标控制
12. 拆分引擎和项目
12. 拆分引擎和项目
13. 绘制文字
13. 绘制文字
13.1 TrueType简介
13.2 绘制单个字符
13.3 绘制多个文字
13.4 彩色字
14. GUI
14. GUI
14.1 正交相机
14.2 UIImage
14.3 UIMask
14.4 UIText
14.5 UIButton
15. 播放音效
15. 播放音效
15.1 播放2D音效
15.2 播放3D音效
15.3 使用FMOD Studio音频引擎
16. Profiler
16. Profiler
16.1 初识easy_profiler
16.2 集成easy_profiler
17. 嵌入Lua
17. 嵌入Lua
17.1 Sol2与C++交互
17.2 更加友好的Lua框架设计
17.3 引擎集成sol2
17.4 调试Lua
18. 骨骼动画
18. 骨骼动画
18.1 Blender制作骨骼动画
18.2 Blender导出骨骼动画
18.3 解析骨骼动画
18.4 矩阵的主序
19. 骨骼蒙皮动画
19. 骨骼蒙皮动画
19.1 骨骼蒙皮动画实现
19.2 骨骼权重
19.3 Blender蒙皮刷权重
19.4 Blender导出蒙皮权重
19.5 加载权重文件
20. 解析FBX文件
20. 解析FBX文件
20.1 导出Mesh
20.2 导出骨骼动画
20.3 导出权重
20.4 渲染骨骼蒙皮动画
21. 多线程渲染
21. 多线程渲染
21.1 GLFW多线程渲染
21.2 基于任务队列的多线程渲染
21.3 完全异步的多线程模型
21.4 引擎支持多线程渲染
22. Physx物理引擎
22. Physx物理引擎
22.1 Physx实例-小球掉落
22.2 物理材质
22.3 碰撞检测
22.4 连续碰撞检测
22.5 场景查询
22.6 引擎集成Physx
23. 经典光照
23. 经典光照
23.1 环境光
23.2 漫反射光照模型
23.3 镜面高光光照模型
23.4 高光贴图
23.5 Shader结构体
23.6 Uniform Buffer Object
23.7 方向光
23.8 点光源
23.9 多光源
24. 引擎编辑器的实现
24. 引擎编辑器的实现
24.1 分析Godot引擎编辑器
24.2 FBO RenderTexture GameTurbo DLSS
24.3 ImGui介绍与使用
24.4 分离引擎核心层和应用层
24.5 使用ImGui实现引擎编辑器
24.6 Hierarchy与Inspector面板
24.7 Geometry Buffer
25. Shadow Mapping
25. Shadow Mapping
25.1 深度图
25.2 简单阴影
88. VSCode扩展开发与定制
88. VSCode扩展开发与定制
88.1 第一个VSCode扩展程序
88.2 从源码编译VSCode
88.3 打包VSCode内置扩展
88.4 打包LuaHelper到Code-OSS
89. Doxygen生成API文档
89. Doxygen生成API文档
90. GPU分析工具
90. GPU分析工具
90.1 RenderDoc分析不显示bug
98. SubstancePainter插件开发
98. SubstancePainter插件开发
98.1 SP插件开发环境
98.2 开发SP功能性插件
98.3 开发SP渲染插件
99. Toolbag插件开发
99. Toolbag插件开发
99.1 插件开发环境
99.2 API介绍
99.3 命令行调用Toolbag
99.4 更多实现
99.5 代码参考
附录1. Wwise音频引擎
附录1. Wwise音频引擎
1.1 Wwise名词概念
1.2 Wwise制作音效导出SoundBank
1.3 集成Wwise
1.4 封装Wwise播放3D音效
1.5 Wwise性能分析器介绍
1.6 猎人开发后记