2013-04-26 121 views
2

我在iOS的OpenGL ES 2.0中有一个球体(地球)。我也有要放在地球上的标记,但我希望标记始终面向用户(广告牌),但当它通过触摸旋转时,还会与地球一起移动。所以我试图研究广告牌并将以下代码放在一起。该代码来自创建地球之后调用的广告牌功能(在Z轴上向后翻译6个单元)。我似乎无法让广告牌的飞机总是面向相机,但它也随着地球旋转而移动。我怎样才能做到这一点?iOS OpenGL ES 2.0球体上的广告牌对象和球体旋转

// Get the current modelview matrix 
    GLKMatrix4 originalMat = self.effect.transform.modelviewMatrix; 
    GLKMatrix4 currMat = self.effect.transform.modelviewMatrix; 

    // Define the buffer designators 
    GLuint billboardVertexArray; 
    GLuint billboardVertexBuffer; 
    GLuint billboardIndexBuffer; 

    glGenVertexArraysOES(1, &billboardVertexArray); 
    glBindVertexArrayOES(billboardVertexArray); 

    // Now draw the billboard 
    glGenBuffers(1, &billboardVertexBuffer); 
    glBindBuffer(GL_ARRAY_BUFFER, billboardVertexBuffer); 
    glBufferData(GL_ARRAY_BUFFER, sizeof(Billboard_vertex), Billboard_vertex, GL_STATIC_DRAW); 

    glGenBuffers(1, &billboardIndexBuffer); 
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, billboardIndexBuffer); 
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Billboard_index), Billboard_index, GL_STATIC_DRAW); 

    // u0,v0,normalx0,normaly0,normalz0,x0,y0,z0 
    glEnableVertexAttribArray(GLKVertexAttribPosition); 
    glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 8*sizeof(float), BUFFER_OFFSET(5)); 
    glEnableVertexAttribArray(GLKVertexAttribTexCoord0); 
    glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, 8*sizeof(float), BUFFER_OFFSET(0)); 
    glEnableVertexAttribArray(GLKVertexAttribNormal); 
    glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, 8*sizeof(float), BUFFER_OFFSET(2)); 

    // Enable the Earth texture 
    self.effect.texture2d0.name = _billBoardTextureInfo.name; 
    self.effect.texture2d0.target = _billBoardTextureInfo.target; 

    // Bind the earth vertex array 
    glBindVertexArrayOES(billboardVertexArray); 

    // Now put a billboard at a specific Lat Lon - so first 
    // calculate XYZ from lat lon 
    XYZ xyz; 
    xyz.x = 0; xyz.y = 0; xyz.z = 0; 
    [self LLAtoXYZwithLat:0 andLon:0 andXYZ:&xyz]; 
    //NSLog(@"XYZ after: %f %f %f",xyz.x,xyz.y,xyz.z); 

    // Move the billboard back so we can see it 
    GLKMatrix4 modelViewMatrix = GLKMatrix4MakeTranslation(0.0f, 0.0f, -6.0f); 

    // In update, we convert the quaternion into a rotation matrix, and apply it to the model view matrix as usual. 
    GLKMatrix4 rotation = GLKMatrix4MakeWithQuaternion(_quat); 
    modelViewMatrix = GLKMatrix4Multiply(modelViewMatrix, rotation); 

    // First create the variation translations to anchor the billboard 
    GLKMatrix4 translationXYZ = GLKMatrix4MakeTranslation(xyz.x, xyz.y, xyz.z); 
    GLKMatrix4 translationForLatLonWithTranslation = GLKMatrix4Multiply(modelViewMatrix,translationXYZ); 

    // Scale this object as well 
    GLKMatrix4 scaledWithTranslationAndRotation = GLKMatrix4Scale(translationForLatLonWithTranslation, scale, scale, scale); 

    // Remove the Translation portion of the matrix 
    // | xx xy xz xw | 
    // | yx yy yz yw | 
    // | zx zy zz zw | 
    // | wx wy wz ww | 
    // 
    // | R  T | 
    // | (0,0,0) 1 | 
    // 
    // d = sqrt(xx² + yx² + zx²) 
    // 
    // | d 0 0 T.x | 
    // | 0 d 0 T.y | 
    // | 0 0 d T.z | 
    // | 0 0 0 1 | 
    // 
    // union _GLKMatrix4 
    // { 
    //  struct 
    //  { 
    //   float m00, m01, m02, m03; 
    //   float m10, m11, m12, m13; 
    //   float m20, m21, m22, m23; 
    //   float m30, m31, m32, m33; 
    //  }; 
    //  float m[16]; 
    // } 
    // typedef union _GLKMatrix4 GLKMatrix4; 

    // Construct the rows in the new matrix 
    float d = sqrt(pow(currMat.m00,2) + pow(currMat.m10,2) + pow(currMat.m20,2)); 
    GLKVector4 columnToInsert0 = GLKVector4Make(d, 0, 0, currMat.m03+xyz.x); 
    GLKVector4 columnToInsert1 = GLKVector4Make(0, d, 0, currMat.m13+xyz.y); 
    //GLKVector4 columnToInsert2 = GLKVector4Make(0, 0, d, currMat.m23-6+xyz.z); 
    GLKVector4 columnToInsert3 = GLKVector4Make(0, 0, 0, 1); 

    // Build the new Matrix 
    GLKMatrix4 noTranslationInfo = GLKMatrix4SetRow(currMat, 0, columnToInsert0); 
    noTranslationInfo = GLKMatrix4SetRow(noTranslationInfo, 1, columnToInsert1); 
    //noTranslationInfo = GLKMatrix4SetRow(noTranslationInfo, 2, columnToInsert2); 
    noTranslationInfo = GLKMatrix4SetRow(noTranslationInfo, 3, columnToInsert3); 

    [self printMatrix:noTranslationInfo]; 

    // Assign the new matrix to draw with - no translation 
    self.effect.transform.modelviewMatrix = noTranslationInfo; 

    // Render the object with GLKit 
    [self.effect prepareToDraw]; 

    // Draw elements from the index array and uv/vertex/normal info 
    glDrawElements(GL_TRIANGLES,Billboard_polygoncount*3,GL_UNSIGNED_SHORT,0); 

    // Restore the original matrix 
    self.effect.transform.modelviewMatrix = originalMat; 

