Saturday, January 28, 2012

iOS OpenGL ES 2.0 Lighting models for beginners.

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 :

+ (Class) layerClass
{
    return [CAEAGLLayer class];
}

In the "initWithFrame" we are start initialize OpenGL context :

CAEAGLLayer* eaglLayer = (CAEAGLLayer*) super.layer;
eaglLayer.opaque = YES;
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];
    };
};

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;
    }
};

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;
};
GLuint handle;
glGenBuffers(1, &handle);
glBindBuffer(GL_ARRAY_BUFFER, m_handle);
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);
else
        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;
};

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;
}

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;
}





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;
}





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;
}




Sunday, July 31, 2011

Atmospheric scattering with blending to the landscape and ocean.

This is some of my sample with atmospheric scattering. It is based on Crysis AS shader, with some improvements to mix colors on the borders. Also present effect of water depth, reflection, refraction, and landscape parallax mapping.

The screenshots : 




Link to the bin and source code

Flash 3d rasterization

I am create simple bitmap rasterization in 3D space.
The screenshots :




I'm working on improving performance now.

Monday, September 20, 2010

Simple Flash Game :-)

Now I develop some simple game on Action Script 3.0 like as Digger. This is sample :

 

Monday, April 5, 2010

m3_viewer Star Craft 2 fast update 0.0.3a.

Fast update : change screen size to 800*600 px.;
                    font changed to Times New Roman;
                    fixed UI blending.

Download : m3_viewer.zip


Sunday, April 4, 2010

m3_viewer Star Craft 2 has updated to 0.0.3.

m3_Viewer has updated to 0.0.3 version. In the new release :

a ) meshes and textures are loading in the second thread ( in background ) parallel with main thread. Now you can see more meshes for one execute;
b ) added simple user interface for convenience :-);
c ) fixed bug with normal calculate ( if you will enable lighting, you will see this);

 Download : m3_Viewer.zip

Screenshots :

Monday, March 8, 2010

m3_viewer Star Craft 2 build 0.02.

m3_viewer has updated. download_link
In this release :
          - convert to .obj file;
          - normal show turn on\off;
          - light turn on\off.