1. 2014.09.18 OpenGLES2.0 GLSL, 2D Basic shader (1)
  2. 2014.09.15 OpenGLES 2.0,GLSL lighting code
  3. 2014.09.12 GLSL, OpenGLES2.0 glFog

1. Outline

  Recently, many developer use OpenGLES 2.0 to make a 2d graphics  game. But it have little difficult because of OpenGLES1.0 & OpenglES 2.0 graphic-pipeline difference. Especially, when we meet GLSL shader first-time, it give little fear of programming. Follow writing show shader for someone who want to make 2d graphic game or app.

2. Vertex Shader

  vertex shader handle each vertex infos like poisition, vertex color etc. In 2d graphic, you don't need to set light or fog. 

  Before processing shader, you have to send posion, color, texture_coord infos. Below code is example.

void OpenGLES_2_0::jdGLVertexPointer(GLint size, GLenum type, GLsizei stride, const GLvoid* pointer)
	glVertexAttribPointer(m_Attributes.Position,size,type, GL_FALSE, stride, pointer);
void OpenGLES_2_0::jdGLColorPointer(int size, unsigned int type, int stride, const void* pointer)
	glVertexAttribPointer(m_Attributes.Color, size,type, GL_FALSE, stride, pointer);
void OpenGLES_2_0::jdGLTexCoordPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
	glVertexAttribPointer(m_Attributes.TexCoord, size,type, GL_FALSE, stride, pointer);

  I wrap opengles2.0 functions to looks like opengles1.0 funtions. If you want to know each parameter means, See reference page(OpenGL ES API), Using  above code and [glDrawElements(mode, count, type, indices)] , you can get each vertex infos like position, color etc. Following code show vertex shader.

attribute vec4 position; attribute vec4 source_color; attribute vec2 texture_coord; uniform mat4 projection; uniform mat4 modelview; varying vec4 destination_color;

