2013-11-02 3 views
2

Я создаю базовую сцену OpenGL, и у меня есть проблема с манипулированием моим объектом. Каждая из них имеет другую матрицу преобразования, также имеется матрица modelview/translation/scaling для всей сцены.Применить преобразование к объекту

Как связать этот объект tomy данных перед выполнением вычислений из вершинного шейдера? Я читал о gl (Push | Pop) Matrix(), но эти функции устарели из того, что я понял.

Немного моего кода. Позиция из вершинного шейдера:

gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex; 

И функция C++ для отображения объектов:

// Clear etc... 

mat4 lookAt = glm::lookAt(); 
glLoadMatrixf(&lookAt[0][0]); 
mat4 combined = lookAt * (mat4) sceneTranslation * (mat4) sceneScale; 
glLoadMatrixf(&combined[0][0]); 

mat4 objectTransform(1.0); 
// Transformations... 

// No idea if it works, but objects are affected by camera position but not individually scaled, moved etc. 
GLuint gl_ModelViewMatrix = glGetUniformLocation(shaderprogram, "gl_ModelViewMatrix"); 
glUniformMatrix4fv(gl_ModelViewMatrix, 1, GL_FALSE, &objectTransform[0][0]); 

// For example 
glutSolidCube(1.0); 

glutSwapBuffers(); 

ответ

5

Ну, вам не нужно использовать glLoadMatrix и другие встроенные функции матрицы, потому что это может быть еще сложнее, чем обработка ваших собственных матриц.

Простой пример камеры, не контролируя его, его статическая камера:

glm::mat4x4 view_matrix = glm::lookAt(
    cameraPosition, 
    cameraPosition+directionVector, //or the focus point the camera is pointing to 
    upVector); 

возвращает матрицу 4x4, это вид матрицы.

glm::mat4x4 projection_matrix = 
glm::perspective(60.0f, float(screenWidth)/float(screenHeight), 1.0f, 1000.0f); 

это матрица проекции

так что теперь у вас есть вид и проекционные матрицы, и вы можете отправить его в шейдер:

gShader->bindShader(); 
gShader->sendUniform4x4("view_matrix",glm::value_ptr(view_matrix)); 
gShader->sendUniform4x4("projection_matrix",glm::value_ptr(projection_matrix)); 

bindshader является простой glUseProgram(shaderprog); Единая программа -

void sendUniform4x4(const string& name, const float* matrix, bool transpose=false) 
{ 
    GLuint location = getUniformLocation(name); 
    glUniformMatrix4fv(location, 1, transpose, matrix); 
} 

Ваша матричная модель индивидуальна для каждого из объектов:

glm::mat4x4 model_matrix= glm::mat4(1); //this is the identity matrix, so its static 
model_matrix= glm::rotate(model_matrix, 
          rotationdegree, 
          vec3(axis)); //same as opengl function. 

Это создало модель матрицы, и вы можете отправить его в шейдер слишком

gShader->bindShader(); 
gShader->sendUniform4x4("model_matrix",glm::value_ptr(model_matrix)); 

glm::value_ptr(...) создает 2 одномерный массив вашего матрица.

в вашем шейдерном коде не используются матрицы glModelViewMatrix и gl_ProjectionMatrix, передаются через форму.

uniform mat4 projection_matrix; 
uniform mat4 view_matrix; 
uniform mat4 model_matrix; 

void main(){ 
gl_Position = projection_matrix*view_matrix*model_matrix*gl_Vertex; 
//i wrote gl_Vertex because of the glutSolidTeapot. 
} 

Я никогда не использовал эту сборку в сеточной функции, так что я не знаю, как это работает, предположим, что он посылает вершины в шейдер с непосредственным использованием режима gl_Vertex. Если вы создаете свои собственные сетки, используйте VBO vertexattribpointer и drawarrays/elements.

Не забудьте связать шейдер перед отправкой униформы.

Так с полным пример:

glm::mat4x4 view_matrix = glm::lookAt(2,4,2,-1,-1,-1,0,1,0); 

glm::mat4x4 projection_matrix = 
    glm::perspective(60.0f, float(screenWidth)/float(screenHeight), 1.0f, 10.0f); 

glm::mat4x4 model_matrix= glm::mat4(1); //this remains unchanged 
glm::mat4x4 teapot_model_matrix= glm::rotate(model_matrix, //this is the teapots model matrix, apply transformations to this 
           45, 
           glm::vec3(1,1,1)); 
teapot_model_matrix = glm::scale(teapot_model_matrix,vec3(2,2,2); 


gShader->bindShader(); 
gShader->sendUniform4x4("model_matrix",glm::value_ptr(model_matrix)); 
gShader->sendUniform4x4("view_matrix",glm::value_ptr(view_matrix)); 
gShader->sendUniform4x4("projection_matrix",glm::value_ptr(projection_matrix)); 

glutSolidCube(0.0); //i don't know what the (0.0) stands for :/ 
glutSwapBuffers(); 

///////////////////////////////// //

в вашем шейдере:

uniform mat4 projection_matrix; //these are the matrixes you've sent 
uniform mat4 view_matrix; 
uniform mat4 model_matrix; 

void main(){ 
gl_Position = projection_matrix*view_matrix*model_matrix*vec4(gl_Vertex.xyz,1); 
} 

Теперь вы должны иметь камеру, расположенную на 2,4,2, сосредоточившись на -1, -1, -1, а вверх вектор направлен вверх:)

