我正在使用opengl-es 2.0开发一个项目,我在设置透视投影时遇到了一些麻烦。
如果我没有设置透视投影并简单地将对象到世界矩阵(我相信它也称为模型矩阵)乘以顶点位置,则屏幕上的对象会正确渲染,它们会显示为拉伸,但是据我所知,投影矩阵会解决这个问题。问题是,每当我设置透视矩阵并使用它时,屏幕上的对象就会消失,无论我移动多少它们都不会出现在屏幕上。
获取模型 - 视图 - 投影矩阵的计算是在CPU中完成的,最后的乘法MVP-Matrix是由实际的对象空间顶点数据在顶点着色器中完成的,这就是为什么我认为问题可能是关于获得MVP-Matrix的过程。我已经运行了一系列单元测试,但根据这些测试(以及我对线性代数的基本知识),这些矩阵正在被正确计算,而我整天的网络研究现在都无济于事。 : - /
这是我用来计算MVP-Matrix的代码:
Matrix4D projection_matrix;
projection_matrix.makePerspective(45.0f, 0.001f, 100.0f, 480.0f/320.0f);
Matrix4D view_matrix;
view_matrix.makeIdentity(); //Should be a real view matrix. TODO.
Matrix4D model_matrix(getWorldMatrix());
Matrix4D mvp_matrix(projection_matrix);
mvp_matrix *= view_matrix;
mvp_matrix *= model_matrix;
mMesh->draw(time, mvp_matrix.getRawData());
我认为这段代码非常明显,但是以防万一,那些Matrix4D是4x4矩阵,在它们上调用makePerspective / makeIdentity会使该矩阵成为Perspective或Identity矩阵。对Matrix4D对象的getRawData()调用将矩阵数据作为以float-major表示法的float数组返回,而mMesh变量是另一个对象,当调用draw时,它将简单地将所有顶点和材质数据发送到着色器。 / p>
makePerspective函数的代码如下:
Matrix4D& Matrix4D::makePerspective(const float field_of_view,
const float near, const float far, const float aspect_ratio) {
float size = near * tanf(DEGREES_TO_RADIANS(field_of_view) / 2.0f);
return this->makeFrustum(-size, size, -size / aspect_ratio,
size / aspect_ratio, near, far);
}
Matrix4D& Matrix4D::makeFrustum(const float left, const float right,
const float bottom, const float top, const float near,
const float far) {
this->mRawData[0] = 2.0f * near / (right - left);
this->mRawData[1] = 0.0f;
this->mRawData[2] = 0.0f;
this->mRawData[3] = 0.0f;
this->mRawData[4] = 0.0f;
this->mRawData[5] = 2.0f * near / (top - bottom);
this->mRawData[6] = 0.0f;
this->mRawData[7] = 0.0f;
this->mRawData[8] = (right + left) / (right - left);
this->mRawData[9] = (top + bottom) / (top - bottom);
this->mRawData[10] = - (far + near) / (far - near);
this->mRawData[11] = -1.0f;
this->mRawData[12] = 0.0f;
this->mRawData[13] = 0.0f;
this->mRawData[14] = -2.0f * far * near / (far - near);
this->mRawData[15] = 0.0f;
return *this;
}
getWorldMatrix()调用会执行此操作(使用一些相关代码):
const Matrix4D& getWorldMatrix() {
return mWorldMatrix =
getTranslationMatrix() *
getRotationMatrix() *
getScaleMatrix();
}
const Matrix4D& getRotationMatrix() {
return this->mRotationMatrix.makeRotationFromEuler(this->mPitchAngle,
this->mRollAngle, this->mYawAngle);
}
const Matrix4D& getTranslationMatrix() {
return this->mTranslationMatrix.makeTranslation(this->mPosition.x,
this->mPosition.y, this->mPosition.z);
}
const Matrix4D& getScaleMatrix() {
return this->mScaleMatrix.makeScale(this->mScaleX, this->mScaleY, this->mScaleZ);
}
///This code goes in the Matrix4D class.
Matrix4D& Matrix4D::makeTranslation(const float x, const float y,
const float z) {
this->mRawData[0] = 1.0f;
this->mRawData[1] = 0.0f;
this->mRawData[2] = 0.0f;
this->mRawData[3] = 0.0f;
this->mRawData[4] = 0.0f;
this->mRawData[5] = 1.0f;
this->mRawData[6] = 0.0f;
this->mRawData[7] = 0.0f;
this->mRawData[8] = 0.0f;
this->mRawData[9] = 0.0f;
this->mRawData[10] = 1.0f;
this->mRawData[11] = 0.0f;
this->mRawData[12] = x;
this->mRawData[13] = y;
this->mRawData[14] = z;
this->mRawData[15] = 1.0f;
return *this;
}
Matrix4D& Matrix4D::makeScale(const float x, const float y,
const float z) {
this->mRawData[0] = x;
this->mRawData[1] = 0.0f;
this->mRawData[2] = 0.0f;
this->mRawData[3] = 0.0f;
this->mRawData[4] = 0.0f;
this->mRawData[5] = y;
this->mRawData[6] = 0.0f;
this->mRawData[7] = 0.0f;
this->mRawData[8] = 0.0f;
this->mRawData[9] = 0.0f;
this->mRawData[10] = z;
this->mRawData[11] = 0.0f;
this->mRawData[12] = 0.0f;
this->mRawData[13] = 0.0f;
this->mRawData[14] = 0.0f;
this->mRawData[15] = 1.0f;
return *this;
}
Matrix4D& Matrix4D::makeRotationFromEuler(const float angle_x,
const float angle_y, const float angle_z) {
float a = cosf(angle_x);
float b = sinf(angle_x);
float c = cosf(angle_y);
float d = sinf(angle_y);
float e = cosf(angle_z);
float f = sinf(angle_z);
float ad = a * d;
float bd = b * d;
this->mRawData[0] = c * e;
this->mRawData[1] = -bd * e + a * f;
this->mRawData[2] = ad * e + b * f;
this->mRawData[3] = 0.0f;
this->mRawData[4] = -c * f;
this->mRawData[5] = bd * f + a * e;
this->mRawData[6] = -ad * f + b * e;
this->mRawData[7] = 0.0f;
this->mRawData[8] = -d;
this->mRawData[9] = -b * c;
this->mRawData[10] = a * c;
this->mRawData[11] = 0.0f;
this->mRawData[12] = 0.0f;
this->mRawData[13] = 0.0f;
this->mRawData[14] = 0.0f;
this->mRawData[15] = 1.0f;
return *this;
}
最后,顶点着色器就是这样的:
#version 110
const float c_one = 1.0;
const float c_cero = 0.0;
uniform float time;
uniform mat4 mvp_matrix;
attribute vec3 position;
attribute vec3 normal;
attribute vec2 texture_coordinate;
varying vec2 v_texture_coordinate;
void main()
{
gl_Position = mvp_matrix * vec4(position, c_one);
v_texture_coordinate = texture_coordinate;
}
以防万一,正在渲染的物体在位置(0.0f,0.0f,-3.0f)上渲染,0.5f比例应用于所有三个轴。
我真的不知道可能出现什么问题,我希望有人能发现我可能遗漏的内容,任何帮助都会受到赞赏。如果我可以在着色器上获得每顶点结果,那么调试这将更容易: - /。
作为旁注,我对如何计算视图或相机矩阵有疑问,据我所知它只是一个带有相机必须做的倒置变换的矩阵,我明白这一点,如果我想将相机100个单元向右移动,我向左移动100个单位,是吗?
编辑:只是想提供更多信息,也许这样有人可以帮助我。我注意到上面的代码模型矩阵是不正确的,主要是因为矩阵顺序,我把它改为以下,现在模型矩阵似乎很好:
const Matrix4D& getWorldMatrix() {
return mWorldMatrix =
getScaleMatrix() * getRotationMatrix() * getTranslationMatrix();
}
尽管如此,仍然没有运气。我的测试数据产生的矩阵如下:
Projection matrix:
[1.609506,0.000000,0.000000,0.000000]
[0.000000,2.414258,0.000000,0.000000]
[0.000000,0.000000,-1.000020,-0.002000]
[0.000000,0.000000,-1.000000,0.000000]
Model matrix:
[0.500000,0.000000,0.000000,0.000000]
[0.000000,0.500000,0.000000,0.000000]
[0.000000,0.000000,0.500000,-3.000000]
[0.000000,0.000000,0.000000,1.000000]
MVP matrix:
[0.804753,0.000000,0.000000,0.000000]
[0.000000,1.207129,0.000000,0.000000]
[0.000000,0.000000,2.499990,-0.001000]
[0.000000,0.000000,-1.000000,0.000000]
我用来测试这一切的网格是一个简单的立方体,从每个轴上的1.0f到-1.0f,以原点为中心。据我所知,这应该沿着z轴将最接近近界限(0.0001f)的顶点定位在-2.0f位置,因此立方体位于摄像机前方并且具有视锥体。有人提出任何线索吗?