enter image description here

enter image description here

回答

2

这似乎是工作不错:

// Get the current modelview matrix 
GLKMatrix4 originalMat = self.effect.transform.modelviewMatrix; 
GLKMatrix4 currMat = self.effect.transform.modelviewMatrix; 

// Print the original matrix for comparison 
//NSLog(@"Original Matrix:"); 
//[self printMatrix:currMat]; 

// Define the buffer designators 
GLuint billboardVertexArray; 
GLuint billboardVertexBuffer; 
GLuint billboardIndexBuffer; 

glGenVertexArraysOES(1, &billboardVertexArray); 
glBindVertexArrayOES(billboardVertexArray); 

// Now draw the billboard 
glGenBuffers(1, &billboardVertexBuffer); 
glBindBuffer(GL_ARRAY_BUFFER, billboardVertexBuffer); 
glBufferData(GL_ARRAY_BUFFER, sizeof(Billboard_vertex), Billboard_vertex, GL_STATIC_DRAW); 

glGenBuffers(1, &billboardIndexBuffer); 
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, billboardIndexBuffer); 
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Billboard_index), Billboard_index, GL_STATIC_DRAW); 

// u0,v0,normalx0,normaly0,normalz0,x0,y0,z0 
glEnableVertexAttribArray(GLKVertexAttribPosition); 
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 8*sizeof(float), BUFFER_OFFSET(5)); 
glEnableVertexAttribArray(GLKVertexAttribTexCoord0); 
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, 8*sizeof(float), BUFFER_OFFSET(0)); 
glEnableVertexAttribArray(GLKVertexAttribNormal); 
glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, 8*sizeof(float), BUFFER_OFFSET(2)); 

// Enable the Earth texture 
self.effect.texture2d0.name = _billBoardTextureInfo.name; 
self.effect.texture2d0.target = _billBoardTextureInfo.target; 

// Bind the earth vertex array 
glBindVertexArrayOES(billboardVertexArray); 

// Now put a billboard at a specific Lat Lon - so first 
// calculate XYZ from lat lon 
XYZ xyz; 
xyz.x = 0; xyz.y = 0; xyz.z = 0; 
[self LLAtoXYZwithLat:35 andLon:-97 andXYZ:&xyz]; 
//NSLog(@"XYZ after: %f %f %f",xyz.x,xyz.y,xyz.z); 

// Scale this object as well 
//GLKMatrix4 scaledWithTranslationAndRotation = GLKMatrix4Scale(translationForLatLonWithTranslation, scale, scale, scale); 

// Remove the Translation portion of the matrix 
// | xx xy xz xw | 
// | yx yy yz yw | 
// | zx zy zz zw | 
// | wx wy wz ww | 
// 
// | R  T | 
// | (0,0,0) 1 | 
// 
// d = sqrt(xx² + yx² + zx²) 
// 
// | d 0 0 T.x | 
// | 0 d 0 T.y | 
// | 0 0 d T.z | 
// | 0 0 0 1 | 
// 
// union _GLKMatrix4 
// { 
//  struct 
//  { 
//   float m00, m01, m02, m03; 
//   float m10, m11, m12, m13; 
//   float m20, m21, m22, m23; 
//   float m30, m31, m32, m33; 
//  }; 
//  float m[16]; 
// } 
// typedef union _GLKMatrix4 GLKMatrix4; 

