OpenGL GLFW PMX模型 骨骼 学习笔记 m8w3

之前的文章中,实现了顶点,纹理和材质。接下来还剩骨骼,变形以及DisplayFrame。

PMX格式资料:https://www.cnblogs.com/ifwz/p/17544729.html

PMX载入方法参考(C++):GitHub - benikabocha/saba: OpenGL Viewer (OBJ PMD PMX)

优化控制逻辑

参考OpenGL实现的控制,是一种类似FPS的控制方式,鼠标控制视角,键盘控制移动。但这种在调试中其实不是很方便。这里参考Unity实现了一套控制系统,Unity的基本控制方式就三种,平移,缩放(或者说前进后退),改变视角方向。

平移:鼠标滚轮控制缩放(或者说前进后退);

缩放:按住鼠标中键后,在相机所在的垂直相机朝向的平面内移动;

视角:按住鼠标右键后,根据鼠标移动改变视角方向;

通过glfw的回调函数都可以实现,设置bool变量做标志位,分别在mouse_button_callback中通过是按住对应按键修改标志位,然后在mouse_callback(GLFWwindow* window, double xpos, double ypos)中根据标志位判断是否根据鼠标偏移量(上一帧和当前帧的位置差)调整摄像机,这里最好用deltatime固定一下摄像机速度。

平移(只改变cameraPos):

缩放(只改变cameraPos):

视角(只改变cameraFront,不改变cameraPos):

GUI和渲染窗口分离

多窗口创建独立ImGui。这块如果出现问题,大概率是窗口和GUI上下文没有切换到位/各个ImGui没有自己独立的IO或上下文环境;

#创建glfw窗口的部分省略

#每个glfw窗口的Imgui都需要创建自己的上下文环境和io
context = ImGui::CreateContext();
ImGui::SetCurrentContext(context);
ImGuiIO& io = ImGui::GetIO(); (void)io;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;
/************************************************************/
#然后在每一帧绘制时,需要设置好上下文环境(glfw窗口和imgui)
glfwMakeContextCurrent(window);
ImGui::SetCurrentContext(context);

在实现下拉框选择纹理过程中,由于纹理路径是utf16,需要先转成utf8来使用,用了以下方法。utf16ToUtf8是使用wstring_convert实现的,输入u16string,输出string:

for (const auto& str : texFileName){
    utf8Items.push_back(utf16ToUtf8(str));
    items.push_back(utf8Items.back().c_str());
}    

会出现问题,比如utf8Items[3] = "spa\\spa_MM2.png",但在item里变成了item[3] = 0x0000020a83e559b0 "葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺",指针失效了。调试了一下,发现是由于utf8Items在push back第5个元素的时候,给第4个元素也就是utf8Items[3]重新分配了地址导致其首地址发生变化(push back会动态分配内存),而items中又不会同步首地址,所以在item中指针就失效了。

但是这与push back动态分配内存的策略描述不一样,utf8Items[3]重新分配了地址但前面的3个元素的首地址又没有变化。而且不管执行多少次,即使每次分配的地址不一样,但结果都是第3个元素的首地址被修改。

解决方法:先把utf8Items的所有数据都处理好,再把首地址给到items即可。(resize提前分配空间给utf8Items也不行,items[3]还是有问题,可能和数据类型是string有关)

!!!【后续会回来再看看】!!!

纹理读取这一块,我是用的另一个glfw窗口读取的主glfw窗口的纹理,由于默认情况下glfw窗口都有自己的OpenGL上下文,且相互隔离。所以想在窗口2中用窗口1的纹理,需要在创建另一个窗口时指定共享OpenGL上下文的窗口,这样就可以在窗口2中读到主窗口的纹理了。

GLFWwindow* window1 = glfwCreateWindow(800, 600, "Window 1", NULL, NULL);
GLFWwindow* window2 = glfwCreateWindow(800, 600, "Window 2", NULL, window1);  // 共享 window1 的上下文

多窗口ImGui输入冲突这一块,具体表现为,创建了两个glfw窗口,同时都有对应独立的imgui,但是在运行时,在任何窗口上的操作都会作用与同一个窗口,而不是当前窗口。

具体原因:glfwPollEvents()处理的用户输入,都只在当前imgui上下文生效(而多glfw窗口是会在对应窗口生效的)。举个栗子,当前imgui上下文是窗口B的imgui,用户在窗口A位置(10,10)处点击了一下,又在窗口B(10,10)处点击了一下。对glfw窗口来说,会调用窗口A和窗口B的鼠标点击回调函数分别一次,而对imgui来说,在窗口B的imgui上会处理两次(10,10)处的点击。

处理方法:!!!在想办法了在想办法了!!!

纹理读取问题

我用OpenGL渲染的PMX模型,在眼睛这一块有问题。第一张是用OpenGl渲染出来的,眼睛上的贴图有问题,第二张是PxmEditor里面打开的正常显示应该有的样子。

这块是读取纹理图像的时候,没有区分通道组成,都统一用RGB处理。但有的是RGBA,需要根据nrChannels设置glTexImage2D的参数。

纹理数量: 9
载入纹理图像...
纹理0: ../Assets/Model/yangyangQ/textures/T_R2T1YangyangMd10011_Q_body_D.png
textures[i].nrChannels: 3
纹理1: ../Assets/Model/yangyangQ/spa/toon_skin0.png
textures[i].nrChannels: 4
纹理2: ../Assets/Model/yangyangQ/spa/toon_fog2.png
textures[i].nrChannels: 4
纹理3: ../Assets/Model/yangyangQ/spa/spa_MM2.png
textures[i].nrChannels: 4
纹理4: ../Assets/Model/yangyangQ/textures/R2T1YangyangMd10011_Q_hair_D.png
textures[i].nrChannels: 3
纹理5: ../Assets/Model/yangyangQ/textures/face.png
textures[i].nrChannels: 3
纹理6: ../Assets/Model/yangyangQ/spa/toon_no.png
textures[i].nrChannels: 4
纹理7: ../Assets/Model/yangyangQ/textures/eye.png
textures[i].nrChannels: 4
纹理8: ../Assets/Model/yangyangQ/textures/bqb.png
textures[i].nrChannels: 4
纹理图像载入完成.

目前效果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值