主要是觉得写顶点坐标的这个方法有点妙,记录一下,看能不能摸索出更好玩的用法来
画一个立方体
先创建8个顶点的数据,再使用EBO实现画12个三角形。实践中发现GL_QUADS
已不可用。
创建8个定点的数据:
float vertex[24] ={0};
int fac[] = {1,-1};
float l = 0.5;
for(int i = 0 ; i < 8; i++){
vertex[i * 3] = l * fac[(i / 2)%2]; // +x: 0 1 4 5 ; -x: 2 3 6 7
vertex[i * 3 + 1] = l * fac[i%2]; //+y:0 2 4 6 -y: 1 3 5 7
vertex[i * 3 + 2] = l * fac[i / 4]; // +z:0 1 2 3 -z: 4 5 6 7
}
创建索引数据,在注释中已表明属于哪一个面。实践过程中发现索引值的顺序会影响创建的图案:
unsigned int indices[] = {
0,1,2,3,1,2, // front
4,5,6,7,5,6, // back
0,1,4,1,4,5, // right
2,3,6,7,3,6, // left
0,2,6,4,0,6,//top
1,3,7, 1,5,7 // bottom
};
坐标序号对应的空间位置如图:
调用自定义函数newObjectEBO
:
int pointCount = 8;
int indexCount = 36;
newObjectEBO(&VAO1, &VBO1, &EBO1, indexCount, indices, pointCount, vertex);
为了区分不同的面,修改fragment shader如下:
#version 330 core
out vec4 FragColor;
in vec3 oPos;
uniform vec4 fill;
void main()
{
FragColor = vec4(oPos.x,oPos.y,fill.z, 0.5);
}
渲染时设置相应的VAO并调用glDrawElements
,需要渲染的点数为36:
glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, 0);
效果:
自动的平移、旋转、变换
在GUI上设置是否自动变换:
ImGui::Checkbox("AutoPlay", &autoplay); ImGui::SameLine();
ImGui::Checkbox("autoscale", &autoscale); ImGui::SameLine();
ImGui::NewLine();
ImGui::Checkbox("autotrans", &autotrans); ImGui::SameLine();
ImGui::Checkbox("autorotate", &autorotate); ImGui::SameLine();
ImGui::NewLine();
根据用户选项对transform矩阵进行相应的赋值。
对于来回的平移和变换,用关于时间变量t
的sin
实现。
对于绕y=z轴的旋转,将rotate
函数的第三个变量(轴的normal vector)设置为(0,1,1)
即可。
if (autoplay) {
float t = (float)glfwGetTime() * 100;
if (autorotate) transform = glm::rotate(transform, glm::radians(t), glm::vec3(0, 1, 1));
if (autotrans) transform = glm::translate(transform, glm::vec3(sin(t*0.01), 0, 0));
float l = sin(t*0.05) + 0.2;
if (autoscale) transform = glm::scale(transform, glm::vec3(l, l, l));
}
效果见GIF。
自定义变换
可输入的参数:
// transformation
ImGui::SliderFloat("translateX"W, &transx, -1.f, 1.0f);
ImGui::SliderFloat("translateY", &transy, -1.f, 1.0f);
ImGui::SliderFloat("translateZ", &transz, -1.f, 1.0f);
ImGui::SliderFloat("rotateX", &rotatex, 0.01f, 360.0f);
ImGui::SliderFloat("rotateY", &rotatey, 0.01f, 360.0f);
ImGui::SliderFloat("rotateZ", &rotatez, 0.01f, 360.0f);
ImGui::SliderFloat("scaleX", &scale.x, 0.01f, 3.0f);
ImGui::SliderFloat("scaleY", &scale.y, 0.01f, 3.0f);
ImGui::SliderFloat("scaleZ", &scale.z, 0.01f, 3.0f);
ImGui::NewLine();
根据参数设置变换矩阵:
transform = glm::translate(transform, glm::vec3(transx, transy, transz));
transform = glm::rotate(transform, glm::radians(rotatex), glm::vec3(1, 0, 0));
transform = glm::rotate(transform, glm::radians(rotatey), glm::vec3(0, 1, 0));
transform = glm::rotate(transform, glm::radians(rotatez), glm::vec3(0, 0, 1));
transform = glm::scale(transform, glm::vec3(scale.x, scale.y, scale.z));
设置uniform
值,输入到shader:
glUniformMatrix4fv(glGetUniformLocation(shaderprogram, "transform"), 1, GL_FALSE, glm::value_ptr(transform));
效果:
3D效果的实现
通过设置model
, view
, projection
三个矩阵实现。
glm::mat4 model;
glm::mat4 view;
glm::mat4 projection;
model = glm::rotate(model, 0.f, glm::vec3(1.0f, 1.0f, 0.0f));
view = glm::translate(view, glm::vec3(0.0f, 0.0f, -4.0f));
projection = glm::perspective(glm::radians(45.0f), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
参数说明:
model
:从local space
到world space
,此处不做更改。
view
:从world space
到view space
, 此处将场景向z轴负方向移动,相当于把camera朝屏幕外移动了。
projection
: perspective
的第一个值是Field of view,这里设置为45°。宽高比设置为视口的宽/高。第3,4个值为near和far平面。