varying      vec2 texture_coord_out; void main(void) { destination_color = source_color;

gl_Position = projection * modelview * position;

texture_coord_out      = texture_coord;


  In opengles 2.0, you have to set projection and modelview matrix.  In other words, you have to make projection matrix like glOrtho, glFrustum and modelview matrix like glTranslate, glRotate, glScale. This programming is easy  using man page.  Search [man glOrtho ]in google. You can see formula.

  Through varying keyword, You can send info to Fragment shader

3. Fragment Shader

  Fragment shader set pixel color info. It run as a number of screen pixels. So when you programming fragment shader, you have to do discreet. It affect performance.

varying lowp vec4 destination_color;
varying mediump vec2 texture_coord_out;
uniform sampler2D sampler;

uniform int enable_texture;
lowp vec4 sample_color;
lowp vec4 tmp_color;
void main(void)
	if(enable_texture == 1)
		sample_color	= texture2D(sampler, texture_coord_out);
		gl_FragColor	= sample_color*destination_color;
		gl_FragColor	= destination_color;

  I didn't handle about glTexEvn, But If you want to apply glTexEnv effect, you have make direct in fragment shader. In shader, bool is exist but you can't get from opengles2.0 functions. So I used int type value. Follow code is my opengles 2.0 eable state code.

void OpenGLES_2_0::jdGLEnable(GLenum cap)
	case GL_TEXTURE_2D:
		glUniform1i(m_Uniforms.EnableTexture, 1);
		glUniform1i(m_Uniforms.EnableNomalize, 1);
		m_enable_normalize = true;
		glUniform1i(m_Uniforms.EnableLighting, 1);
		glUniform1i(m_Uniforms.EnableAlphaTest, 1);
	case GL_FOG:
		glUniform1i(m_Uniforms.EnableFog, 1);
	case GL_LIGHT0:
	case GL_LIGHT1:
	case GL_LIGHT2:
	case GL_LIGHT3:
	case GL_LIGHT4:
	case GL_LIGHT5:
	case GL_LIGHT6:
	case GL_LIGHT7:
		int index = cap ^ 0x4000;
		Light& tmp_light = m_light_array[index];
		glUniform1i(tmp_light.enable, 1);
		int result = 0;

 opengles 2.0 don't have GL_TEXTURE_2D, GLNORMALIZE etc. But 2d-graphics only need GL_TEXURE_2D. You don't neet to set GL_LIGHTING, GL_FOG.

3. Result Scene

<OpenGL Diary app>

1. outline

  OpenGLES 2.0 don't support glLightf. So developer have to make light effect using glsl shader. Following content don't explane  about OpenGL2.0 functions like glGetUniformLocation, glGetAttribLocation, ect. 

2. Light formula

  Below formual show graphics expression of light in 3D graphics.

I = Global Ambient  + Emission + Ambient + Diffuse + Specular

= Ga + Me + 1/a+bD+cD^2(Ka*Ia + Kd*Id(NㆍL) + Ks*Is(RㆍV)^n)

Ga = Global Ambient

Me = Material Emission

D = light distance from vertex

a = constant attenuation

b = linear attenuation

c = quadratic attenuation

Ka  = Material Ambient

Ia = Light Ambient

Kd = Material Diffuse

Id = Light Diffuse

Ks = Material Specular

Is  = Light Specular

N = Normal Unit Vector of Vertex

L = Light Unit Vector (i.e. Light Position - Vertex Position)

R = Reflection Unit Vector

V = View point Unit Vector

Global Ambient, Ambient, Diffuse, Spcrular, Emission, Attenuations and Position values are set by opengles 2.0 functions like glUniform4f, glUniform1f. 


I initialize material values 

//init material
m_material.ambient	= glGetUniformLocation(program, "material.ambient");
m_material.diffuse 	= glGetUniformLocation(program, "material.diffuse");
m_material.specular 	= glGetUniformLocation(program, "material.specular");
m_material.emission 	= glGetUniformLocation(program, "material.emission");
m_material.shininess 	= glGetUniformLocation(program, "material.shininess");

glUniform4f(m_material.ambient, 0.2f, 0.2f, 0.2f, 1.0f);
glUniform4f(m_material.diffuse, 0.8f, 0.8f, 0.8f, 1.0f);
glUniform4f(m_material.specular, 0.0f, 0.0f, 0.0f, 1.0f);
glUniform4f(m_material.emission, 0.0f, 0.0f, 0.0f, 1.0f);
glUniform1f(m_material.shininess, 0.0f);

Otherwise, Normal Vector, Reflection Vector, Eye Vector and Light Vector are set in shader.

Light Vector : Light Position - Vertex Position. Blow show shader code.

gl_Position = modelview * position; vec3 L = vec3(light_position.x - gl_Position.x, light_position.y - gl_Position.y, light_position.z - gl_Position.z); D = sqrt(L.x*L.x + L.y*L.y + L.z*L.z);

'D' is distance light and vertex. This is used to apply attenuation effect.

Normal Vector : This value is influenced by modelview matrix. If you translate your model, normal vector is also translated. So I made a Nomal-Matirx that is made by ModelView-Matrix.

m_Uniforms.NormalMatrix = glGetUniformLocation(m_current_shader_program,"normal_matrix");
glUniformMatrix3fv(m_Uniforms.NormalMatrix, 1, 0,>ToMat3().Inverse().Transposed().Pointer());

To get Normal Matrix, I got 3x3 Matrix from Modelview Matrix. And I inversed and transpose this matrix. Lastly Send to shader matrix.

In shader, you can get normal vector. Below show shader code.

vec3 normalized_N 	= normalize(normal_matrix * normal);	//normal vector

Reflection Vector : This Vector is reflection of light-vector. You can get from Light vector and Normal Vector. Below show shader code.

vec3 normalized_R 	= normalize(dot(L, normalized_N)*2.0*normalized_N - L);		//reflection vector

Eye Vector :This Vector is direction of eye. Default is vec3(0,0,1). Also I use Default.

vec3 normalized_V 	= normalize(vec3(0.0, 0.0, 1.0));		//eye vector

Attenuation : Light is changed by distance. If light and vertex distance is close, light intensity is big. In 3D graphics, attenuation is expressed 

1/(a+ b*dD + c*D^2). 

attenuation = 1.0/(light[0].constant_attenuation + light[0].linear_attenuation*D + light[0].quadratic_attenuation*D*D);

3. Ambient + Diffuse + Specualr

Ambient is neighboring light. In 3d graphics, This value is expressed Ka*Ia/D^2. [Ka] is Material Ambient value. [Ia] is Light Ambient. D is distance. 

Diffuse is spread of light. This is Kd*Id*(NㆍL).

Specular is Ks*Is*((RㆍV)^n)

Below show shader code.

float df = max(0.0, dot(normalized_N, normalized_L));							//get diffuse constant
float sf = max(0.0, dot(normalized_R, normalized_V));							//get specualr constant
float shininess = clamp(material.shininess, 0.0, 128.0);
if(material.shininess != 0.0)
	sf = pow(sf, material.shininess);

float attenuation = 1.0;
float spot_exponent_value = 1.0;
if(light[0].position.w != 0.0)
	attenuation = 1.0/(light[0].constant_attenuation + light[0].linear_attenuation*D + light[0].quadratic_attenuation*D*D);
	spot_exponent_value = pow(max(0.0,spotlight_dot),light[0].spot_exponent);
//get color
vec4 ambient_value = light[0].ambient*material.ambient*attenuation;
vec4 diffuse_value = df*light[0].diffuse*material.diffuse*attenuation*spot_exponent_value;
vec4 specualr_value = sf*light[0].specular*material.specular*attenuation*spot_exponent_value;   
sum_color = global_ambient + material.emission + ambient_value + diffuse_value;

df is inner product Normal Vector and Light Vector. This is used in diffuse. sf is ((RㆍV)^n) that used in Specular.

4. Result Scene

This is OpenGL test App (OpenGL Diary)

'NDK & OpenGL ES' 카테고리의 다른 글

Android, NDK OpenGLES2.0 Texture  (0) 2014.09.22
OpenGLES2.0 GLSL, 2D Basic shader  (1) 2014.09.18
OpenGLES 2.0,GLSL lighting code  (0) 2014.09.15
GLSL, OpenGLES2.0 glFog  (0) 2014.09.12
NDK AdMob, Can't see admob on Framelayout  (0) 2014.09.10
GLSurfaceView & GLRenderer 설정  (0) 2014.04.15

OpenGLES2.0 not support glFog. So If you want fog effect, you have to a code using glsl.

1. Calculate

  GL_FOG_MODE have 3 modes.

GL_LINEAR : f = (end - z)/(end - start)

GL_EXP :  f = exp(-density*z) 

GL_EXP2 : f = exp2(-(density*z)*(density*z))

Color = Color_source*f + (1-f)Color_fog

  start - fog start distionce(usually 0.0f)

  end - fog's end distance (usually 1.0f)

  Color_source is fragment color.

  Color_fog is fog-color set by GL_FOG_COLOR

2. GLSL Code

  Below show glsl code. It is very simple code

tmp_color is rgba color that texture color and source color modulated. 

enable_fog is set by glUniform1i c++ code. Default mode is GL_LINEAR. 

To get fragment's depth buffer value, I used gl_FragCoord.z that is [0-1].

void main(void)
	if(enable_fog == 1)
		float f = 0.0;
		float z = gl_FragCoord.z;
		float alpha = tmp_color.a;
		if(fog_mode == FOG_EXP)
			f = clamp(exp(-fog_density*z),0.0, 1.0);
		else if(fog_mode == FOG_EXP2)
			f = clamp(exp((fog_density*z)*(fog_density*z)),0.0, 1.0);
			float divide = fog_end - fog_start;
			if(divide != 0.0)
				f = clamp((fog_end - z)/(divide),0.0, 1.0);
		tmp_color = f*tmp_color + (1.0 - f)*fog_color;
		tmp_color.a = alpha;
	gl_FragColor = tmp_color;

Below show result,

(OpenGL Diary)

'NDK & OpenGL ES' 카테고리의 다른 글

OpenGLES2.0 GLSL, 2D Basic shader  (1) 2014.09.18
OpenGLES 2.0,GLSL lighting code  (0) 2014.09.15
GLSL, OpenGLES2.0 glFog  (0) 2014.09.12
NDK AdMob, Can't see admob on Framelayout  (0) 2014.09.10
GLSurfaceView & GLRenderer 설정  (0) 2014.04.15
이클립스 NDK설정  (0) 2014.04.15