// Construct the rows in the new matrix 
float d = sqrt(pow(currMat.m00,2) + pow(currMat.m10,2) + pow(currMat.m20,2)); 
GLKVector4 columnToInsert0 = GLKVector4Make(d, 0, 0, xyz.x); 
GLKVector4 columnToInsert1 = GLKVector4Make(0, d, 0, xyz.y); 
GLKVector4 columnToInsert2 = GLKVector4Make(0, 0, d, xyz.z); 
GLKVector4 columnToInsert3 = GLKVector4Make(0, 0, 0, 1); 

// Build the new Matrix 
GLKMatrix4 noTranslationInfo = GLKMatrix4SetRow(currMat, 0, columnToInsert0); 
noTranslationInfo = GLKMatrix4SetRow(noTranslationInfo, 1, columnToInsert1); 
noTranslationInfo = GLKMatrix4SetRow(noTranslationInfo, 2, columnToInsert2); 
noTranslationInfo = GLKMatrix4SetRow(noTranslationInfo, 3, columnToInsert3); 

// Print out the 'no translation' matrix 
//NSLog(@"No Translation Matrix:"); 
//[self printMatrix:noTranslationInfo]; 

// Get a rotation matrix from the quaternion we last rotated the globe with 
GLKMatrix4 rotationMatrixFromQuaternion = GLKMatrix4MakeWithQuaternion(_quat); 
//NSLog(@"Rotation Matrix from Quaternion: "); 
//[self printMatrix:rotationMatrixFromQuaternion]; 

// Now use the matrix produced from our Quaternion to rotate the global coordinates 
// of the billboard object 
GLKMatrix4 rotatedNoTranslationInfo = GLKMatrix4Multiply(rotationMatrixFromQuaternion, noTranslationInfo); 

//NSLog(@"rotatedNoTranslationInfo:"); 
//[self printMatrix:rotatedNoTranslationInfo]; 

// Throw the world translation coordinates in the matrix 
noTranslationInfo.m30 = (rotatedNoTranslationInfo.m30); 
noTranslationInfo.m31 = (rotatedNoTranslationInfo.m31); 
noTranslationInfo.m32 = (rotatedNoTranslationInfo.m32 + GLOBAL_EARTH_Z_LOCATION); 

//NSLog(@"Final Matrix:"); 
//[self printMatrix:noTranslationInfo]; 

// Assign the new matrix to draw with - no translation 
self.effect.transform.modelviewMatrix = noTranslationInfo; 

// Render the object with GLKit 
[self.effect prepareToDraw]; 

// Draw elements from the index array and uv/vertex/normal info 
glDrawElements(GL_TRIANGLES,Billboard_polygoncount*3,GL_UNSIGNED_SHORT,0); 

// Restore the original matrix 
self.effect.transform.modelviewMatrix = originalMat; 

enter image description here

enter image description here

enter image description here

+0

您的代码非常友好,对我非常有帮助。但我只有一个问题: 如何计算四元数(在代码中是'_quat' ivar)? – 2013-07-25 11:55:39

+0

嗨,我做到了,就像在本教程中一样:http://www.raywenderlich.com/12667/how-to-rotate-a-3d-object-using-touches-with-opengl – PhilBot 2013-07-25 18:57:11

1

当我做这个,我送来的四个顶点的广告牌,全部由矩形的中心,顶点着色器(真的二套,三套的,对于两个三角形),并使顶点着色器取代它们始终面向观察者。我描述这一过程中my answer here,但相关顶点着色器代码如下:

attribute vec4 position; 
attribute vec4 inputImpostorSpaceCoordinate; 

varying mediump vec2 impostorSpaceCoordinate; 
varying mediump vec3 normalizedViewCoordinate; 

uniform mat4 modelViewProjMatrix; 
uniform mediump mat4 orthographicMatrix; 
uniform mediump float sphereRadius; 

void main() 
{ 
    vec4 transformedPosition; 
    transformedPosition = modelViewProjMatrix * position; 
    impostorSpaceCoordinate = inputImpostorSpaceCoordinate.xy; 

    transformedPosition.xy = transformedPosition.xy + inputImpostorSpaceCoordinate.xy * vec2(sphereRadius); 
    transformedPosition = transformedPosition * orthographicMatrix; 

    normalizedViewCoordinate = (transformedPosition.xyz + 1.0)/2.0; 
    gl_Position = transformedPosition; 
} 

inputImpostorSpaceCoordinate属性是四个坐标范围从(-1,-1)(1,1),并在被提供平行于你想要呈现的矩形广告牌的四个顶点。它们的作用是移动顶点相对于屏幕,然后也可以提供上面使用的那种子地图的纹理坐标。我使用这些值来为我的球体世代进行光线跟踪计算,但是您可以忽略它的那部分。

+0

感谢我欣赏它的答案。我真的想知道如何做到这一点,从我的ModelView矩阵开始。我需要做些什么才能让广告牌正确绘制,以便在使用GLK4Matrices(但不使用着色器)与地球一起旋转时始终面对相机。 – PhilBot 2013-04-27 01:20:00