Чайник повернут на 4 5 градусов вокруг (1,1,1) вектора и масштабируется на 2 в каждом направлении.

После изменения матрицы модели отправьте ее в шейдер, так что, если у вас есть больше объектов для рендеринга , отправьте их после каждого, если вы хотите иметь различные преобразования, применяемые к каждой сетке. псевдокод это выглядит следующим образом:

camera.lookat(camerapostion,focuspoint,updirection); //sets the view 
camera.project(fov,aspect ratio,near plane, far plane) //and projection matrix 
camera.sendviewmatrixtoshader; 
camera.sendprojectionmatrixtoshader; 

obj1.rotate(45 degrees, 1,1,1); //these functions should transform the model matrix of the object. Make sure each one has its own. 
obj1.sendmodelmatrixtoshader; 
obj2.scale(2,1,1); 
obj2.sendmodelmatrixtoshader; 

Если это не работает, попробуйте его с VertexBuffer и простой треугольник или куб, созданный самостоятельно.

3

Вы должны использовать математическую библиотеку, я рекомендую GLM. Он имеет свои матричные функции, как и в OpenGL, и использует основные матрицы столбцов, поэтому вы можете рассчитать свои собственные и применять их для объектов.

Во-первых, у вас должен быть класс матрицы для вашей сцены, который вычисляет вашу матрицу просмотра и матрицу проекций. (glm :: lookAt и glm :: project). Они работают так же, как и в openGL. Вы можете отправить их в виде униформы в вершинный шейдер.

Для целей, вы вычисляете свои собственные марши и отправляете их в качестве матрицы модели в шейдер (ы).

В затенении или на процессоре рассчитать мв матрицу:

vp = proj*view. 

Вы присылаете свои индивидуальные модели матрицы в шейдер и рассчитать конечную позицию:

gl_Position = vp*m*vec4(vertex.xyz,1); 

МОДЕЛЬ МАТРИЦА

с glm, вы можете легко вычислить, преобразовать ваши матрицы. Вы создаете простую идентичную матрицу:

glm::mat4x4(1) //identity 

Вы можете перевести, повернуть и масштабировать.

glm::scale 
glm::rotate 
glm::translate 

Они работают как в непосредственном режиме в opengl.

после того, как у вас есть ваша матрица, отправьте его через форму.

MORE МОДЕЛЬ МАТРИЦА

shader->senduniform("proj", camera.projectionmatrix); 
shader->senduniform("view", camera.viewmatrix); 
glm::mat4 model(1); 

obj1.modelmatrix = glm::translate(model,vec3(1,2,1)); 
shader->senduniform("model", obj1.modelmatrix); 
objectloader.render(obj1); 

obj2.modelmatrix = glm::rotate(model,obj2.degrees,vec3(obj2.rotationaxis)); 
shader->senduniform("model", obj2.modelmatrix); 
objectloader.render(obj2); 

Это лишь один из способов сделать это. Вы можете написать класс для тяни/поп-матричных вычислений, автоматизации, описанным выше способом, как это:

obj1.rotate(degrees,vec3(axis)); //this calculates the obj1.modelmatrix for example rotating the identity matrix. 
obj1.translate(vec3(x,y,z))//more transform 
obj1.render(); 
//continue with object 2 

матричном

матрицу вида почти такой же, как модель матрицы. Используйте это для управления глобальной «матрицей модели», камерой. Это преобразует ваш экран по всему миру, и вы можете иметь модельные матрицы для своих объектов индивидуально.

В классе моей камеры я вычисляю это с помощью glm :: lookAt (то же, что и opengl), а затем отправляю его через форму для всех шейдеров, которые я использую.

Затем, когда я визуализую что-то, я могу манипулировать его матрицей модели, поворачивая или масштабируя ее, но матрица вида является глобальной.

Если вы хотите статический объект, вы не должны использовать модель матрицы на нее, вы можете вычислить позицию только:

gl_Position = projmatrix*viewmatrix*staticobjectvertex; 

GLOBAL МОДЕЛЬ МАТРИЦА

Вы можете иметь глобальная модельная матрица.

Используйте его как

renderer.globmodel.rotate(axis,degree); 
renderer.globmodel.scale(x,y,z); 

Отправить как униформе тоже, и применить его после того, как модели матричных объектов. (я использовал его, чтобы сделать океан отражений в текстуру.)

Подводя итог:

  • создать глобальное представление матрицы
  • (камера) создать модель матрицы для каждого из ваших sceens, сетка или объекты
  • преобразования матрицы объектов, по отдельности
  • посылают проекции, модель и представление матриц с помощью мундиров в шейдер
  • вычислить окончательную позицию: Рго * камера * модель * вершина
  • перемещать объекты и перемещать камеру

Я не говорю, что их нет лучшего способа сделать это, но это работает мне хорошо.

PS: если вы хотите, чтобы некоторые камеры были отключены, у меня довольно хороший;).

+0

Благодарим за подробное описание. Я добавил немного кода для лучшего понимания моей проблемы. Я отправляю данные в шейдер правильно? –

+0

Проблема с вашим кодом заключается в том, что вы смешиваете функции ffp (устаревшие) с вашими собственными, что не является хорошей практикой. Я отправляю еще один ответ. –

+0

Ну, мне удалось просто умножить матрицу трансформации объекта на матрицу сцены и glLoadMatrixf(). Спасибо за интерес. –