一個3D方向的變化例
參考資料
http://blog.csdn.net/kesalin/article/details/7168967
http://blog.csdn.net/kesalin/article/details/8271112
將原本的例子重新整理到新版的Xcode,並將角錐改成長方形以及加上Y方向的旋轉選項。
1. 首先開啓一個新的專案
2. 加入所需的Sliders/Buttons以及UIView到Storyboard,UIView作為OPENGL的演示區。
POSX/POSY的範圍 3 ~ -3 default 0.5
POSZ 的範圍 -10 ~ -1 default -5.5
ScaleZ 範圍 2 ~ 0.5 default 1
RotateX/RotateY 範圍 -180 ~180 default 0
3.加入所需的Framework,新增OpenGLES及QuartzCore這兩個
4. 首先加入utils的class,此處做為載入Shader之用,繼承自NSObject
GLESUtils.h
#import <Foundation/Foundation.h>
#include <OpenGLES/ES2/gl.h>
@interface GLESUtils :
NSObject
// Create a shader object, load the shader source string, and compile the shader.
//
+(GLuint)loadShader:(GLenum)type withString:(NSString *)shaderString;
+(GLuint)loadShader:(GLenum)type withFilepath:(NSString *)shaderFilepath;
//
///
/// Load a vertex and fragment shader, create a program object, link program.
/// Errors output to log.
/// vertexShaderFilepath Vertex shader source file path.
/// fragmentShaderFilepath Fragment shader source file path
/// return A new program object linked with the vertex/fragment shader pair, 0 on failure
//
+(GLuint)loadProgram:(NSString *)vertexShaderFilepath withFragmentShaderFilepath:(NSString *)fragmentShaderFilepath;
@end
及
GLESUtils.m
#import "GLESUtils.h"
@implementation GLESUtils
+(GLuint)loadShader:(GLenum)type withFilepath:(NSString *)shaderFilepath
{
NSError* error;
NSString* shaderString = [NSString stringWithContentsOfFile:shaderFilepath
encoding:NSUTF8StringEncoding
error:&error];
if (!shaderString) {
NSLog(@"Error: loading shader file: %@ %@", shaderFilepath, error.localizedDescription);
return 0;
}
return [self loadShader:type withString:shaderString];
}
+(GLuint)loadShader:(GLenum)type withString:(NSString *)shaderString
{
// Create the shader object
GLuint shader = glCreateShader(type);
if (shader == 0) {
NSLog(@"Error: failed to create shader.");
return 0;
}
// Load the shader source
const char * shaderStringUTF8 = [shaderString UTF8String];
glShaderSource(shader, 1, &shaderStringUTF8, NULL);
// Compile the shader
glCompileShader(shader);
// Check the compile status
GLint compiled = 0;
glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
if (!compiled) {
GLint infoLen = 0;
glGetShaderiv ( shader, GL_INFO_LOG_LENGTH, &infoLen );
if (infoLen > 1) {
char * infoLog = malloc(sizeof(char) * infoLen);
glGetShaderInfoLog (shader, infoLen, NULL, infoLog);
NSLog(@"Error compiling shader:\n%s\n", infoLog );
free(infoLog);
}
glDeleteShader(shader);
return 0;
}
return shader;
}
+(GLuint)loadProgram:(NSString *)vertexShaderFilepath withFragmentShaderFilepath:(NSString *)fragmentShaderFilepath
{
// Load the vertex/fragment shaders
GLuint vertexShader = [self loadShader:GL_VERTEX_SHADER
withFilepath:vertexShaderFilepath];
if (vertexShader == 0)
return 0;
GLuint fragmentShader = [self loadShader:GL_FRAGMENT_SHADER
withFilepath:fragmentShaderFilepath];
if (fragmentShader == 0) {
glDeleteShader(vertexShader);
return 0;
}
// Create the program object
GLuint programHandle = glCreateProgram();
if (programHandle == 0)
return 0;
glAttachShader(programHandle, vertexShader);
glAttachShader(programHandle, fragmentShader);
// Link the program
glLinkProgram(programHandle);
// Check the link status
GLint linked;
glGetProgramiv(programHandle, GL_LINK_STATUS, &linked);
if (!linked) {
GLint infoLen = 0;
glGetProgramiv(programHandle, GL_INFO_LOG_LENGTH, &infoLen);
if (infoLen > 1){
char * infoLog = malloc(sizeof(char) * infoLen);
glGetProgramInfoLog(programHandle, infoLen, NULL, infoLog);
NSLog(@"Error linking program:\n%s\n", infoLog);
free(infoLog);
}
glDeleteProgram(programHandle );
return 0;
}
// Free up no longer needed shader resources
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
return programHandle;
}
@end
5. 加入矩陣運算的C Code
ksMatrix.c
#include "ksMatrix.h"
#include <stdlib.h>
#include <math.h>
void * memcpy(void *, const void *, size_t);
void * memset(void *, int, size_t);
unsigned int ksNextPot(unsigned int n)
{
n--;
n |= n >> 1; n |= n >> 2;
n |= n >> 4; n |= n >> 8;
n |= n >> 16;
n++;
return n;
}
//
// Matrix math utility
//
void ksMatrixScale(ksMatrix4 * result, float sx, float sy, float sz)
{
result->m[0][0] *= sx;
result->m[0][1] *= sx;
result->m[0][2] *= sx;
result->m[0][3] *= sx;
result->m[1][0] *= sy;
result->m[1][1] *= sy;
result->m[1][2] *= sy;
result->m[1][3] *= sy;
result->m[2][0] *= sz;
result->m[2][1] *= sz;
result->m[2][2] *= sz;
result->m[2][3] *= sz;
}
void ksMatrixTranslate(ksMatrix4 * result, float tx, float ty, float tz)
{
result->m[3][0] += (result->m[0][0] * tx + result->m[1][0] * ty + result->m[2][0] * tz);
result->m[3][1] += (result->m[0][1] * tx + result->m[1][1] * ty + result->m[2][1] * tz);
result->m[3][2] += (result->m[0][2] * tx + result->m[1][2] * ty + result->m[2][2] * tz);
result->m[3][3] += (result->m[0][3] * tx + result->m[1][3] * ty + result->m[2][3] * tz);
}
void ksMatrixRotate(ksMatrix4 * result, float angle, float x, float y, float z)
{
float sinAngle, cosAngle;
float mag = sqrtf(x * x + y * y + z * z);
sinAngle = sinf ( angle * M_PI / 180.0f );
cosAngle = cosf ( angle * M_PI / 180.0f );
if ( mag > 0.0f )
{
float xx, yy, zz, xy, yz, zx, xs, ys, zs;
float oneMinusCos;
ksMatrix4 rotMat;
x /= mag;
y /= mag;
z /= mag;
xx = x * x;
yy = y * y;
zz = z * z;
xy = x * y;
yz = y * z;
zx = z * x;
xs = x * sinAngle;
ys = y * sinAngle;
zs = z * sinAngle;
oneMinusCos = 1.0f - cosAngle;
rotMat.m[0][0] = (oneMinusCos * xx) + cosAngle;
rotMat.m[0][1] = (oneMinusCos * xy) - zs;
rotMat.m[0][2] = (oneMinusCos * zx) + ys;
rotMat.m[0][3] = 0.0F;
rotMat.m[1][0] = (oneMinusCos * xy) + zs;
rotMat.m[1][1] = (oneMinusCos * yy) + cosAngle;
rotMat.m[1][2] = (oneMinusCos * yz) - xs;
rotMat.m[1][3] = 0.0F;
rotMat.m[2][0] = (oneMinusCos * zx) - ys;
rotMat.m[2][1] = (oneMinusCos * yz) + xs;
rotMat.m[2][2] = (oneMinusCos * zz) + cosAngle;
rotMat.m[2][3] = 0.0F;
rotMat.m[3][0] = 0.0F;
rotMat.m[3][1] = 0.0F;
rotMat.m[3][2] = 0.0F;
rotMat.m[3][3] = 1.0F;
ksMatrixMultiply( result, &rotMat, result );
}
}
// result[x][y] = a[x][0]*b[0][y]+a[x][1]*b[1][y]+a[x][2]*b[2][y]+a[x][3]*b[3][y];
void ksMatrixMultiply(ksMatrix4 * result, const ksMatrix4 *a, const ksMatrix4 *b)
{
ksMatrix4 tmp;
int i;
for (i = 0; i < 4; i++)
{
tmp.m[i][0] = (a->m[i][0] * b->m[0][0]) +
(a->m[i][1] * b->m[1][0]) +
(a->m[i][2] * b->m[2][0]) +
(a->m[i][3] * b->m[3][0]) ;
tmp.m[i][1] = (a->m[i][0] * b->m[0][1]) +
(a->m[i][1] * b->m[1][1]) +
(a->m[i][2] * b->m[2][1]) +
(a->m[i][3] * b->m[3][1]) ;
tmp.m[i][2] = (a->m[i][0] * b->m[0][2]) +
(a->m[i][1] * b->m[1][2]) +
(a->m[i][2] * b->m[2][2]) +
(a->m[i][3] * b->m[3][2]) ;
tmp.m[i][3] = (a->m[i][0] * b->m[0][3]) +
(a->m[i][1] * b->m[1][3]) +
(a->m[i][2] * b->m[2][3]) +
(a->m[i][3] * b->m[3][3]) ;
}
memcpy(result, &tmp, sizeof(ksMatrix4));
}
void ksMatrixDotVector(ksVec4 * out, const ksMatrix4 * m, const ksVec4 * v)
{
out->x = m->m[0][0] * v->x + m->m[0][1] * v->y + m->m[0][2] * v->z + m->m[0][3] * v->w;
out->y = m->m[1][0] * v->x + m->m[1][1] * v->y + m->m[1][2] * v->z + m->m[1][3] * v->w;
out->z = m->m[2][0] * v->x + m->m[2][1] * v->y + m->m[2][2] * v->z + m->m[2][3] * v->w;
out->w = m->m[3][0] * v->x + m->m[3][1] * v->y + m->m[3][2] * v->z + m->m[3][3] * v->w;
}
void ksMatrixCopy(ksMatrix4 * target, const ksMatrix4 * src)
{
memcpy(target, src, sizeof(ksMatrix4));
}
int ksMatrixInvert(ksMatrix4 * out, const ksMatrix4 * in)
{
float * m = (float *)(&in->m[0][0]);
float * om = (float *)(&out->m[0][0]);
double inv[16], det;
int i;
inv[0] = m[5] * m[10] * m[15] -
m[5] * m[11] * m[14] -
m[9] * m[6] * m[15] +
m[9] * m[7] * m[14] +
m[13] * m[6] * m[11] -
m[13] * m[7] * m[10];
inv[4] = -m[4] * m[10] * m[15] +
m[4] * m[11] * m[14] +
m[8] * m[6] * m[15] -
m[8] * m[7] * m[14] -
m[12] * m[6] * m[11] +
m[12] * m[7] * m[10];
inv[8] = m[4] * m[9] * m[15] -
m[4] * m[11] * m[13] -
m[8] * m[5] * m[15] +
m[8] * m[7] * m[13] +
m[12] * m[5] * m[11] -
m[12] * m[7] * m[9];
inv[12] = -m[4] * m[9] * m[14] +
m[4] * m[10] * m[13] +
m[8] * m[5] * m[14] -
m[8] * m[6] * m[13] -
m[12] * m[5] * m[10] +
m[12] * m[6] * m[9];
inv[1] = -m[1] * m[10] * m[15] +
m[1] * m[11] * m[14] +
m[9] * m[2] * m[15] -
m[9] * m[3] * m[14] -
m[13] * m[2] * m[11] +
m[13] * m[3] * m[10];
inv[5] = m[0] * m[10] * m[15] -
m[0] * m[11] * m[14] -
m[8] * m[2] * m[15] +
m[8] * m[3] * m[14] +
m[12] * m[2] * m[11] -
m[12] * m[3] * m[10];
inv[9] = -m[0] * m[9] * m[15] +
m[0] * m[11] * m[13] +
m[8] * m[1] * m[15] -
m[8] * m[3] * m[13] -
m[12] * m[1] * m[11] +
m[12] * m[3] * m[9];
inv[13] = m[0] * m[9] * m[14] -
m[0] * m[10] * m[13] -
m[8] * m[1] * m[14] +
m[8] * m[2] * m[13] +
m[12] * m[1] * m[10] -
m[12] * m[2] * m[9];
inv[2] = m[1] * m[6] * m[15] -
m[1] * m[7] * m[14] -
m[5] * m[2] * m[15] +
m[5] * m[3] * m[14] +
m[13] * m[2] * m[7] -
m[13] * m[3] * m[6];
inv[6] = -m[0] * m[6] * m[15] +
m[0] * m[7] * m[14] +
m[4] * m[2] * m[15] -
m[4] * m[3] * m[14] -
m[12] * m[2] * m[7] +
m[12] * m[3] * m[6];
inv[10] = m[0] * m[5] * m[15] -
m[0] * m[7] * m[13] -
m[4] * m[1] * m[15] +
m[4] * m[3] * m[13] +
m[12] * m[1] * m[7] -
m[12] * m[3] * m[5];
inv[14] = -m[0] * m[5] * m[14] +
m[0] * m[6] * m[13] +
m[4] * m[1] * m[14] -
m[4] * m[2] * m[13] -
m[12] * m[1] * m[6] +
m[12] * m[2] * m[5];
inv[3] = -m[1] * m[6] * m[11] +
m[1] * m[7] * m[10] +
m[5] * m[2] * m[11] -
m[5] * m[3] * m[10] -
m[9] * m[2] * m[7] +
m[9] * m[3] * m[6];
inv[7] = m[0] * m[6] * m[11] -
m[0] * m[7] * m[10] -
m[4] * m[2] * m[11] +
m[4] * m[3] * m[10] +
m[8] * m[2] * m[7] -
m[8] * m[3] * m[6];
inv[11] = -m[0] * m[5] * m[11] +
m[0] * m[7] * m[9] +
m[4] * m[1] * m[11] -
m[4] * m[3] * m[9] -
m[8] * m[1] * m[7] +
m[8] * m[3] * m[5];
inv[15] = m[0] * m[5] * m[10] -
m[0] * m[6] * m[9] -
m[4] * m[1] * m[10] +
m[4] * m[2] * m[9] +
m[8] * m[1] * m[6] -
m[8] * m[2] * m[5];
det = m[0] * inv[0] + m[1] * inv[4] + m[2] * inv[8] + m[3] * inv[12];
if (det == 0)
return 0;
det = 1.0 / det;
for (i = 0; i < 16; i++)
*om++ = (float)(inv[i] * det);
return 1;
}
void ksMatrixTranspose(ksMatrix4 * result, const ksMatrix4 * src)
{
ksMatrix4 tmp;
tmp.m[0][0] = src->m[0][0];
tmp.m[0][1] = src->m[1][0];
tmp.m[0][2] = src->m[2][0];
tmp.m[0][3] = src->m[3][0];
tmp.m[1][0] = src->m[0][1];
tmp.m[1][1] = src->m[1][1];
tmp.m[1][2] = src->m[2][1];
tmp.m[1][3] = src->m[3][1];
tmp.m[2][0] = src->m[0][2];
tmp.m[2][1] = src->m[1][2];
tmp.m[2][2] = src->m[2][2];
tmp.m[2][3] = src->m[3][2];
tmp.m[3][0] = src->m[0][3];
tmp.m[3][1] = src->m[1][3];
tmp.m[3][2] = src->m[2][3];
tmp.m[3][3] = src->m[3][3];
memcpy(result, &tmp, sizeof(ksMatrix4));
}
void ksMatrix4ToMatrix3(ksMatrix3 * result, const ksMatrix4 * src)
{
result->m[0][0] = src->m[0][0];
result->m[0][1] = src->m[0][1];
result->m[0][2] = src->m[0][2];
result->m[1][0] = src->m[1][0];
result->m[1][1] = src->m[1][1];
result->m[1][2] = src->m[1][2];
result->m[2][0] = src->m[2][0];
result->m[2][1] = src->m[2][1];
result->m[2][2] = src->m[2][2];
}
void ksMatrixLoadIdentity(ksMatrix4 * result)
{
memset(result, 0x0, sizeof(ksMatrix4));
result->m[0][0] = 1.0f;
result->m[1][1] = 1.0f;
result->m[2][2] = 1.0f;
result->m[3][3] = 1.0f;
}
void ksFrustum(ksMatrix4 * result, float left, float right, float bottom, float top, float nearZ, float farZ)
{
float deltaX = right - left;
float deltaY = top - bottom;
float deltaZ = farZ - nearZ;
ksMatrix4 frust;
if ( (nearZ <= 0.0f) || (farZ <= 0.0f) ||
(deltaX <= 0.0f) || (deltaY <= 0.0f) || (deltaZ <= 0.0f) )
return;
frust.m[0][0] = 2.0f * nearZ / deltaX;
frust.m[0][1] = frust.m[0][2] = frust.m[0][3] = 0.0f;
frust.m[1][1] = 2.0f * nearZ / deltaY;
frust.m[1][0] = frust.m[1][2] = frust.m[1][3] = 0.0f;
frust.m[2][0] = (right + left) / deltaX;
frust.m[2][1] = (top + bottom) / deltaY;
frust.m[2][2] = -(nearZ + farZ) / deltaZ;
frust.m[2][3] = -1.0f;
frust.m[3][2] = -2.0f * nearZ * farZ / deltaZ;
frust.m[3][0] = frust.m[3][1] = frust.m[3][3] = 0.0f;
ksMatrixMultiply(result, &frust, result);
}
void ksPerspective(ksMatrix4 * result, float fovy, float aspect, float nearZ, float farZ)
{
float frustumW, frustumH;
frustumH = tanf( fovy / 360.0f * M_PI ) * nearZ;
frustumW = frustumH * aspect;
ksFrustum(result, -frustumW, frustumW, -frustumH, frustumH, nearZ, farZ);
}
void ksOrtho(ksMatrix4 * result, float left, float right, float bottom, float top, float nearZ, float farZ)
{
float deltaX = right - left;
float deltaY = top - bottom;
float deltaZ = farZ - nearZ;
ksMatrix4 ortho;
if ((deltaX == 0.0f) || (deltaY == 0.0f) || (deltaZ == 0.0f))
return;
ksMatrixLoadIdentity(&ortho);
ortho.m[0][0] = 2.0f / deltaX;
ortho.m[3][0] = -(right + left) / deltaX;
ortho.m[1][1] = 2.0f / deltaY;
ortho.m[3][1] = -(top + bottom) / deltaY;
ortho.m[2][2] = -2.0f / deltaZ;
ortho.m[3][2] = -(nearZ + farZ) / deltaZ;
ksMatrixMultiply(result, &ortho, result);
}
void ksLookAt(ksMatrix4 * result, const ksVec3 * eye, const ksVec3 * target, const ksVec3 * up)
{
ksVec3 side, up2, forward ;
//ksVec4 eyePrime;
ksMatrix4 transMat;
ksVectorSubtract(&forward, target, eye);
ksVectorNormalize(&forward);
ksCrossProduct(&side, up, &forward);
ksVectorNormalize(&side );
ksCrossProduct(&up2, &side, &forward);
ksVectorNormalize(&up2);
ksMatrixLoadIdentity(result);
result->m[0][0] = side.x;
result->m[0][1] = side.y;
result->m[0][2] = side.z;
result->m[1][0] = up2.x;
result->m[1][1] = up2.y;
result->m[1][2] = up2.z;
result->m[2][0] = -forward.x;
result->m[2][1] = -forward.y;
result->m[2][2] = -forward.z;
ksMatrixLoadIdentity(&transMat);
ksMatrixTranslate(&transMat, -eye->x, -eye->y, -eye->z);
ksMatrixMultiply(result, result, &transMat);
//eyePrime.x = -eye->x;
//eyePrime.y = -eye->y;
//eyePrime.z = -eye->z;
//eyePrime.w = 1;
//ksMatrixMultiplyVector(&eyePrime, result, &eyePrime);
//ksMatrixTranspose(result, result);
//result->m[3][0] = eyePrime.x;
//result->m[3][1] = eyePrime.y;
//result->m[3][2] = eyePrime.z;
//result->m[3][3] = eyePrime.w;
}
及
ksMatrix.h
#ifndef __KS_MATRIX_H__
#define __KS_MATRIX_H__
#include <math.h>
#include "ksVector.h"
#ifndef M_PI
#define M_PI 3.1415926535897932384626433832795f
#endif
#define DEG2RAD( a ) (((a) * M_PI) / 180.0f)
#define RAD2DEG( a ) (((a) * 180.f) / M_PI)
// angle indexes
#define PITCH 0 // up / down
#define YAW 1 // left / right
#define ROLL 2 // fall over
typedef struct ksMatrix3
{
float m[3][3];
} ksMatrix3;
typedef struct ksMatrix4
{
float m[4][4];
} ksMatrix4;
#ifdef __cplusplus
extern "C" {
#endif
unsigned int ksNextPot(unsigned int n);
void ksMatrixCopy(ksMatrix4 * target, const ksMatrix4 * src);
int ksMatrixInvert(ksMatrix4 * out, const ksMatrix4 * in);
void ksMatrixTranspose(ksMatrix4 * result, const ksMatrix4 * src);
void ksMatrix4ToMatrix3(ksMatrix3 * target, const ksMatrix4 * src);
void ksMatrixDotVector(ksVec4 * out, const ksMatrix4 * m, const ksVec4 * v);
//
/// multiply matrix specified by result with a scaling matrix and return new matrix in result
/// result Specifies the input matrix. Scaled matrix is returned in result.
/// sx, sy, sz Scale factors along the x, y and z axes respectively
//
void ksMatrixScale(ksMatrix4 * result, float sx, float sy, float sz);
//
/// multiply matrix specified by result with a translation matrix and return new matrix in result
/// result Specifies the input matrix. Translated matrix is returned in result.
/// tx, ty, tz Scale factors along the x, y and z axes respectively
//
void ksMatrixTranslate(ksMatrix4 * result, float tx, float ty, float tz);
//
/// multiply matrix specified by result with a rotation matrix and return new matrix in result
/// result Specifies the input matrix. Rotated matrix is returned in result.
/// angle Specifies the angle of rotation, in degrees.
/// x, y, z Specify the x, y and z coordinates of a vector, respectively
//
void ksMatrixRotate(ksMatrix4 * result, float angle, float x, float y, float z);
//
/// perform the following operation - result matrix = srcA matrix * srcB matrix
/// result Returns multiplied matrix
/// srcA, srcB Input matrices to be multiplied
//
void ksMatrixMultiply(ksMatrix4 * result, const ksMatrix4 *srcA, const ksMatrix4 *srcB);
//
//// return an identity matrix
//// result returns identity matrix
//
void ksMatrixLoadIdentity(ksMatrix4 * result);
//
/// multiply matrix specified by result with a perspective matrix and return new matrix in result
/// result Specifies the input matrix. new matrix is returned in result.
/// fovy Field of view y angle in degrees
/// aspect Aspect ratio of screen
/// nearZ Near plane distance
/// farZ Far plane distance
//
void ksPerspective(ksMatrix4 * result, float fovy, float aspect, float nearZ, float farZ);
//
/// multiply matrix specified by result with a perspective matrix and return new matrix in result
/// result Specifies the input matrix. new matrix is returned in result.
/// left, right Coordinates for the left and right vertical clipping planes
/// bottom, top Coordinates for the bottom and top horizontal clipping planes
/// nearZ, farZ Distances to the near and far depth clipping planes. These values are negative if plane is behind the viewer
//
void ksOrtho(ksMatrix4 * result, float left, float right, float bottom, float top, float nearZ, float farZ);
//
// multiply matrix specified by result with a perspective matrix and return new matrix in result
/// result Specifies the input matrix. new matrix is returned in result.
/// left, right Coordinates for the left and right vertical clipping planes
/// bottom, top Coordinates for the bottom and top horizontal clipping planes
/// nearZ, farZ Distances to the near and far depth clipping planes. Both distances must be positive.
//
void ksFrustum(ksMatrix4 * result, float left, float right, float bottom, float top, float nearZ, float farZ);
void ksLookAt(ksMatrix4 * result, const ksVec3 * eye, const ksVec3 * target, const ksVec3 * up);
#ifdef __cplusplus
}
#endif
#endif // __KS_MATRIX_H__
6. 加入矩陣運算所需要的向量運算函數碼
ksVector.c
#include "ksVector.h"
#include <math.h>
void ksVectorCopy(ksVec3 * out, const ksVec3 * in)
{
out->x = in->x;
out->y = in->y;
out->z = in->z;
}
void ksVectorAdd(ksVec3 * out, const ksVec3 * a, const ksVec3 * b)
{
out->x = a->x + b->x;
out->y = a->y + b->y;
out->z = a->z + b->z;
}
void ksVectorSubtract(ksVec3 * out, const ksVec3 * a, const ksVec3 * b)
{
out->x = a->x - b->x;
out->y = a->y - b->y;
out->z = a->z - b->z;
}
void ksCrossProduct(ksVec3 * out, const ksVec3 * a, const ksVec3 * b)
{
out->x = a->y * b->z - a->z * b->y;
out->y = a->z * b->x - a->x * b->z;
out->z = a->x * b->y - b->y * a->x;
}
float ksDotProduct(const ksVec3 * a, const ksVec3 * b)
{
return (a->x * b->x + a->y * b->y + a->z * b->z);
}
void ksVectorLerp(ksVec3 * out, const ksVec3 * a, const ksVec3 * b, float t)
{
out->x = (a->x * (1 - t) + b->x * t);
out->y = (a->y * (1 - t) + b->y * t);
out->z = (a->z * (1 - t) + b->z * t);
}
void ksVectorScale(ksVec3 * v, float scale)
{
v->x *= scale;
v->y *= scale;
v->z *= scale;
}
void ksVectorInverse(ksVec3 * v)
{
v->x = -v->x;
v->y = -v->y;
v->z = -v->z;
}
void ksVectorNormalize(ksVec3 * v)
{
float length = ksVectorLength(v);
if (length != 0)
{
length = 1.0 / length;
v->x *= length;
v->y *= length;
v->z *= length;
}
}
int ksVectorCompare(const ksVec3 * a, const ksVec3 * b)
{
if (a == b)
return 1;
if (a->x != b->x || a->y != b->y || a->z != b->z)
return 0;
return 1;
}
float ksVectorLength(const ksVec3 * in)
{
return (float)sqrt(in->x * in->x + in->y * in->y + in->z * in->z);
}
float ksVectorLengthSquared(const ksVec3 * in)
{
return (in->x * in->x + in->y * in->y + in->z * in->z);
}
float ksVectorDistance(const ksVec3 * a, const ksVec3 * b)
{
ksVec3 v;
ksVectorSubtract(&v, a, b);
return ksVectorLength(&v);
}
float ksVectorDistanceSquared(const ksVec3 * a, const ksVec3 * b)
{
ksVec3 v;
ksVectorSubtract(&v, a, b);
return (v.x * v.x + v.y * v.y + v.z * v.z);
}
及
ksVector.h
#ifndef __KS_VECTOR_H__
#define __KS_VECTOR_H__
typedef struct
{
float x;
float y;
float z;
} ksVec3;
typedef struct
{
float x;
float y;
float z;
float w;
} ksVec4;
typedef struct
{
float r;
float g;
float b;
float a;
} ksColor;
typedef unsigned char byte;
#ifdef __cplusplus
extern "C" {
#endif
void ksVectorCopy(ksVec3 * out, const ksVec3 * in);
void ksVectorAdd(ksVec3 * out, const ksVec3 * a, const ksVec3 * b);
void ksVectorSubtract(ksVec3 * out, const ksVec3 * a, const ksVec3 * b);
void ksVectorLerp(ksVec3 * out, const ksVec3 * a, const ksVec3 * b, float t);
void ksCrossProduct(ksVec3 * out, const ksVec3 * a, const ksVec3 * b);
float ksDotProduct(const ksVec3 * a, const ksVec3 * b);
float ksVectorLengthSquared(const ksVec3 * in);
float ksVectorDistanceSquared(const ksVec3 * a, const ksVec3 * b);
void ksVectorScale(ksVec3 * v, float scale);
void ksVectorNormalize(ksVec3 * v);
void ksVectorInverse(ksVec3 * v);
int ksVectorCompare(const ksVec3 * a, const ksVec3 * b);
float ksVectorLength(const ksVec3 * in);
float ksVectorDistance(const ksVec3 * a, const ksVec3 * b);
#ifdef __cplusplus
}
#endif
#endif //__KS_VECTOR_H__
7. 加入OPENGL 的程式碼,首先要新增一個UIView的Class,因為要顯示在其中。
OpenGLView.h
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
#include <OpenGLES/ES2/gl.h>
#include <OpenGLES/ES2/glext.h>
#include "ksMatrix.h"
@interface OpenGLView : UIView
{
CAEAGLLayer* _eaglLayer;
EAGLContext* _context;
GLuint _colorRenderBuffer;
GLuint _frameBuffer;
GLuint _programHandle;
GLuint _positionSlot;
GLint _modelViewSlot;
GLint _projectionSlot;
ksMatrix4 _modelViewMatrix;
ksMatrix4 _projectionMatrix;
float _posX;
float _posY;
float _posZ;
float _rotateX;
float _scaleZ;
float _rotateY;
}
@property (nonatomic, assign) float posX;
@property (nonatomic, assign) float posY;
@property (nonatomic, assign) float posZ;
@property (nonatomic, assign) float scaleZ;
@property (nonatomic, assign) float rotateX;
@property (nonatomic, assign) float rotateY;
- (void)resetTransform;
- (void)render;
- (void)cleanup;
- (void)toggleDisplayLink;
@end
8. OpenGLView.m
#import "OpenGLView.h"
#import "GLESUtils.h"
@interface OpenGLView()
{
CADisplayLink * _displayLink;
}
- (void)setupLayer;
- (void)setupContext;
- (void)setupBuffers;
- (void)destoryBuffers;
- (void)setupProgram;
- (void)setupProjection;
- (void)updateTransform;
- (void)displayLinkCallback:(CADisplayLink*)displayLink;
@end
@implementation OpenGLView
@synthesize posX = _posX;
@synthesize posY = _posY;
@synthesize posZ = _posZ;
@synthesize scaleZ = _scaleZ;
@synthesize rotateX = _rotateX;
@synthesize rotateY = _rotateY;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
+ (Class)layerClass {
// 只有 [CAEAGLLayer class] 类型的 layer 才支持在其上描绘 OpenGL 内容。
return [CAEAGLLayer class];
}
- (void)setupLayer
{
_eaglLayer = (CAEAGLLayer*) self.layer;
// CALayer 默认是透明的,必须将它设为不透明才能让其可见
_eaglLayer.opaque = YES;
// 设置描绘属性,在这里设置不维持渲染内容以及颜色格式为 RGBA8
_eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:NO], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];
}
- (void)setupContext {
// 指定 OpenGL 渲染 API 的版本,在这里我们使用 OpenGL ES 2.0
EAGLRenderingAPI api = kEAGLRenderingAPIOpenGLES2;
_context = [[EAGLContext alloc] initWithAPI:api];
if (!_context) {
NSLog(@" >> Error: Failed to initialize OpenGLES 2.0 context");
exit(1);
}
// 设置为当前上下文
if (![EAGLContext setCurrentContext:_context]) {
_context = nil;
NSLog(@" >> Error: Failed to set current OpenGL context");
exit(1);
}
}
- (void)setupBuffers {
glGenRenderbuffers(1, &_colorRenderBuffer);
// 设置为当前 renderbuffer
glBindRenderbuffer(GL_RENDERBUFFER, _colorRenderBuffer);
// 为 color renderbuffer 分配存储空间
[_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:_eaglLayer];
glGenFramebuffers(1, &_frameBuffer);
// 设置为当前 framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, _frameBuffer);
// 将 _colorRenderBuffer 装配到 GL_COLOR_ATTACHMENT0 这个装配点上
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_RENDERBUFFER, _colorRenderBuffer);
}
- (void)destoryBuffers
{
glDeleteRenderbuffers(1, &_colorRenderBuffer);
_colorRenderBuffer = 0;
glDeleteFramebuffers(1, &_frameBuffer);
_frameBuffer = 0;
}
- (void)cleanup
{
[self destoryBuffers];
if (_programHandle != 0) {
glDeleteProgram(_programHandle);
_programHandle = 0;
}
if (_context && [EAGLContext currentContext] == _context)
[EAGLContext setCurrentContext:nil];
_context = nil;
}
- (void)setupProgram
{
// Load shaders
//
NSString * vertexShaderPath = [[NSBundle mainBundle] pathForResource:@"VertexShader"
ofType:@"glsl"];
NSString * fragmentShaderPath = [[NSBundle mainBundle] pathForResource:@"FragmentShader"
ofType:@"glsl"];
_programHandle = [GLESUtils loadProgram:vertexShaderPath
withFragmentShaderFilepath:fragmentShaderPath];
if (_programHandle == 0) {
NSLog(@" >> Error: Failed to setup program.");
return;
}
glUseProgram(_programHandle);
// Get the attribute position slot from program
//
_positionSlot = glGetAttribLocation(_programHandle, "vPosition");
// Get the uniform model-view matrix slot from program
//
_modelViewSlot = glGetUniformLocation(_programHandle, "modelView");
// Get the uniform projection matrix slot from program
//
_projectionSlot = glGetUniformLocation(_programHandle, "projection");
}
-(void)setupProjection
{
// Generate a perspective matrix with a 60 degree FOV
//
float aspect = self.frame.size.width / self.frame.size.height;
ksMatrixLoadIdentity(&_projectionMatrix);
ksPerspective(&_projectionMatrix, 60.0, aspect, 1.0f, 20.0f);
// Load projection matrix
glUniformMatrix4fv(_projectionSlot, 1, GL_FALSE, (GLfloat*)&_projectionMatrix.m[0][0]);
}
- (void)updateTransform
{
// Generate a model view matrix to rotate/translate/scale
//
ksMatrixLoadIdentity(&_modelViewMatrix);
// Translate away from the viewer
//
ksMatrixTranslate(&_modelViewMatrix, self.posX, self.posY, self.posZ);
// Rotate the triangle
//
ksMatrixRotate(&_modelViewMatrix, self.rotateX, 1.0, 0.0, 0.0); // rotate X
ksMatrixRotate(&_modelViewMatrix, self.rotateY, 0.0, 1.0, 0.0); // rotate Y
// Scale the triangle
ksMatrixScale(&_modelViewMatrix, 1.0, 1.0, self.scaleZ);
// Load the model-view matrix
glUniformMatrix4fv(_modelViewSlot, 1, GL_FALSE, (GLfloat*)&_modelViewMatrix.m[0][0]);
}
- (void)drawTriangle
{
GLfloat vertices[] = {
0.0f, 0.7f, 0.0f,
-0.7f, -0.7f, 0.0f,
0.7f, -0.7f, 0.0f };
glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, 0, vertices );
glEnableVertexAttribArray(_positionSlot);
// Draw triangle
//
glDrawArrays(GL_TRIANGLES, 0, 3);
}
- (void)drawTriCone
{
GLfloat vertices[] = {
0.7f, 0.7f, 0.0f,
0.7f, -0.7f, 0.0f,
-0.7f, -0.7f, 0.0f,
-0.7f, 0.7f, 0.0f,
0.0f, 0.0f, -1.0f,
};
GLubyte indices[] = {
0, 1, 1, 2, 2, 3, 3, 0,
4, 0, 4, 1, 4, 2, 4, 3
};
glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, 0, vertices );
glEnableVertexAttribArray(_positionSlot);
// Draw lines
//
glDrawElements(GL_LINES, sizeof(indices)/sizeof(GLubyte), GL_UNSIGNED_BYTE, indices);
}
- (void)drawCube //方塊設定
{
GLfloat vertices[] = {
0.7f, 0.7f, 0.0f, // point 0
0.7f, -0.7f, 0.0f, // point 1
-0.7f, -0.7f, 0.0f,
-0.7f, 0.7f, 0.0f,
0.7f, 0.7f, -2.0f,
0.7f, -0.7f, -2.0f,
-0.7f, -0.7f, -2.0f,
-0.7f, 0.7f, -2.0f, // point 7
};
GLubyte indices[] = { // 此處為兩兩一組,設定點與點之間的連線
0, 1, 1, 2, 2, 3, 3, 0,
4, 0, 4,5, 5,1 , 6,2, 5,6 , 6,7, 7,4 ,7,3
};
glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, 0, vertices );
glEnableVertexAttribArray(_positionSlot);
// Draw lines
glDrawElements(GL_LINES, sizeof(indices)/sizeof(GLubyte), GL_UNSIGNED_BYTE, indices);
}
- (void)render
{
if (_context == nil)
return;
glClearColor(0, 1.0, 0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
// Setup viewport
//
glViewport(0, 0, self.frame.size.width, self.frame.size.height);
//[self drawTriangle];
//[self drawTriCone];
[self drawCube];
[_context presentRenderbuffer:GL_RENDERBUFFER];
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) {
[self setupLayer];
[self setupContext];
[self setupProgram];
[self setupProjection];
[self resetTransform];
}
return self;
}
- (void)layoutSubviews
{
[EAGLContext setCurrentContext:_context];
glUseProgram(_programHandle);
[self destoryBuffers];
[self setupBuffers];
[self updateTransform];
[self render];
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
#pragma mark - Transform properties
- (void)toggleDisplayLink
{
if (_displayLink == nil) {
_displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkCallback:)];
[_displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}
else {
[_displayLink invalidate];
[_displayLink removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
_displayLink = nil;
}
}
- (void)displayLinkCallback:(CADisplayLink*)displayLink
{
self.rotateX += displayLink.duration * 90;
// 每 1/60 秒 會加一次角度 (duration = 1/60)*90 = 1.5
}
- (void)resetTransform
{
if (_displayLink != nil) {
[_displayLink removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
_displayLink = nil;
}
_posX = 0.0;
_posY = 0.0;
_posZ = -5.5;
_scaleZ = 1.0;
_rotateX = 0.0;
_rotateY = 0.0;
[self updateTransform];
}
- (void)setPosX:(float)x
{
_posX = x;
[self updateTransform];
[self render];
}
- (float)posX
{
return _posX;
}
- (void)setPosY:(float)y
{
_posY = y;
[self updateTransform];
[self render];
}
- (float)posY
{
return _posY;
}
- (void)setPosZ:(float)z
{
_posZ = z;
[self updateTransform];
[self render];
}
- (float)posZ
{
return _posZ;
}
- (void)setScaleZ:(float)scaleZ
{
_scaleZ = scaleZ;
[self updateTransform];
[self render];
}
- (float)scaleZ
{
return _scaleZ;
}
- (void)setRotateX:(float)rotateX
{
_rotateX = rotateX;
[self updateTransform];
[self render];
}
- (float)rotateX
{
return _rotateX;
}
- (void)setRotateY:(float)rotateY
{
_rotateY = rotateY;
[self updateTransform];
[self render];
}
- (float)rotateY
{
return _rotateY;
}
#pragma mark
@end
9. 設定主要的運作檔 mainViewController.h,將Storyboard上的元件設定到此檔。
#import <UIKit/UIKit.h>
#import "OpenGLView.h"
@interface mainViewController : UIViewController
@property (strong, nonatomic) IBOutlet UIView *controlView; 最外圍的控制區
@property (strong, nonatomic) IBOutlet OpenGLView *openGLView; // OPENGL 顯示區
@property (strong, nonatomic) IBOutlet UISlider *posXSlider;
@property (strong, nonatomic) IBOutlet UISlider *posYSlider;
@property (strong, nonatomic) IBOutlet UISlider *posZSlider;
@property (strong, nonatomic) IBOutlet UISlider *scaleZSlider;
@property (strong, nonatomic) IBOutlet UISlider *rotateXSlider;
@property (strong, nonatomic) IBOutlet UISlider *rotateYSlider;
@end
10. 設定mainViewController.m,設定Slider/Button的控制碼,此處是改動較多的地方
#import "mainViewController.h"
@interface mainViewController ()
@end
@implementation mainViewController
@synthesize posXSlider,posYSlider, posZSlider;
@synthesize scaleZSlider;
@synthesize rotateXSlider, rotateYSlider;
@synthesize openGLView;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self resetControls];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)posXChange:(id)sender {
openGLView.posX = posXSlider.value;
NSLog(@" >> current x is %f", posXSlider.value);
}
- (IBAction)posYChange:(id)sender {
openGLView.posY = posYSlider.value;
NSLog(@" >> current y is %f", posYSlider.value);
}
- (IBAction)posZChange:(id)sender {
openGLView.posZ = posZSlider.value;
NSLog(@" >> current z is %f", posZSlider.value);
}
- (IBAction)scaleZ:(id)sender {
openGLView.scaleZ = scaleZSlider.value;
NSLog(@" >> scale z is %3.3f", scaleZSlider.value);
}
- (IBAction)rotateX:(id)sender {
//rotateYSlider.value = 0;
// openGLView.rotateY = 0;
openGLView.rotateX = rotateXSlider.value;
NSLog(@" >> rotate x is %f", rotateXSlider.value);
}
- (IBAction)rotateY:(id)sender {
//rotateXSlider.value = 0;
// openGLView.rotateX = 0;
openGLView.rotateY = rotateYSlider.value;
NSLog(@" >> rotate Y is %f", rotateYSlider.value);
}
- (IBAction)autoButton:(id)sender {
[openGLView toggleDisplayLink];
UIButton * button = (UIButton *)sender;
NSString * text = button.titleLabel.text;
if ([text isEqualToString:@"Auto"]) {
[button setTitle: @"Stop" forState: UIControlStateNormal];
}
else {
[button setTitle: @"Auto" forState: UIControlStateNormal];
}
}
- (IBAction)resetButton:(id)sender {
[openGLView resetTransform];
[openGLView render];
[self resetControls];
}
- (void)resetControls
{
[posXSlider setValue:self.openGLView.posX];
[posYSlider setValue:self.openGLView.posY];
[posZSlider setValue:self.openGLView.posZ];
[scaleZSlider setValue:self.openGLView.scaleZ];
[rotateXSlider setValue:self.openGLView.rotateX];
}
@end
11. 加入兩個GLSL檔,
FragmentShader.glsl
precision mediump float;
void main()
{
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
VertexShader.glsl
uniform mat4 projection;
uniform mat4 modelView;
attribute vec4 vPosition;
void main(void)
{
gl_Position = projection * modelView * vPosition;
}
12 結果顯示