STEP 1 ( OpenGL Context initialization ) :
The first step that you are need for iOS OpenGL ES application will be creation of UIView Controller which contain EAGLContext property. Also you are need override "+ (Class) layerClass" method like this :
In the "initWithFrame" we are start initialize OpenGL context :
After that we are add event listener for "drawView" method :
The next step is initialization of the render buffers :
Properties of buffers :
The _fWidth and _fHeight properties are size of UIGLView.
And in the end we are add the next code int the "drawView" method :
STEP 2 ( Math Matrix, Vector ) :
Each OpenGL application must include Vector and Matrix structs. You can use third party math lib or develop your own lib. The minimal requirements of math lib something like this :
The minimal list of function with vector is :
The minimal list of function with matrix is :
STEP 3 ( Meshes VBO, IBO ) :
Vertex Buffer Objects (VBOs) are Buffer Objects that are used for vertex data. Since the storage for buffer objects is allocated by OpenGL, vertex buffer objects are a mechanism for storing vertex data in "fast" memory (i.e. video RAM or AGP RAM, and in the case of PCI Express, video RAM or RAM), thereby allowing for significant increases in vertex throughput between the application and the GPU.
The next code present creation of VBO object :
Note that when interleaving vertex attribute data some folks say there is gain to be had by aligning blocks of interleaved vertex data on 32-byte-aligned boundaries (keep in mind, there's nothing stopping you from inserting dead space into a VBO, if you're using the stride parameter to your pointer set calls).
The next code present creation of IBO object :
STEP 4 ( Textures PVRTC ) :
PVR file is a container for various texture format such as PVRTC, RGB and so forth. You can use directly these texture formats as is.
PVRTC is compressed texture format that is natively supported by GPU (PowerVR MBX or SGX). GPU can render PVRTC effectively. It would increase framerate.
glTexImage2D(GL_TEXTURE_2D, MIP_LEVEL, TEXTURE_FORMAT, Width, Height, 0, TEXTURE_FORMAT, TEXTURE_TYPE, pData);
STEP 5 ( Shaders GLSL ) :
Lighting vertex shader :
This is vertex shader will be use in all next samples of lighting.
Lambert lighting fragment shader :
Phong lighting fragment shader :
STEP 7 ( Non-realistic lighting Cell-Shading, Gooch, Rim Light ) :
Cell-Shading lighting fragment shader :
void main(void)
{
highp vec4 vDiffuseColor = vec4( 0.0, 0.0, 0.5, 1.0 );
highp float fDiffuseFactor = 0.2 + max ( dot ( OUT_Normal, OUT_Light ), 0.0 );
highp vec4 clr;
if ( fDiffuseFactor < 0.3 )
vDiffuseColor = vDiffuseColor * 0.1;
else
if ( fDiffuseFactor < 0.7 )
vDiffuseColor = vDiffuseColor * 0.5;
else
if ( fDiffuseFactor < 0.8 )
vDiffuseColor = vDiffuseColor;
else
vDiffuseColor = vDiffuseColor * 1.3;
gl_FragColor = vDiffuseColor;
}
Gooch lighting fragment shader :
void main(void)
{
highp vec3 vDiffuceColor = texture2D(EXT_TEXTURE_01, OUT_TexCoord).xyz;
highp vec3 vWarmColor = vec3 ( 0.6, 0.6, 0.0 );
highp vec3 vColdColor = vec3 ( 0.0, 0.0, 0.6 );
highp float fDiffuseWarm = 0.45;
highp float fDiffuseCold = 0.45;
highp vec3 vCold = min ( vColdColor + fDiffuseCold * vDiffuceColor, 1.0 );
highp vec3 vWarm = min ( vWarmColor + fDiffuseWarm * vDiffuceColor, 1.0 );
highp float fDiffucePower = max ( dot ( OUT_Normal, OUT_Light ), 0.0);
highp vec3 vFinal = mix ( vCold, vWarm, fDiffucePower );
highp vec3 vReflect = reflect(-OUT_View, OUT_Normal);
highp float fSpecularFactor = pow ( max ( dot ( vReflect, OUT_View ), 0.0 ), 32.0 );
gl_FragColor = vec4 ( min ( vFinal + fSpecularFactor, 1.0 ), 1.0 );
}
Rim-lighting fragment shader :
void main(void)
{
highp vec4 vDiffuceColor = texture2D(EXT_TEXTURE_01, OUT_TexCoord);
highp vec4 vSpecularColor = vec4 ( 0.7, 0.7, 0.7, 1.0 );
highp vec4 vRimColor = vec4 (0.0, 0.9, 0.0, 1.0) ;
highp float fSpecularPower = 16.0;
highp float fRimPower = 8.0;
highp float fBias = 0.3;
highp vec3 vReflect = reflect(-OUT_View, OUT_Normal);
vSpecularColor = vSpecularColor * pow ( max ( dot ( OUT_Light, vReflect ), 0.0 ), 16.0 );
vDiffuceColor = vDiffuceColor * max ( dot ( OUT_Normal, OUT_Light ), 0.0 );
vRimColor = vRimColor * pow ( 1.0 + fBias - max ( dot ( OUT_Normal, OUT_View ), 0.0 ), fRimPower );
gl_FragColor = vDiffuceColor + vRimColor + vSpecularColor;
}
The first step that you are need for iOS OpenGL ES application will be creation of UIView Controller which contain EAGLContext property. Also you are need override "+ (Class) layerClass" method like this :
+ (Class) layerClass
{
return [CAEAGLLayer class];
}
{
return [CAEAGLLayer class];
}
In the "initWithFrame" we are start initialize OpenGL context :
CAEAGLLayer* eaglLayer = (CAEAGLLayer*) super.layer;
eaglLayer.opaque = YES;
EAGLRenderingAPI api = kEAGLRenderingAPIOpenGLES2;
EAGLRenderingAPI api = kEAGLRenderingAPIOpenGLES2;
context = [[EAGLContext alloc] initWithAPI:api];
[context renderbufferStorage:GL_RENDERBUFFER fromDrawable: eaglLayer];After that we are add event listener for "drawView" method :
CADisplayLink* displayLink;
displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(drawView:)];[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];The next step is initialization of the render buffers :
Properties of buffers :
GLuint m_hFrameBuffer;
GLuint m_hRenderBuffer;
GLuint m_hDepthBuffer;
The _fWidth and _fHeight properties are size of UIGLView.
glGenRenderbuffers(1, &m_hDepthBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, m_hDepthBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, _fWidth, _fHeight);
glGenRenderbuffers(1, &m_hRenderBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, m_hRenderBuffer);
glGenFramebuffers(1, &m_hFrameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, m_hFrameBuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_hRenderBuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_hDepthBuffer);
glEnable( GL_DEPTH_TEST );
glEnable(GL_CULL_FACE);
glViewport(0, 0, _fWidth, _fHeight);And in the end we are add the next code int the "drawView" method :
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
----> scope for the render model <----
glFinish();
[context presentRenderbuffer:GL_RENDERBUFFER];STEP 2 ( Math Matrix, Vector ) :
Each OpenGL application must include Vector and Matrix structs. You can use third party math lib or develop your own lib. The minimal requirements of math lib something like this :
class Vector3d
{
public:
union
{
struct
{
float x, y, z;
};
float v[3];
};
};{
public:
union
{
struct
{
float x, y, z;
};
float v[3];
};
struct Matrix4x4
{
{
float m[16];
Matrix4x4()
{
memset(&m, 0x0, 16 * sizeof(float));
m[0] = 1.0f;
m[5] = 1.0f;
m[10] = 1.0f;
m[15] = 1.0f;
Matrix4x4()
{
memset(&m, 0x0, 16 * sizeof(float));
m[0] = 1.0f;
m[5] = 1.0f;
m[10] = 1.0f;
m[15] = 1.0f;
}
};
};
The minimal list of function with vector is :
Length();
Normalize();
CrossProduct();
DotProduct();
The minimal list of function with matrix is :
CreateViewMatrix();
CreateProjectionMatrix();
RotateMatrixAxis();
ScaleMatrix();
TransformMatrix();
InvertMatrix();STEP 3 ( Meshes VBO, IBO ) :
Vertex Buffer Objects (VBOs) are Buffer Objects that are used for vertex data. Since the storage for buffer objects is allocated by OpenGL, vertex buffer objects are a mechanism for storing vertex data in "fast" memory (i.e. video RAM or AGP RAM, and in the case of PCI Express, video RAM or RAM), thereby allowing for significant increases in vertex throughput between the application and the GPU.
The next code present creation of VBO object :
struct SVertex
{
Vector3d m_vPosition;
Vector2d m_vTexCoord;
Vector3d m_vNormal;
Vector3d m_vPosition;
Vector2d m_vTexCoord;
Vector3d m_vNormal;
};
GLuint handle;
glGenBuffers(1, &handle);
glBindBuffer(GL_ARRAY_BUFFER, m_handle);
glBufferData(GL_ARRAY_BUFFER, m_stride * m_count, m_pData, GL_STATIC_DRAW);
glBufferData(GL_ARRAY_BUFFER, m_stride * m_count, m_pData, GL_STATIC_DRAW);
GLint hPositionSlot = glGetAttribLocation(handle, "VERTEX_SLOT");
GLint hTexcoordSlot = glGetAttribLocation(handle, "TEXCOORD_SLOT");
GLint hNormalSlot = glGetAttribLocation(handle, "NORMAL_SLOT");
glBindBuffer(GL_ARRAY_BUFFER, m_handle);
glVertexAttribPointer(hPositionSlot, 3, GL_FLOAT, GL_FALSE, m_stride, 0);
glEnableVertexAttribArray(hPositionSlot);
glVertexAttribPointer(hTexcoordSlot, 2, GL_FLOAT, GL_FALSE, m_stride, (GLvoid*) (sizeof(float) * 3));
glEnableVertexAttribArray(hTexcoordSlot);glVertexAttribPointer(hNormalSlot, 3, GL_FLOAT, GL_FALSE, m_stride, (GLvoid*) (sizeof(float) * 5));
glEnableVertexAttribArray(hNormalSlot);
Note that when interleaving vertex attribute data some folks say there is gain to be had by aligning blocks of interleaved vertex data on 32-byte-aligned boundaries (keep in mind, there's nothing stopping you from inserting dead space into a VBO, if you're using the stride parameter to your pointer set calls).
The next code present creation of IBO object :
glGenBuffers(1, &handle);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, handle);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_count * sizeof(unsigned short), m_pData, GL_STATIC_DRAW);STEP 4 ( Textures PVRTC ) :
PVR file is a container for various texture format such as PVRTC, RGB and so forth. You can use directly these texture formats as is.
PVRTC is compressed texture format that is natively supported by GPU (PowerVR MBX or SGX). GPU can render PVRTC effectively. It would increase framerate.
glGenTextures( 1, &m_pSource->m_uiHanlde );
glBindTexture( GL_TEXTURE_2D, m_pSource->m_uiHanlde );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
if (Compressed)
glCompressedTexImage2D(GL_TEXTURE_2D, MIP_LEVEL, TEXTURE_FORMAT, Width, Height, 0, size, pData);
elseglCompressedTexImage2D(GL_TEXTURE_2D, MIP_LEVEL, TEXTURE_FORMAT, Width, Height, 0, size, pData);
glTexImage2D(GL_TEXTURE_2D, MIP_LEVEL, TEXTURE_FORMAT, Width, Height, 0, TEXTURE_FORMAT, TEXTURE_TYPE, pData);
STEP 5 ( Shaders GLSL ) :
OpenGL Shading Language (abbreviated: GLSL or GLslang), is a high-level shading language based on the syntax of the C programming language. It was created by the OpenGL to give developers more direct control of the graphics pipeline without having to use assembly language or hardware-specific languages.
struct SGLSLData
{
GLuint s_programmHandle;
GLuint s_vertexHandle;
GLuint s_fragmentHandle;
GLuint s_programmHandle;
GLuint s_vertexHandle;
GLuint s_fragmentHandle;
};
s_vertexHandle = glCreateShader(GL_VERTEX_SHADER ? GL_FRAGMENT_SHADER);
glShaderSource(s_vertexHandle, 1, &_pSource, 0);
glCompileShader(s_vertexHandle);
GLint success;
glGetShaderiv(s_vertexHandle, GL_COMPILE_STATUS, &success);
s_programmHandle = glCreateProgram();
glAttachShader(s_programmHandle s_vertexHandle);
glAttachShader(s_programmHandle , s_fragmentHandle);
glLinkProgram(s_programmHandle );
GLint success;
glGetProgramiv(s_programmHandle, GL_LINK_STATUS, &success);
A sample trivial GLSL vertex shader :
void main()
{
gl_Position = MATRIX_PROJECTION * MATRIX_VIEW * MATRIX_WORLD * VERTEX_POSITION;
}
A sample trivial GLSL fragment shader :
void main(void)
{
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
STEP 6 ( Lighting Lambert, Phong ) :
Lighting vertex shader :
attribute vec3 IN_SLOT_Position;
attribute vec2 IN_SLOT_TexCoord;
attribute vec3 IN_SLOT_Normal;
varying vec3 OUT_View;
varying vec3 OUT_Light;
varying vec3 OUT_Normal;
varying vec2 OUT_TexCoord;
uniform vec3 EXT_View;
uniform vec3 EXT_Light;
uniform mat4 EXT_MATRIX_Projection;
uniform mat4 EXT_MATRIX_View;
uniform mat4 EXT_MATRIX_World;
void main(void)
{
vec4 vWorldPosition = EXT_MATRIX_World * vec4(IN_SLOT_Position, 1.0);
OUT_Light = normalize(EXT_Light);
OUT_View = normalize(EXT_View - vec3(vWorldPosition));
OUT_Normal = normalize(mat3(EXT_MATRIX_World) * IN_SLOT_Normal);
OUT_TexCoord = IN_SLOT_TexCoord;
gl_Position = EXT_MATRIX_Projection * EXT_MATRIX_View * vWorldPosition;
}
void main(void)
{
vec4 vWorldPosition = EXT_MATRIX_World * vec4(IN_SLOT_Position, 1.0);
OUT_Light = normalize(EXT_Light);
OUT_View = normalize(EXT_View - vec3(vWorldPosition));
OUT_Normal = normalize(mat3(EXT_MATRIX_World) * IN_SLOT_Normal);
OUT_TexCoord = IN_SLOT_TexCoord;
gl_Position = EXT_MATRIX_Projection * EXT_MATRIX_View * vWorldPosition;
}
This is vertex shader will be use in all next samples of lighting.
Lambert lighting fragment shader :
varying mediump vec3 OUT_View;
varying mediump vec3 OUT_Light;
varying mediump vec3 OUT_Normal;
varying mediump vec2 OUT_TexCoord;
uniform sampler2D EXT_TEXTURE_01;
uniform sampler2D EXT_TEXTURE_02;
uniform sampler2D EXT_TEXTURE_03;
uniform sampler2D EXT_TEXTURE_04;
void main(void)
{
highp vec4 vDiffuseColor = texture2D(EXT_TEXTURE_01, OUT_TexCoord);
vDiffuseColor = vDiffuseColor * max ( dot ( OUT_Normal, OUT_Light ), 0.0 );
gl_FragColor = vDiffuseColor;
}
void main(void)
{
highp vec4 vDiffuseColor = texture2D(EXT_TEXTURE_01, OUT_TexCoord);
vDiffuseColor = vDiffuseColor * max ( dot ( OUT_Normal, OUT_Light ), 0.0 );
gl_FragColor = vDiffuseColor;
}
Phong lighting fragment shader :
varying mediump vec3 OUT_View;
varying mediump vec3 OUT_Light;
varying mediump vec3 OUT_Normal;
varying mediump vec2 OUT_TexCoord;
uniform sampler2D EXT_TEXTURE_01;
uniform sampler2D EXT_TEXTURE_02;
uniform sampler2D EXT_TEXTURE_03;
uniform sampler2D EXT_TEXTURE_04;
void main(void)
{
highp vec4 vDiffuseColor = texture2D(EXT_TEXTURE_01, OUT_TexCoord);
highp vec4 vSpecularColor = vec4(0.7, 0.7, 0.7, 1.0);
highp vec3 vReflect = reflect(-OUT_View, OUT_Normal);
vDiffuseColor = vDiffuseColor * max ( dot ( OUT_Normal, OUT_Light ), 0.0 );
vSpecularColor = vSpecularColor * pow ( max ( dot ( OUT_Light, vReflect ), 0.0 ), 16.0 );
gl_FragColor = vDiffuseColor + vSpecularColor;
}
void main(void)
{
highp vec4 vDiffuseColor = texture2D(EXT_TEXTURE_01, OUT_TexCoord);
highp vec4 vSpecularColor = vec4(0.7, 0.7, 0.7, 1.0);
highp vec3 vReflect = reflect(-OUT_View, OUT_Normal);
vDiffuseColor = vDiffuseColor * max ( dot ( OUT_Normal, OUT_Light ), 0.0 );
vSpecularColor = vSpecularColor * pow ( max ( dot ( OUT_Light, vReflect ), 0.0 ), 16.0 );
gl_FragColor = vDiffuseColor + vSpecularColor;
}
STEP 7 ( Non-realistic lighting Cell-Shading, Gooch, Rim Light ) :
Cell-Shading lighting fragment shader :
varying mediump vec3 OUT_View;
varying mediump vec3 OUT_Light;
varying mediump vec3 OUT_Normal;
varying mediump vec2 OUT_TexCoord;
uniform sampler2D EXT_TEXTURE_01;
uniform sampler2D EXT_TEXTURE_02;
uniform sampler2D EXT_TEXTURE_03;
uniform sampler2D EXT_TEXTURE_04;
void main(void)
{
highp vec4 vDiffuseColor = vec4( 0.0, 0.0, 0.5, 1.0 );
highp float fDiffuseFactor = 0.2 + max ( dot ( OUT_Normal, OUT_Light ), 0.0 );
highp vec4 clr;
if ( fDiffuseFactor < 0.3 )
vDiffuseColor = vDiffuseColor * 0.1;
else
if ( fDiffuseFactor < 0.7 )
vDiffuseColor = vDiffuseColor * 0.5;
else
if ( fDiffuseFactor < 0.8 )
vDiffuseColor = vDiffuseColor;
else
vDiffuseColor = vDiffuseColor * 1.3;
gl_FragColor = vDiffuseColor;
}
Gooch lighting fragment shader :
varying mediump vec3 OUT_View;
varying mediump vec3 OUT_Light;
varying mediump vec3 OUT_Normal;
varying mediump vec2 OUT_TexCoord;
uniform sampler2D EXT_TEXTURE_01;
uniform sampler2D EXT_TEXTURE_02;
uniform sampler2D EXT_TEXTURE_03;
uniform sampler2D EXT_TEXTURE_04;
void main(void)
{
highp vec3 vDiffuceColor = texture2D(EXT_TEXTURE_01, OUT_TexCoord).xyz;
highp vec3 vWarmColor = vec3 ( 0.6, 0.6, 0.0 );
highp vec3 vColdColor = vec3 ( 0.0, 0.0, 0.6 );
highp float fDiffuseWarm = 0.45;
highp float fDiffuseCold = 0.45;
highp vec3 vCold = min ( vColdColor + fDiffuseCold * vDiffuceColor, 1.0 );
highp vec3 vWarm = min ( vWarmColor + fDiffuseWarm * vDiffuceColor, 1.0 );
highp float fDiffucePower = max ( dot ( OUT_Normal, OUT_Light ), 0.0);
highp vec3 vFinal = mix ( vCold, vWarm, fDiffucePower );
highp vec3 vReflect = reflect(-OUT_View, OUT_Normal);
highp float fSpecularFactor = pow ( max ( dot ( vReflect, OUT_View ), 0.0 ), 32.0 );
gl_FragColor = vec4 ( min ( vFinal + fSpecularFactor, 1.0 ), 1.0 );
}
Rim-lighting fragment shader :
varying mediump vec3 OUT_View;
varying mediump vec3 OUT_Light;
varying mediump vec3 OUT_Normal;
varying mediump vec2 OUT_TexCoord;
uniform sampler2D EXT_TEXTURE_01;
uniform sampler2D EXT_TEXTURE_02;
uniform sampler2D EXT_TEXTURE_03;
uniform sampler2D EXT_TEXTURE_04;
void main(void)
{
highp vec4 vDiffuceColor = texture2D(EXT_TEXTURE_01, OUT_TexCoord);
highp vec4 vSpecularColor = vec4 ( 0.7, 0.7, 0.7, 1.0 );
highp vec4 vRimColor = vec4 (0.0, 0.9, 0.0, 1.0) ;
highp float fSpecularPower = 16.0;
highp float fRimPower = 8.0;
highp float fBias = 0.3;
highp vec3 vReflect = reflect(-OUT_View, OUT_Normal);
vSpecularColor = vSpecularColor * pow ( max ( dot ( OUT_Light, vReflect ), 0.0 ), 16.0 );
vDiffuceColor = vDiffuceColor * max ( dot ( OUT_Normal, OUT_Light ), 0.0 );
vRimColor = vRimColor * pow ( 1.0 + fBias - max ( dot ( OUT_Normal, OUT_View ), 0.0 ), fRimPower );
gl_FragColor = vDiffuceColor + vRimColor + vSpecularColor;
}