我正在尝试在OpenGL中旋转文本,但问题是文本旋转得像它应该但在错误的点,即它不会在文本的中心旋转(并且我想要我知道怎么做!)。
我之所以感到困惑是因为我对文本的不同字母使用多个纹理让我感到困惑。
如果您想知道我使用的是哪个库,则为CGLM
但是当我编译这段代码时,rotate函数会以错误的旋转点旋转对象。
根据Rabbid76。我做了以下工作来获得整个文本的大小: -
for (int i = 0; i < (signed)strlen(text); i++)
{
tw += iterator[(int)text[i]].Character_Array.Size[0];
th += iterator[(int)text[i]].Character_Array.Size[1];
}
我仍然没有得到正确的结果,文字仍然是错误的。
在任何轮换之前(这是它应该旋转的地方): - 旋转45度后(它的位置错位): -
编辑:源文件的整个代码: -
// Std. Includes
#include <stdio.h>
#include <stdlib.h>
// GLEW
#define GLEW_STATIC
#include <GL/glew.h>
// GLFW
#include <GLFW/glfw3.h>
// GLM
#include <cglm/cglm.h>
// FreeType
#include <ft2build.h>
#include FT_FREETYPE_H
// Properties
const GLuint WIDTH = 800, HEIGHT = 600;
const GLchar * vertexShaderSource =
"#version 330 core\n"
"layout(location = 0) in vec4 vertex;\n"
"out vec2 TexCoords;\n"
"uniform mat4 projection;\n"
"uniform mat4 model;\n"
"void main()\n"
"{\n"
"gl_Position = projection * model * vec4(vertex.xy, 0.0, 1.0);\n"
"TexCoords = vertex.zw;\n"
"}\n\0";
const GLchar * fragmentShaderSource =
"#version 330 core\n"
"in vec2 TexCoords;\n"
"out vec4 color;\n"
"uniform sampler2D text;\n"
"uniform vec4 textColor;\n"
"void main()\n"
"{\n"
"vec4 sampled = vec4(1.0, 1.0, 1.0, texture(text, TexCoords).r);\n"
"color = textColor * sampled;\n"
"}\n\0";
/// Holds all state information relevant to a character as loaded using FreeType
typedef struct {
GLuint TextureID; // ID handle of the glyph texture
int Size[2]; // Size of glyph
int Bearing[2]; // Offset from baseline to left/top of glyph
GLuint Advance; // Horizontal offset to advance to next glyph
} Character;
typedef struct
{
GLchar char_Array;
Character Character_Array;
} Iterator;
Iterator * iterator;
GLuint VAO, VBO;
// RenderText function.. to render our text...
void RenderText(GLuint program, const char * text, GLfloat originx, GLfloat originy, GLfloat x, GLfloat y, GLfloat scalex, GLfloat scaley, float rotation, float r, float g, float b, float a);
// The MAIN function, from here we start our application and run the Game loop
int main()
{
iterator = NULL;
// Init GLFW
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "LearnOpenGL", NULL, NULL); // Windowed
glfwMakeContextCurrent(window);
// Initialize GLEW to setup the OpenGL Function pointers
glewExperimental = GL_TRUE;
glewInit();
// Define the viewport dimensions
glViewport(0, 0, WIDTH, HEIGHT);
// Set OpenGL options
glEnable(GL_CULL_FACE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// Compile and setup the shader
GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex_shader, 1, &vertexShaderSource, NULL);
glCompileShader(vertex_shader);
GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment_shader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragment_shader);
GLuint program = glCreateProgram();
glAttachShader(program, vertex_shader);
glAttachShader(program, fragment_shader);
glLinkProgram(program);
glDeleteShader(vertex_shader);
glDeleteShader(fragment_shader);
mat4 projection;
glm_ortho(0.0f, (GLfloat)WIDTH, (GLfloat)HEIGHT, 0.0f, -1, 1, projection);
glUseProgram(program);
glUniformMatrix4fv(glGetUniformLocation(program, "projection"), 1, GL_FALSE, (GLfloat *)projection);
// FreeType
FT_Library ft;
// All functions return a value different than 0 whenever an error occurred
if (FT_Init_FreeType(&ft))
printf("ERROR::FREETYPE: Could not init FreeType Library\n");
// Load font as face
FT_Face face;
if (FT_New_Face(ft, "playfair.ttf", 0, &face))
printf("ERROR::FREETYPE: Failed to load font\n");
// Set size to load glyphs as
FT_Set_Pixel_Sizes(face, 0, 72);
// Disable byte-alignment restriction
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
int i = 0;
// Load first 128 characters of ASCII set
for (GLubyte c = 0; c < 255; c++)
{
// Load character glyph
if (FT_Load_Char(face, c, FT_LOAD_RENDER))
{
printf("ERROR::FREETYTPE: Failed to load Glyph\n");
continue;
}
// Generate texture
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RED,
face->glyph->bitmap.width,
face->glyph->bitmap.rows,
0,
GL_RED,
GL_UNSIGNED_BYTE,
face->glyph->bitmap.buffer
);
// Set texture options
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Now store character for later use
Character character = {
texture,
{(signed)face->glyph->bitmap.width, (signed)face->glyph->bitmap.rows},
{face->glyph->bitmap_left, face->glyph->bitmap_top},
(GLuint)face->glyph->advance.x
};
iterator = (Iterator*)realloc(iterator, sizeof(Iterator) * (i + 1));
iterator[i].Character_Array = character;
iterator[i].char_Array = c;
i++;
}
glBindTexture(GL_TEXTURE_2D, 0);
// Destroy FreeType once we're finished
FT_Done_Face(face);
FT_Done_FreeType(ft);
// Configure VAO/VBO for texture quads
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 6 * 4, NULL, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
glfwVulkanSupported();
// Game loop
float k = 0;
while (!glfwWindowShouldClose(window))
{
// Check and call events
glfwPollEvents();
// Clear the colorbuffer
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
if (k > 360)
{
k = 0;
}
k += 0.1f;
RenderText(program, "Rotation", 0, 0, 10.0f, 10.0f, 1.0f, 1.0f, k, 0.5f, 0.8f, 0.2f, 1.0f);
// Swap the buffers
glfwSwapBuffers(window);
}
glfwTerminate();
return 0;
}
void RenderText(GLuint program, const char * text, GLfloat originx, GLfloat originy, GLfloat x, GLfloat y, GLfloat scalex, GLfloat scaley, float rotation, float r, float g, float b, float a)
{
// Activate corresponding render state
glUseProgram(program);
glUniform4f(glGetUniformLocation(program, "textColor"), r, g, b, a);
glActiveTexture(GL_TEXTURE0);
glBindVertexArray(VAO);
GLfloat tw = iterator[(int)text[i]].Character_Array.Bearing[0],
th = 0.0f;
for (int i = 0; i < (signed)strlen(text); i++)
{
Character ch = iterator[(int)text[i]].Character_Array;
tw += (ch.Advance >> 6);
th += ch.Size[1];
}
GLfloat rx = tw / 2.0f;
GLfloat ry = th / 2.0f;
mat4 model;
glm_mat4_identity(model);
glm_translate(model, (vec3) { originx, originy, 0.0f });
glm_translate(model, (vec3) { scalex * rx, scaley * ry, 0.0f });
glm_rotate(model, glm_rad(rotation), (vec3) { 0.0f, 0.0f, 1.0f });
glm_translate(model, (vec3) { -scalex * rx, -scaley * ry, 0.0f });
glm_scale(model, (vec3) { scalex, scaley, 1.0f });
GLfloat xpos = 0.0;
GLfloat ypos = 0.0;
for (int i = 0; i < (signed)strlen(text); i++)
{
Character ch = iterator[(int)text[i]].Character_Array;
mat4 ch_model;
memcpy(ch_model, model, 16 * sizeof(float));
glm_translate(ch_model, (vec3) { x, 0.0f, 0.0f });
// Now advance cursors for next glyph (note that advance is number of 1/64 pixels)
x += (ch.Advance >> 6); // Bitshift by 6 to get value in pixels (2^6 = 64 (divide amount of 1/64th pixels by 64 to get amount of pixels))
glUniformMatrix4fv(glGetUniformLocation(program, "model"), 1, GL_FALSE, (GLfloat *)ch_model);
// Render glyph texture over quad
glBindTexture(GL_TEXTURE_2D, ch.TextureID);
GLfloat w = ch.Size[0] * scalex;
GLfloat h = ch.Size[1] * scaley;
GLfloat vertices[6][4] = {
{ 0.0f, h, 0.0, 1.0 },
{ w, 0.0f, 1.0, 0.0 },
{ 0.0f, 0.0f, 0.0, 0.0 },
{ 0.0f, h, 0.0, 1.0 },
{ w, h, 1.0, 01.0 },
{ w, 0.0f, 01.0, 0.0 },
};
// Update content of VBO memory
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices); // Be sure to use glBufferSubData and not glBufferData
glBindBuffer(GL_ARRAY_BUFFER, 0);
// Render quad
glDrawArrays(GL_TRIANGLES, 0, 6);
}
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
}
答案 0 :(得分:0)
glm_rotate
在原点应用轮播。因此,如果几何体的中心不在原点,则不会围绕对象/几何体的中心进行旋转。
解决方案: X = T(p)Rz(φ)T(-p)其中X是最终变换,p是枢轴
如果要围绕对象的中心旋转(如果对象的中心不在原点),则必须计算该对象/几何的中心。在应用任何轮换之前。您可以计算边界框然后获得该框的中心。
cglm还提供了以下功能:glm_vec_center(min, max, pivot); /* pivot = center of object */
。现在我们有中心点。让我们围绕这一点轮换:
/* ... */
glm_vec_center(min, max, pivot); /* center of object */
glm_vec_inv_to(pivot, pivotInv); /* -pivot */
/* ... */
glm_translate(model, pivot);
glm_rotate(model, angle, axis);
glm_translate(model, pivotInv);
上面的代码与 X = T(p)Rz(φ)T(-p)(平移(-pivot),旋转,平移(枢轴))相同。代码在代码中似乎相反,因为glm_translate
=转换*转换。如果glm_translate
= Translate * Transform,则不会是逆序。 cglm将来也可以提供这种替代的翻译乘法
编辑:启动v0.4.2版本cglm为此提供了功能:检查glm_rotate_at()和glm_quat_rotate_at(),glm_rotate_atm
和{{ 1}}为枢轴点创建新的旋转,因为glm_quat_rotate_atm
和glm_rotate_at
会旋转现有的变换。要使用这些功能,请确保您拥有最新版本。