BAB 4 Viewing / Camera
4.1 Pengertian Viewing / Camera
Viewing camera adalah cara mengatur sudut pandang dari
pergerakan kamera terhadap objek 2D maupun 3D, sehingga dapat
memproyeksikan objek sehingga tampak riil.
4.1.1 Proyeksi Paralel
Proyeksi paralel dapat dikategorikan menurut hubungan antara
arah proyeksi dengan vektor normal dari bidang proyeksi, ke dalam
dua macam proyeksi. Proyeksi yang di hasilkan belum membentuk
object 3D yang tampak riil. Pusat proyeksi pada objek akan bertemu
di titik yang tak terhingga.
Gambar 4.1 Proyeksi paralel
4.1.2 Syntax Proyeksi Paralel
Dalam OpenGL terdapat syntax untuk Parallel Projection. Salah
satunya dapat menggunakan syntax:
glOrtho(-15.0, 20.0, -10.0, 15.0, -50.0, 70.0);
Mendefinisikan besarnya sistem koordinat 3D: dengan range
sumbu x adalah [-15,20], range untuk sumbu y adalah [-10,15],
range untuk sumbu z adalah [-50,70]
Pusat Proyeksi pada titik
tak terhingga
Bidang Proyeksi
B
C
D
A
B’
C’
D’
gluOrtho2D(-100,100,-200,200);
Mendefinisikan besarnya sistem koordinat 2D: dengan range
sumbu x adalah 100,100] dan range untuk sumbu y adalah
[-200,200].
4.1.3 Proyeksi Perspektif
Perspective projection di gunakan untuk memodifikasi
gambar 2D pada layar agar terlihat 3D seperti di dunia nyata, gambar
terlihat semakin kecil di belakang, mempunyai pusat di satu titik,
konsep ini seperti penglihatan di dunia nyata, ketika objek benda
semakin jauh maka akan terlihat semakin kecil, ketika di lihat lebih
dekat maka benda akan membesar secara konstan satu garis lurus.
Untuk menciptakan pandangan perspektif, maka setting kamera perlu
diubah dari glOrtho() menjadi gluPerspective(), gluLookAt(), dan
glFrustum().
Gambar 4.2 Proyeksi Perspektif
4.1.4 Syntax Proyeksi Perspektif
Dalam OpenGL terdapat syntax untuk Parallel Projection. Salah
satunya dapat menggunakan syntax:
•
gluPerspective(GLdouble fovy, GLdouble aspect, GLdouble near,
GLdouble far)
–
Fovy adalah sudut di bidang pandang (dalam rentang dari
[0.0, 180])
–
Aspect adalah rasio aspek frustrum (lebar jendela di atas
ketinggian jendela)
Gambar 4.3 gluPerspective()
•
glFrustum(GLdouble left, GLdouble right, GLdouble bottom,
GLdouble top, GLdouble near, GLdouble far)
–
left, right, top, and bottom mendefinisikan batas dari near.
–
near and far menentukan seberapa jauh dari sudut pandang
clipping pane
Gambar 4.4 glFrustum()
•
gluLookAt(GLdouble e_x, GLdouble e_y, GLdouble e_z,
ouble c_x, GLdouble c_y, GLdouble c_z, GLdouble u_x,
GLd-ouble u_y, GLdGLd-ouble u_z)
–
e_x, e_y, and e_z menentukan sudut pandang yang
di-inginkan (mata)
–
c_x, c_y, c_z menentukan beberapa titik di sepanjang garis
yang diinginkan sight (pusat)
–
u_x, u_y, and u_z mendifinisikan vector up dari camera kita
(up)
Aktivasi Fungsi:
•
gluPerspective()
:
………
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
………..
•
gluLookAt()
………
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(mata_x, mata_y, mata_z, lihat_x, lihat_y, lihat_z,
atas_x, atas_y, atas_z);
………..
4.2 Matematika Synthetic Camera
Cara kerja kamera sintetik:
Gambar 4.5 Cara Kerja Kamera Sintetik
Objek terletak pada sistem koordinat dunia (x, y, z), lensa
ter-letak pada sistem koordinat UVN atau kamera sintetik (u, v, n), dan
film sebagai bidang proyeksi.
Sistem koordinat kamera sintetik:
Gambar 4.6 Sistem koordinat kamera sintetik
Sumbu n sebagai arah pandang kamera, dan ditentukan
ber-dasarkan vektor normal (n
x,n
y,n
z).
Sumbu v sebagai arah atas, sumbu u sebagai arah horisontal. (v
∟
n), (u ∟ n) dan (u ∟ v)
Cara mendapatkan sumbu u, v, dan n:
User menentukan titik tengah view/ eye (VRP), pusat titik
pan-dang objek /center (lookAt) dan vektor atas (UpVector).
n adalah vektor dari VRP menuju lookAt. Lalu vektor n
dinormal-isasi.
Contoh : Diketahui VRP di titik r(r
x, r
y, r
z), lookAt di titik la(la
x, la
y, la
z) dan UpVector di titik up(up
x,up
y,up
z). Sehingga,
n
x
v
u
init
v
init
v
v
adalah
init
v
vektor
unit
n
n
up
up
init
v
init
n
init
n
n
adalah
init
n
vektor
unit
r
la
init
n
_
_
)
(
_
,
*
_
_
_
)
(
_
,
_
Memindahkan titik koordinat dunia P(P
x,P
y,P
z) ke koordinat
ka-mera sintetik Q(Q
u,Q
v,Q
n). Titik Q dapat diperoleh melalui :
–
t(t
x,t
y,t
z) = P - r
–
Q
u= t
•
u, Q
v= t
•
v dan Q
n= t
•
n
Q
u= (P-
r) • u = (P • u)
-
(r • u)
Contoh
:
Diketahui koordinat UVN dengan u=(-1,0,0), v=(0,0.8,0.6),
n=(0,-0.6,0.8) dan r = (2,3,-1). Hitunglah lokasi Q(Q
u,Q
v,Q
n) yang
merupakan transformasi dari titik P(4,7,2) di koordinat dunia !
Jawab
:
t(t
x,t
y,t
z) = P - r = (4-2,7-3,2-(-1)) =(2,4,3)
Q
u= t • u =(2,4,3) • (
-1,0,0) = 2*(-1)+4*(0)+3*(0)=-2
Q
v= t • v =(2,4,3) • (0,0.8,0.6) = 2*(0)+4*(0.8)+3*(0.6)=5
Q
n= t • n =(2,4,3) • (0,
-0.6,0.8) = 2*(0)+4*(-0.6)+3*(0.8)=0
Jadi titik Q terletak di koordinat (-2,5,0) pada sistem koordinat
UVN.
Matrik transformasi dari koordinat dunia ke UVN:
1
1
0
0
0
1
Pz
Py
Px
n
r
n
n
n
v
r
v
v
v
u
r
u
u
u
Qn
Qv
Qu
z y x z y x z v xSetelah titik Q diketahui, maka langkah berikutnya adalah
melakukan proyeksi perspektif terhadap titik Q, sehingga
di-peroleh titik T(u*, v*).
Proyeksi Q ke T dapat diperoleh dengan menggunakan rumus
berikut:
n n v
n n u
e
Q
Q
v
e
Q
Q
u
1
*
,
1
*
Mata/ eye terletak di (0, 0, e
n), dengan syarat e
n> n
zdan e
n!= 0.
Contoh: dengan menggunakan Tabel 4.1 dan 4.2 berikut:
(se-bagai informasi tentang vertex dan permukaan objek)
Vertex
X
Y
Z
0
0.0
-1.0
0.0
1
1.0
-1.0
0.0
2
1.0
-1.0
1.0
3
0.0
-1.0
1.0
4
0.5
0.5
0.5
Surface Index
0
1
4
1
2
4
2
3
4
3
0
4
Jawab:
Mencari sistem koordinat UVN:
) 88 . 0 , 01 . 0 , 46 . 0 ( )) 56 . 0 32 . 0 ( ), 2 . 0 19 . 0 ( ), 16 . 0 3 . 0 (( ))) 8 . 0 ( * ) 7 . 0 (( )) 6 . 0 ( * ) 53 . 0 (( )), 38 . 0 ( * ) 53 . 0 (( )) 27 . 0 ( * ) 7 . 0 (( ), 27 . 0 ( * ) 6 . 0 ( ) 38 . 0 ( * ) 8 . 0 (( 38 . 0 6 . 0 7 . 0 27 . 0 8 . 0 53 . 0 ) 38 . 0 , 6 . 0 , 7 . 0 ( 36 . 0 ) 23 . 0 , 36 . 0 , 42 . 0 ( 05 . 0 13 . 0 18 . 0 ) 23 . 0 , 36 . 0 , 42 . 0 ( ) 23 . 0 ( ) 36 . 0 ( ) 42 . 0 ( ) 23 . 0 , 36 . 0 , 42 . 0 ( | _ | _ ) 23 . 0 , 36 . 0 , 42 . 0 ( ) 23 . 0 , 64 . 0 , 42 . 0 ( ) 0 , 1 , 0 ( _ )) 27 . 0 ( * 8 . 0 ), 8 . 0 ( * 8 . 0 ), 53 . 0 ( * 8 . 0 ( ) 0 , 1 , 0 ( ) 27 . 0 , 8 . 0 , 53 . 0 )( 8 . 0 ( ) 0 , 1 , 0 ( _ ) 27 . 0 , 8 . 0 , 53 . 0 ( * )) 27 . 0 ( * 0 ) 8 . 0 ( * 1 ) 53 . 0 ( * 0 ( ) 0 , 1 , 0 ( * ) ( _ ) 27 . 0 , 8 . 0 , 53 . 0 ( 14 1 , 14 3 , 14 2 ) 1 ( ) 3 ( ) 2 ( ) 1 , 3 , 2 ( | _ | _ ) 1 , 3 , 2 ( ) 1 , 3 , 2 ( ) 0 , 0 , 0 ( _ 2 2 2 2 2 2                                                                                                              u u k j i n v u init v init v v init v init v n n up up init v init n init n n r la init n
la = (0,0,0) dan r = (2,3,1)
n = (-0.53,-0.8,-0.27)
v = (-0.7,0.6,-0.38)
u = (0.46,-0.01,-0.88)
Transformasi vertex ke sistem UVN:
Vertex
t
X
=p-r
t
Y=p-r
t
Z=p-r
0
0-2=-2
-1-3=-4
0-1=-1
1
-1
-4
-1
2
-1
-4
0
3
-2
-4
0
4
-1.5
-2.5
-0.5
Q
u
=t•u
Q
v=t•v
Q
n=t•n
0
-0.62
4.53
0.46
-1.32
4
-0.42
-1.7
3.73
-0.88
-1
4.26
-0.23
-0.26
2.93
Vertex
u*
v*
0
0
-2.53
1
1.38
-3.96
2
-1.11
-4.49
3
-3.03
-3.45
4
-0.45
-0.51
Gambar 4.7 Gambar synthetic camera dari vertex hasil trtasformasi
perspektif (u*,v*)
4.3 Membuat Multiple View Object
•
Satu objek yang dapat dilihat dengan posisi mata yang
ber-beda yaitu posisi mata kanan dan mata kiri.
•
Didasarkan pada stereokopik alami dari sistem mata.
•
Masing-masing mata melihat objek dari lokasi yang berbeda.
Gambar 4.8 Ilustrasi Multiple View Object
v*
Source Code 4.1 Code Membuat Multiple View Object
ESRender.java
package com.camera_n_viewing_project;
import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10;
//import android.opengl.GLU;
import android.opengl.GLSurfaceView.Renderer; import android.opengl.GLU;
public class ESRender implements Renderer {
private TransObject transobject; // the primitive object to be drawn
private TransPolarObject transpolarobject; private TransKubusObject kubus;
private TransPiramidaObject piramida;
int RunMode=1;
float CurrentAngle = 0.0f; //
Angle in degrees
float AnimateStep = 2.0f; //
Rotation step per update
/** Constructor to set the handed over context */ public ESRender() {
this.piramida = new TransPiramidaOb-ject();
}
@Override
public void onDrawFrame(GL10 gl) { // clear Screen and Depth Buffer //gl.glClearColor(1.0f, 1.0f, 1.0f, 1.0f); // set background dgn warna putih
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
// Reset the Modelview Matrix gl.glLoadIdentity();
// menampilkan piramida gl.glPushMatrix();
gl.glTranslatef(0.0f, 0.0f, 0.0f);
// Rotate the object
gl.glTranslatef(0.0f, 0.0f, -5.0f);
gl.glRotatef( CurrentAngle, 0.1f, 1.0f, -0.1f );
piramida.draw(gl); gl.glPopMatrix();
// Update the rotational angle after each refresh
if (RunMode==1) {
// re-Calculate animation parame-ters
CurrentAngle += AnimateStep; if (CurrentAngle > 360.0) {
//CurrentAngle -= 360.0*Math.floor(CurrentAngle/360.0);
CurrentAngle=0.0f; CurrentAngle += Ani-mateStep;
} }
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
if (height == 0)
height = 1; // To prevent divide by zero
float aspect = (float) width / height;
// Set the viewport (display area) to cover the entire window
gl.glViewport(0, 0, width, height);
// Setup perspective projection, with as-pect ratio matches viewport
gl.glMatrixMode(GL10.GL_PROJECTION); // Select projection matrix
gl.glLoadIdentity(); // Reset projection matrix
// Use perspective projection
GLU.gluPerspective(gl, 45, aspect, 0.1f, 100.f);
//gl.glOrthof(3.0f, 3.0f, 3.0f, 3.0f, -3.0f, 3.0f);
gl.glMatrixMode(GL10.GL_MODELVIEW); // Select model-view matrix
gl.glLoadIdentity(); // Reset
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
gl.glClearDepthf(1.0f); // Set depth's clear-value to farthest
gl.glEnable(GL10.GL_DEPTH_TEST); // Ena-bles depth-buffer for hidden
// surface removal
gl.glDepthFunc(GL10.GL_LEQUAL); // The type of depth testing to do
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST); // nice
// perspective
// view
gl.glShadeModel(GL10.GL_SMOOTH); // Ena-ble smooth shading of color
gl.glDisable(GL10.GL_DITHER); // Disable dithering for better
// performance }
public int getRunMode() { return RunMode;
}
public void setRunMode(int mRunMode) { RunMode = mRunMode;
}
public float getAnimateStep() { return AnimateStep;
}
public void setAnimateStep(float mAnimateStep) { AnimateStep = mAnimateStep;
}
}
ESSurfaceView.java
package com.camera_n_viewing_project;
import android.content.Context; import android.opengl.GLSurfaceView; import android.util.Log;
import android.view.KeyEvent; import android.view.MotionEvent;
/**
* A view container where OpenGL ES graphics can be drawn on screen.
* This view can also be used to capture touch events, such as a user
* interacting with drawn objects. */
private final ESRender esRender;
public ESSurfaceView(Context context) { super(context);
// Set the Renderer for drawing on the GLSur-faceView
esRender = new ESRender(); setRenderer(esRender);
// To enable keypad
this.setFocusable(true); this.requestFocus();
// To enable touch mode
this.setFocusableInTouchMode(true);
// Render the view only when there is a change in the drawing data
// merender hanya ketika ada perubahan/ event
//setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY); }
//private final float TOUCH_SCALE_FACTOR = 180.0f / 320;
//private float mPreviousX; //private float mPreviousY;
@Override
public boolean onTouchEvent(MotionEvent v) { // MotionEvent reports input details from the touch screen
// and other input controls. In this case, we are only
// interested in events where the touch position changed.
/*float x = e.getX(); float y = e.getY();*/
switch (v.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.v("Test Action Down", "action down working");
Log.i("Test Action Nilai", ""+Math.abs(esRender.getRunMode()-1));
esRen-der.setRunMode(Math.abs(esRender.getRunMode()-1));
//break;
requestRender();
//case MotionEvent.ACTION_POINTER_UP: //Log.v("Test Action
ACTION_POINTER_UP", "action working");
//Log.i("Test Action Nilai", ""+Math.abs(esRender.getAnimateStep()));
//esRender.setAnimateStep(esRender.getAnimateStep ()+8.0f);
//requestRender(); //case MotionEvent.ACTION_MOVE: //Log.v("Test Action ACTION_POINTER_DOWN", "action working");
//Log.i("Test Action Nilai", ""+Math.abs(esRender.getAnimateStep()));
//esRender.setAnimateStep(esRender.getAnimateStep ()-8.0f);
//requestRender(); //case MotionEvent.ACTION_UP:
//Log.v("Test Action Up", "action up working");
//esRender.setRunMode(esRender.getRunMode()); //requestRender();
//case MotionEvent.ACTION_MOVE:
//esRender.setRunMode(esRender.getRunMode()); //requestRender();
}
//mPreviousX = x; // mPreviousY = y; return true; //break; }
// Key-up event handler @Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_RIGHT: // In-crease rightward speed
Log.v("Test Action
KEYCODE_DPAD_RIGHT", "action working"); Log.i("Test Action Nilai", ""+Math.abs(esRender.getAnimateStep()));
esRen-der.setAnimateStep(esRender.getAnimateStep()+8.0f);
requestRender();
//ballSpeedX++;
break;
case KeyEvent.KEYCODE_DPAD_LEFT: // In-crease leftward speed
esRen-der.setAnimateStep(esRender.getAnimateStep()-8.0f);
requestRender();
//ballSpeedX--;
break;
case KeyEvent.KEYCODE_DPAD_UP: // In-crease upward speed
//ballSpeedY--;
break;
//ballSpeedY++;
break;
case KeyEvent.KEYCODE_DPAD_CENTER: // Stop
//ballSpeedX = 0;
//ballSpeedY = 0;
break;
case KeyEvent.KEYCODE_A: // Zoom in
Log.v("Test Action
KEYCODE_DPAD_RIGHT", "action working"); Log.i("Test Action Nilai", ""+Math.abs(esRender.getAnimateStep()));
esRen-der.setAnimateStep(esRender.getAnimateStep()+8.0f);
requestRender();
// Max radius is about 90% of half of the smaller dimension
//float maxRadius = (xMax > yMax) ? yMax / 2 * 0.9f : xMax / 2 * 0.9f;
//if (ballRadius < maxRadius) {
//ballRadius *= 1.05; //
Increase radius by 5%
//}
break;
case KeyEvent.KEYCODE_Z: // Zoom out
Log.v("Test Action
KEYCODE_DPAD_RIGHT", "action working"); Log.i("Test Action Nilai", ""+Math.abs(esRender.getAnimateStep()));
esRen-der.setAnimateStep(esRender.getAnimateStep()-8.0f);
requestRender();
//if (ballRadius > 20) { // Mini-mum radius
// ballRadius *= 0.95; //
De-crease radius by 5%
//}
break;
}
return true; // Event handled
}
}
MainActivity.java
package com.camera_n_viewing_project;
import android.opengl.GLSurfaceView; import android.os.Bundle;
import android.app.Activity; import android.view.Menu; import android.view.Window;
import android.view.WindowManager;
public class MainActivity extends Activity {
private GLSurfaceView glSurfaceView;
@Override
protected void onCreate(Bundle savedInstanceS-tate) {
super.onCreate(savedInstanceState); //setContentView(R.layout.activity_main);
// requesting to turn the title OFF requestWindowFeature(Window.FEATURE_NO_TITLE); // making it full screen
getWin-dow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREE N,
WindowManag-er.LayoutParams.FLAG_FULLSCREEN);
// Initiate the Open GL view and
// create an instance with this activity glSurfaceView = new ESSurfaceView(this);
// set our renderer to be the main renderer with // the current activity context
//glSurfaceView.setRenderer(new ESRender()); setContentView(glSurfaceView);
}
/**
* Remember to resume the glSurface */
@Override
protected void onResume() { super.onResume();
glSurfaceView.onResume(); }
/**
* Also pause the glSurface */
@Override
protected void onPause() { super.onPause();
glSurfaceView.onPause(); }
@Override
public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true; }
TransPiramidaObject.java
package com.camera_n_viewing_project; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.FloatBuffer;
import javax.microedition.khronos.opengles.GL10; public class TransPiramidaObject {
private float[] vertices = { // 5 vertices of the pyramid in (x,y,z)
-1.0f, -1.0f, -1.0f, // 0. left-bottom-back
1.0f, -1.0f, -1.0f, // 1. right-bottom-back
1.0f, -1.0f, 1.0f, // 2. right-bottom-front
-1.0f, -1.0f, 1.0f, // 3. left-bottom-front
0.0f, 1.0f, 0.0f // 4. top };
private float[] colors = { // Colors of the 5 vertices in RGBA
0.0f, 0.0f, 1.0f, 1.0f, // 0. blue 0.0f, 1.0f, 0.0f, 1.0f, // 1. green
0.0f, 0.0f, 1.0f, 1.0f, // 2. blue 0.0f, 1.0f, 0.0f, 1.0f, // 3. green
1.0f, 0.0f, 0.0f, 1.0f // 4. red };
private byte[] indices = { // Vertex indices of the 4 Triangles
0, 1, 4, // back face 1, 2, 4, // right face 2, 3, 4, // front face (CCW) 3, 0, 4 // left face
};
// Constructor - Set up the buffers public TransPiramidaObject() {
}
// Point to our vertex buffer, return buffer holding the vertices
public static FloatBuffer makeFloatBuffer(float[] arr){
ByteBuffer bb = ByteBuff-er.allocateDirect(arr.length * 4);
bb.order(ByteOrder.nativeOrder()); FloatBuffer fb = bb.asFloatBuffer(); fb.put(arr);
// Setup index-array buffer. Indices in byte. public static ByteBuffer makeByteBuffer(byte[] arr){
ByteBuffer bb = ByteBuff-er.allocateDirect(arr.length);
bb.put(arr); bb.position(0); return bb; }
// Draw the shape
public void draw(GL10 gl) {
gl.glFrontFace(GL10.GL_CCW); // Front face in counter-clockwise
// orientation
// Enable arrays and define their buffers
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); gl.glVertexPointer(3, GL10.GL_FLOAT, 0, makeFloatBuffer(vertices));
gl.glEnableClientState(GL10.GL_COLOR_ARRAY); gl.glColorPointer(4, GL10.GL_FLOAT, 0, makeFloatBuffer(colors));
//gl.glDrawElements(GL10.GL_TRIANGLES, indices.length,
//GL10.GL_UNSIGNED_BYTE, makeByteBuffer(indices));
gl.glDrawElements(GL10.GL_LINE_STRIP, in-dices.length,
GL10.GL_UNSIGNED_BYTE, makeByteBuffer(indices));
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL10.GL_COLOR_ARRAY); }
}
BAB 5 Texture Mapping
5.1 Pengertian Texture Mapping
Texture Mapping merupakan metode yang digunakan untuk
menambah detail texture pada permukaan objek.
Gambar 5.1 Texture Mapping
Texture merupakan data segi-empat sederhana yang berada
pada bidang texture. Bidang texture diwakili oleh dua sumbu koordinat
yaitu sumbu s dan sumbu t. Setiap texture akan memenuhi bidang
koordinat (0.0,0.0) sd. (1.0,1.0). Nilai individual dari array texture
biasanya dikenal dengan istilah texels (texture pixels).Yang membuat
texture mapping sedikit rumit adalah bagaimana proses pemetaan
antara bentuk segi empat texture ke polygon mengingat secara umum
bentuk
poligon
biasanya
non-rectangular.
Beberapa
contoh
penggunaan texture mapping antara lain:
Mensimulasikan aspek visual dari material seperti tampakan
kayu, batu bata, atau granit.
Mengurangi kompleksitas (jumlah polygon yang dibutuhkan)
dari suatu obyek geometri.
Teknik pemrosesan citra seperti image wraping dan
rectification, rotation, dan scaling.
Salah satu keuntungan dari texture mapping adalah bahwa detail
visual itu berada di citra bukan di geometri. Dan sekompleks apapun
citra, selama tidak merubah ukuran citra, tidak berpengaruh pada
kinerja keseluruhan, yaitu kompleksitas dari citra tidak berpengaruh
kepada pipeline geometric (transformasi, clipping) dari OpenGL.
Texture ditambahkan saat rasterisasi ketika geometric pipeline dan
pixel pipeline bertemu seperti diilustrasikan pada Gambar 5.2.
Raster-isasi adalah mengubah gambar dari format vector ke format pixel atau
titik.
vertices
image
geometry pipeline
pixel pipeline
rasterizer
Gambar 5.2 Ilustrasi Rasterisasi
Ada dua cara untuk melakukan texture mapping:
Membuat extra polygon untuk membangun detail model pada
ob-jek.
o
Menambah kompleksitas scene sehingga memperlambat
kecepatan rendering grafis.
o
Beberapa fitur grafis akan sulit untuk dimodelkan.
Membuat texture map pada permukaan (pendekatan yang lebih
sering digunakan).
Secara konseptual ada tiga langkah dalam melakukan texture
mapping, yaitu:
1. Penentuan texture
Baca image dari file
Generate texture id untuk image tersebut glGenTextures(3,
&texture[0])
2. Pemberian koordinat texture ke vertex
3. Penentuan parameter texture (wrapping / filtering)
5.2 Representasi Texture Mapping
Bitmap Texture
(s,t) yang telah dinormalisasi, terdapat image value [red, green,
blue].
Gambar 5.3 Bitmap Texture
Procedural Texture
Procedural texture adalah gambar yang dihasilkan computer
yang dibuat dengan algoritma untuk menciptakan representasi
realistis dari unsur-unsur alam seperti kayu, marmer, granit,
logam, batu, dan sebagainya.
5.3 Parameter Texture Mapping
Texture mapping diaktifkan dan di-non-aktifkan menggunakan
glEnable() atau
glDisable()
dengan
GL_TEXTURE_1D
atau
GL_TEXTURE_2D untuk menandakan satu atau dua dimensi.
glTexParameter*() digunakan untuk mengatur texture.
Berikut merupakan contoh penggunaan glTexParameter*()
un-tuk melakukan magnification dan minification:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_NEAREST);
Berikut merupakan contoh penggunakan glTexParameter*()
un-tuk melakukan repeating:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
Gambar 5.5 Repeating Texture
Berikut merupakan contoh penggunakan glTexParameter*()
un-tuk melakukan clamping:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
Gambar 5.6 Clamping Texture
Berikut merupakan contoh penggunakan glTexParameter*()
un-tuk melakukan repeating dan clamping:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
Gambar 5.7 Repeating dan Clamping Texture
5.4 Texture Mapping Pada Segitiga
Source Code 5.1 Code Texture Mapping Pada Segitiga
ESRender.java
package com.texture_mapping;
import java.util.Formatter;
import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10;
import android.content.Context; import android.opengl.GLES20; import android.opengl.GLSurfaceView; import android.opengl.Matrix;
import android.opengl.GLSurfaceView.Renderer; import android.opengl.GLU;
import android.util.Log; import android.widget.TextView;
public class ESRender implements Renderer {
private ESText glText; private TextView textview;
private ObjectArena objectarena; // the
private int RunMode=1;
private float mAngle = 0.0f; //
Angle in degrees
private float AnimateStep = 2.0f; // Rotation step per update
private long startTime; private long fpsStartTime; private long numFrames;
float radius = 50.0f; // Ball's radius float x = radius; // Ball's center (x,y) float y = radius;
float speedX = 5f; // Ball's speed (x,y) float speedY = 3f;
int xMin, xMax, yMin, yMax;
private int mywidth=0; private int myheight=0;
/** Constructor to set the handed over context */ public ESRender(Context context) {
//super();
this.context = context;
this.objectarena = new ObjectArena(); this.objectball = new ObjectBall(); this.objectball_hole = new ObjectBall(); this.objectball1 = new ObjectBall(); this.objectball2 = new ObjectBall();
this.objectball3 = new ObjectBall(); }
@Override
public void onDrawFrame(GL10 gl) {
// Draw background color
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
// segitiga
gl.glPushMatrix();
//GLU.gluLookAt(gl, 0, 0, 0.01f, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
gl.glTranslatef(50.0f, 60.0f, 0.0f);
gl.glScalef(80.0f, 80.0f, 0.0f);
gl.glRotatef(180, 1.0f, 0.0f, 0.0f);
gl.glTranslatef(5.0f, -3.5f, 0.0f);
objectball1.draw_segitiga(gl);
// update
moveWithCollisionDetection(this);
set((int)-radius, (int)-radius, mywidth, myheight);
// Update the rotational angle after each refresh
if (RunMode==1) {
// re-Calculate animation parame-ters
mAngle += AnimateStep; if (mAngle > 360.0) {
//CurrentAngle -= 360.0*Math.floor(CurrentAngle/360.0);
mAngle=0.0f;
mAngle += AnimateStep; }
}
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
gl.glClearColor(0.5f, 0.5f, 0.5f, 1.0f); // Set color's clear-value to black
gl.glClearDepthf(1.0f); // Set depth's clear-value to farthest
gl.glEnable(GL10.GL_DEPTH_TEST); // Ena-bles depth-buffer for hidden
// surface removal
gl.glDepthFunc(GL10.GL_LEQUAL); // The type of depth testing to do
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST); // nice
// perspective
// view
gl.glShadeModel(GL10.GL_SMOOTH); // Ena-ble smooth shading of color
gl.glDisable(GL10.GL_DITHER); // Disable dithering for better
// performance
// Create the GLText
glText = new ESText( gl, context.getAssets() );
// Load the font from file (set size + pad-ding), creates the texture
// NOTE: after a successful call to this the font is ready for rendering!
//gl.glDisable(GL10.GL_DITHER); // Disa-ble dithering for better
// performance
// Setup Texture, each time the surface is created (NEW)
objectball_hole.loadBallTexture(gl, con-text,0);
objectball1.loadBallTexture(gl, context,1);
objectball2.loadBallTexture(gl, context,0); objectball3.loadBallTexture(gl, context,1);
gl.glEnable(GL10.GL_TEXTURE_2D); //
Ena-ble texture (NEW)
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
mywidth=width;
myheight=height;
gl.glViewport( 0, 0, width, height );
// Setup orthographic projection
gl.glMatrixMode( GL10.GL_PROJECTION ); // Activate Projection Matrix
gl.glLoadIdentity(); // Load Identity Matrix
gl.glOrthof( // Set Ortho Projection
(Left,Right,Bottom,Top,Front,Back) 0, width,
0, height, 1.0f, -10.0f );
// Save width and height
//this.width = width; // Save Current Width
//this.height = height; // Save Current Height
gl.glMatrixMode(GL10.GL_MODELVIEW); // Se-lect model-view matrix
gl.glLoadIdentity(); // Reset
}
public float getxMax() { return xMax;
}
public void setxMax(int xmax) { xMax = xmax;
public float getxMin() { return xMin;
}
public void setxMin(int xmin) { xMin = xmin;
}
public float getyMax() { return yMax;
}
public void setyMax(int ymax) { yMax = ymax;
}
public float getyMin() { return yMin;
}
public void setyMin(int ymin) { yMin = ymin;
}
public float getspeedX() { return speedX;
}
public void setspeedX(float speedX_) { speedX = speedX_;
}
public float getspeedY() { return speedY;
}
public void setspeedY(float speedY_) { speedY = speedY_;
}
public void moveWithCollisionDetection(ESRender esRender) {
// Get new (x,y) position x += speedX;
y += speedY;
// Detect collision and react
if (x + radius > esRender.getxMax()) { speedX = -speedX;
x = esRender.getxMax() - radius; }
else if (x - radius < esRender.getxMin()) {
speedX = -speedX;
x = esRender.getxMin() + radius; }
if (y + radius > esRender.getyMax()) { speedY = -speedY;
y = esRender.getyMax() - radius; } else if (y - radius <
esRen-der.getyMin()) {
speedY = -speedY;
y = esRender.getyMin() + radius; }
public void set(int x, int y, int width, int height) {
xMin = x;
//xMax = x + width - 1; xMax = x + width; yMin = y;
//yMax = y + height - 1; yMax = y + height; }
}
ESSurfaceView.java
package com.texture_mapping;
import android.content.Context; import android.opengl.GLSurfaceView; import android.util.Log;
import android.view.KeyEvent; import android.view.MotionEvent;
/**
* A view container where OpenGL ES graphics can be drawn on screen.
* This view can also be used to capture touch events, such as a user
* interacting with drawn objects. */
public class ESSurfaceView extends GLSurfaceView {
private final ESRender esRender; private float previousX;
private float previousY;
public ESSurfaceView(Context context) { super(context);
// Set the Renderer for drawing on the GLSur-faceView
esRender = new ESRender(context); setRenderer(esRender);
// To enable keypad
this.setFocusable(true); this.requestFocus();
// To enable touch mode
this.setFocusableInTouchMode(true);
// Render the view only when there is a change in the drawing data
//setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY); }
//private final float TOUCH_SCALE_FACTOR = getWidth() / getHeight();
private float mPreviousX; private float mPreviousY;
@Override
public boolean onTouchEvent(MotionEvent v) { // MotionEvent reports input details from the touch screen
// and other input controls. In this case, we are only
// interested in events where the touch posi-tion changed.
float currentX = v.getX(); float currentY = v.getY();
float deltaX, deltaY;
//float scalingFactor = 0.50f /
((esRen-der.xMax > esRender.yMax) ? esRender.yMax //: esRender.xMax);
switch (v.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.v("Test Action Down", "action down working");
//break;
requestRender();
//case MotionEvent.ACTION_POINTER_UP:
//Log.v("Test Action
ACTION_POINTER_UP", "action working");
//requestRender();
//case MotionEvent.ACTION_MOVE:
//Log.v("Test Action
ACTION_POINTER_DOWN", "action working");
//requestRender();
//case MotionEvent.ACTION_UP:
//Log.v("Test Action Up", "action up working");
//requestRender(); case MotionEvent.ACTION_MOVE:
// Modify rotational angles according to movement
deltaX = currentX - previousX;
deltaY = currentY - previousY;
//esRender.setspeedX(esRender.getspeedX()+ (del-taX/getWidth()));
//esRender.setspeedY(esRender.getspeedY()+ (del-taY/getHeight()));
esRen-der.setspeedY(esRender.getspeedY()+ deltaY/100);
requestRender();
}
// Save current x, y
previousX = currentX;
previousY = currentY;
return true; // Event handled
//break; }
// Key-up event handler
@Override
public boolean onKeyUp(int keyCode, KeyEvent
event) {
switch (keyCode) {
case KeyEvent.KEYCODE_A: // mengurangi
kecepatan object
if((esRender.getspeedX()- 0.05f
>0) ){
esRen-der.setspeedX(esRender.getspeedX()- 0.05f);
}
if((esRender.getspeedX()- 0.05f
<0) ){
esRender.setspeedX(0.0f);
}
if((esRender.getspeedY()- 0.05f
>=0)){
esRen-der.setspeedY(esRender.getspeedY()- 0.05f);
}
if((esRender.getspeedY()- 0.05f
<0) ){
esRender.setspeedY(0.0f);
}
Log.v("Test Action KEYCODE_A",
"action working");
break;
case KeyEvent.KEYCODE_Z:
Log.v("Test Action KEYCODE_Z",
"action working");
break;
}
return true; // Event handled
}
MainActivity.java
package com.texture_mapping;
import com.texture_mapping.R;
import android.opengl.GLSurfaceView; import android.os.Bundle;
import android.app.Activity; import android.view.Menu; import android.view.Window;
import android.view.WindowManager;
public class MainActivity extends Activity {
/** The OpenGL view */
private GLSurfaceView glSurfaceView;
@Override
protected void onCreate(Bundle savedInstanceS-tate) {
super.onCreate(savedInstanceState); //setContentView(R.layout.activity_main);
// requesting to turn the title OFF requestWindowFeature(Window.FEATURE_NO_TITLE); // making it full screen
getWin-dow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCR EEN,
WindowManag-er.LayoutParams.FLAG_FULLSCREEN);
// Initiate the Open GL view and
// create an instance with this activity glSurfaceView = new ESSurfaceView(this);
// set our renderer to be the main renderer with
// the current activity context
//glSurfaceView.setRenderer(new ESRender()); setContentView(glSurfaceView);
}
/**
* Remember to resume the glSurface */
@Override
protected void onResume() { super.onResume();
glSurfaceView.onResume(); }
/**
@Override
protected void onPause() { super.onPause();
glSurfaceView.onPause(); }
@Override
public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true; }
}
ObjectBall.java
package com.texture_mapping;
import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer;
import javax.microedition.khronos.opengles.GL10; import javax.microedition.khronos.opengles.GL11; import
ja-vax.microedition.khronos.opengles.GL11ExtensionPack;
import com.texture_mapping.R;
import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.opengl.GLES20;
import android.opengl.GLUtils; import android.util.Log;
public class ObjectBall {
private float vertices[] = {
-0.5f, -0.5f, 0.0f, // V1 - first vertex (x,y,z)
-0.5f, 0.5f, 0.0f, //
V2
0.5f, 0.5f, 0.0f, //
V3
0.5f, -0.5f, 0.0f, // V4
-0.5f, -0.5f, 0.0f //
};
private float textCoord_Triagle[]={
1.0f, 1.0f, 0.0f, //
V3
0.0f, 1.0f, 0.0f, //
V2
0.5f, 0.0f, 0.0f, // V1 -
first vertex (x,y,z) };
float[] texCoords = { // Texture coords for the above face (NEW)
0.0f, 1.0f, // A. left-bottom (NEW)
1.0f, 1.0f, // B. right-bottom (NEW)
0.0f, 0.0f, // C. left-top (NEW) 1.0f, 0.0f // D. right-top (NEW) };
private float vertices_color[] = {
1.0f, 0.0f, 0.0f, 1.0f, //
CV1 - first color (red,green,blue)
0.0f, 1.0f, 0.0f, 1.0f, //
CV2
0.0f, 0.0f, 1.0f, 1.0f, //
CV3
0.0f, 1.0f, 0.0f, 1.0f, //
CV4
1.0f, 0.0f, 0.0f, 1.0f // CV5
};
private float vertices_circle[]={0.0f,0.0f,0.0f}; private float
verti-ces_circle_color[]={0.0f,0.0f,0.0f,0.5f}; private float textCoord[],textCoord_hole[]; private float
verti-ces_circle1[],vertices_circle1_hole[];
private int[] imageFileIDs = { // Image file IDs R.drawable.nature,
R.drawable.mule};
int[] textures_indek = new int[1];
private int batas_sudut=360; float jari_jari;
float a,b; float x,y;
float step=3.0f,step_line=0.2f; float x1,y1;
float x2,y2;
float teta, teta_hole; private int loop,loop_color;
// ============ start to generate stetch texture coordinat ==========================
//Inisialisasi jari_jari=0.5f;
// Titik Pusat a = 0.5f; b = 0.5f ; //x=a+jari_jari; y=b; teta = 0;
// generate stretch texture coordinat teta=0; teta_hole=0;
textCoord = new float[batas_sudut * 3]; textCoord_hole = new float[batas_sudut * 3];
for (int ii = 0; ii < batas_sudut * 3; ii += 3) {
// membentuk textCoord untuk cir-cle color
textCoord[ii] = (jari_jari*((float) Math.cos(-teta)))+a;
textCoord[ii + 1] = (jari_jari*((float) Math.sin(-teta)))+b;
textCoord[ii + 2] = 0.0f;
teta += Math.PI / 90;
// membentuk textCoord untuk cir-cle hole
textCoord_hole[ii] = (jari_jari*((float) Math.cos(-teta_hole)))+a;
textCoord_hole[ii + 1] = (jari_jari*((float) Math.sin(-teta_hole)))+b;
textCoord_hole[ii + 2] = 0.0f;
teta_hole += 15; }
// ============ start to generate verti-ces to circle (Cara 1) ==========================
//Inisialisasi jari_jari=50.0f;
// Titik Pusat
a = 50.0f; b = 50.0f ;
teta=0; teta_hole=0;
vertices_circle1 = new float[batas_sudut * 3];
vertices_circle1_hole = new float[batas_sudut * 3];
for (int ii = 0; ii < batas_sudut * 3; ii += 3) {
// membentuk vertices_circle1 vertices_circle1[ii] =
vertices_circle1[ii + 2] = 0.0f;
teta += Math.PI / 90;
// membentuk vertices_circle1 vertices_circle1_hole[ii] = (jari_jari*((float) Math.cos(teta_hole)))+a;
vertices_circle1_hole[ii + 1] = (jari_jari*((float) Math.sin(teta_hole)))+b;
vertices_circle1_hole[ii + 2] = 0.0f;
teta_hole += 15; }
// ============ start to generate verti-ces to circle (Cara 2) ==========================
//Inisialisasi jari_jari=50.0f;
// Titik Pusat
a = 50.0f; b = 50.0f ; x=a+jari_jari; y=b;
loop=0; loop_color=0; vertices_circle=new
float[(int)(3*batas_sudut/step)*3]; vertices_circle_color=new float[(int)(3*batas_sudut/step)*4];
for(teta=0;teta<=2*batas_sudut;teta+=step){
vertices_circle[loop] = (float)
((x-a)*Math.cos((teta/180)*(22/7)) - ((y-b)*Math.sin((teta/180)*(22/7))) + a);
vertices_circle[loop+1] = (float)
((x-a)*Math.sin((teta/180)*(22/7)) - ((y-b)*Math.cos((teta/180)*(22/7))) + b);
vertices_circle[loop+2]=0;
loop+=3;
//mengenerate warna untuk setiap vertex
//vertices_circle_color[loop_color]=(float) ((x-a)*Math.cos((teta/180)*(22/7)) -
((y-b)*Math.sin((teta/180)*(22/7))) + a);
//vertices_circle_color[loop_color+1]=(float) ((x-a)*Math.sin((teta/180)*(22/7)) -
((y-b)*Math.cos((teta/180)*(22/7))) + b);
vertices_circle_color[loop_color]=(float)
(Math.cos((teta/180)*(22/7)) );
verti-ces_circle_color[loop_color+1]=(float) (Math.sin((teta/180)*(22/7)));
vertices_circle_color[loop_color+2]=0.5f;
loop_color+=4; }
// ============= end for generate vertices to circle ====================
}
// Point to our vertex buffer, return buffer holding the vertices
public static FloatBuffer makeFloatBuffer(float[] arr){
ByteBuffer bb = ByteBuff-er.allocateDirect(arr.length * 4);
bb.order(ByteOrder.nativeOrder()); FloatBuffer fb = bb.asFloatBuffer(); fb.put(arr);
fb.position(0); return fb; }
// Setup index-array buffer. Indices in byte. public static ByteBuffer makeByteBuffer(byte[] arr){
ByteBuffer bb = ByteBuff-er.allocateDirect(arr.length);
bb.put(arr); bb.position(0); return bb; }
/** The draw method for the primitive object with the GL context */
public void draw_circle(GL10 gl) {
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
// set the colour for the object circle //gl.glColor4f(0.0f, 0.0f, 1.0f, 1.0f);
//create VBO from buffer with glBuffer-Data()
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, make-FloatBuffer(vertices_circle));
//memetakan warna untuk setiap vertex gl.glColorPointer(4, GL10.GL_FLOAT, 0, make-FloatBuffer(vertices_circle_color));
//draw circle as filled shape
//gl.glDrawArrays(GL10.GL_TRIANGLE_FAN, 1, (int) ((int) 2*batas_sudut/step));
//draw circle contours
//gl.glDrawArrays(GL10.GL_LINES, 1, (int) ((int) 2*batas_sudut/step));
gl.glDrawArrays(GL10.GL_LINE_STRIP, 1, (int) ((int) 2*batas_sudut/step));
//gl.glDrawArrays(GL10.GL_POINTS, 1, (int) ((int) 2*batas_sudut/step));
//Disable the client state before leaving
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL10.GL_COLOR_ARRAY); }
public void draw_circle_hole(GL10 gl) {
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
//create VBO from buffer with glBuffer-Data()
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, make-FloatBuffer(vertices_circle1_hole));
//menempelkan tekstur ke objek gl.glEnable(GL10.GL_TEXTURE_2D);
gl.glEnable(GL10.GL_BLEND); gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
gl.glBindTexture(GL10.GL_TEXTURE_2D, tex-tures_indek[0]); //
gl.glTexCoordPointer(3, GL10.GL_FLOAT, 0, makeFloatBuffer(textCoord_hole)); //
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRA Y);
gl.glDrawArrays(GL10.GL_LINE_STRIP, 0, ba-tas_sudut);
//draw circle contours
//gl.glDrawArrays(GL10.GL_LINES, 1, (int) ((int) 2*batas_sudut/step)); // membuat garis putus-putus pada tepi lingkaran
//gl.glDrawArrays(GL10.GL_LINE_STRIP, 1,
(int) ((int) 2*batas_sudut/step));
//Disable the client state before leaving
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisable( GL10.GL_BLEND ); // Disable Alpha Blend
gl.glDisable( GL10.GL_TEXTURE_2D ); // Disable Texture Mapping
}
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
//create VBO from buffer with glBuffer-Data()
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, make-FloatBuffer(vertices_circle1));
//menempelkan tekstur ke objek gl.glEnable(GL10.GL_TEXTURE_2D);
gl.glEnable(GL10.GL_BLEND); gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
gl.glBindTexture(GL10.GL_TEXTURE_2D, tex-tures_indek[0]); //
gl.glTexCoordPointer(3, GL10.GL_FLOAT, 0, makeFloatBuffer(textCoord)); //
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRA Y);
gl.glDrawArrays(GL10.GL_TRIANGLE_FAN, 0, ba-tas_sudut);
//draw circle contours
//gl.glDrawArrays(GL10.GL_LINES, 1, (int) ((int) 2*batas_sudut/step)); // membuat garis putus-putus pada tepi lingkaran
//gl.glDrawArrays(GL10.GL_LINE_STRIP, 1,
(int) ((int) 2*batas_sudut/step));
//Disable the client state before leaving
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisable( GL10.GL_BLEND ); // Disable Alpha Blend
gl.glDisable( GL10.GL_TEXTURE_2D ); // Disable Texture Mapping
}
public void draw_kotak(GL10 gl) {
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
// Point to our vertex buffer
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, makeFloatBuffer(vertices));
// Draw the vertices as square
gl.glColorPointer(4, GL10.GL_FLOAT, 0, makeFloatBuffer(vertices_color));
gl.glColorPointer(4, GL10.GL_FLOAT, 0, makeFloatBuffer(vertices_color));
gl.glDrawArrays(GL10.GL_TRIANGLES, 2, 3);
//Disable the client state before leaving
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL10.GL_COLOR_ARRAY);
}
public void draw_segitiga(GL10 gl) {
gl.glFrontFace(GL10.GL_CCW); // Front face in counter-clockwise
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
//gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
// set the colour for the triangle //gl.glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, makeFloatBuffer(new float [] {
1.0f, 1.0f, 0.0f, // V3
0.0f, 1.0f, 0.0f, // V2
0.5f, 0.0f, 0.0f, //
V1 - first vertex (x,y,z) }));
// Draw the vertices as triangle
//gl.glColorPointer(4, GL10.GL_FLOAT, 0, makeFloatBuffer(vertices_color));
//menempelkan tekstur ke objek gl.glEnable(GL10.GL_TEXTURE_2D);
gl.glEnable(GL10.GL_BLEND); gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
gl.glBindTexture(GL10.GL_TEXTURE_2D, tex-tures_indek[0]); //
gl.glTexCoordPointer(3, GL10.GL_FLOAT, 0, makeFloatBuffer(textCoord_Triagle)); //
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRA Y);
gl.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 3);
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
//gl.glDisableClientState(GL10.GL_COLOR_ARRAY);
gl.glDisable( GL10.GL_BLEND ); // Disable Alpha Blend
gl.glDisable( GL10.GL_TEXTURE_2D ); // Disable Texture Mapping
}
public void loadBallTexture(GL10 gl, Context con-text,int index_Texture) {
// Bitmap bitmap = BitmapFacto-ry.decodeResource(context.getResources(),
// resource);
/*Bitmap bitmap = BitmapFacto-ry.decodeStream(context.getResources()
.openRawResource(R.drawable.nature));*/
Bitmap bitmap = BitmapFacto-ry.decodeStream(context.getResources()
.openRawResource(imageFileIDs[index_Texture]));
gl.glGenTextures(1, textures_indek, 0); gl.glBindTexture(GL10.GL_TEXTURE_2D, tex-tures_indek[0]);
//gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE );
//gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE );
gl.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
gl.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
bitmap.recycle(); }
Gambar 5.8 Texture Mapping Pada Segitiga
5.5 Texture Mapping Pada Lingkaran
Source Code 5.2 Code Texture Mapping Pada Lingkaran
ESRender.java
package com.texture_mapping;
import java.util.Formatter;
import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10;
import android.content.Context; import android.opengl.GLES20; import android.opengl.GLSurfaceView; import android.opengl.Matrix;
import android.opengl.GLSurfaceView.Renderer; import android.opengl.GLU;
import android.util.Log; import android.widget.TextView;
public class ESRender implements Renderer {
private ESText glText; private TextView textview;
private ObjectArena objectarena; // the
Context context;
private int RunMode=1;
private float mAngle = 0.0f; //
Angle in degrees
private float AnimateStep = 2.0f; // Rotation step per update
private long startTime; private long fpsStartTime; private long numFrames;
float radius = 50.0f; // Ball's radius float x = radius; // Ball's center (x,y) float y = radius;
float speedX = 5f; // Ball's speed (x,y) float speedY = 3f;
int xMin, xMax, yMin, yMax;
private int mywidth=0; private int myheight=0;
/** Constructor to set the handed over context */ public ESRender(Context context) {
//super();
this.context = context;
this.objectarena = new ObjectArena(); this.objectball = new ObjectBall(); this.objectball_hole = new ObjectBall(); this.objectball1 = new ObjectBall(); this.objectball2 = new ObjectBall();
this.objectball3 = new ObjectBall(); }
@Override
public void onDrawFrame(GL10 gl) {
// Draw background color
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
// menampilkan lingkaran only line with texture
gl.glPushMatrix();
//gl.glScalef(150.0f, 150.0f, 150.0f);
gl.glTranslatef(0.0f, 100.0f, 0.0f);
gl.glLineWidth(1.0f);
gl.glEnable(GL10.GL_LINE_SMOOTH);
object-ball_hole.draw_circle_hole(gl); gl.glPopMatrix();
gl.glPushMatrix();
gl.glLineWidth(1.0f);
gl.glEnable(GL10.GL_LINE_SMOOTH); //bounds.set(x - radius, y - radi-us, x + radiradi-us, y + radius);
gl.glTranslatef(x, y, 0.0f); //gl.glScalef(10.0f,10.0f,10.0f); //gl.glTranslatef(0.0f, 0.0f, -5.0f);
objectball2.draw_circle_color(gl); gl.glPopMatrix();
// menampilkan lingkaran dengan gradasi warna
gl.glPushMatrix();
gl.glLineWidth(1.0f);
gl.glEnable(GL10.GL_LINE_SMOOTH); //bounds.set(x - radius, y - radi-us, x + radiradi-us, y + radius);
gl.glTranslatef(0, 200, 0.0f); //gl.glScalef(10.0f,10.0f,10.0f); //gl.glTranslatef(0.0f, 0.0f, -5.0f);
objectball3.draw_circle_color(gl); gl.glPopMatrix();
//render text
gl.glPushMatrix();
// enable texture + alpha blending // NOTE: this is required for text rendering! we could incorporate it into
// the GLText class, but then it would be called multiple times (which impacts perfor-mance).
gl.glEnable( GL10.GL_TEXTURE_2D ); // Enable Texture Mapping
gl.glEnable( GL10.GL_BLEND ); // Enable Alpha Blend
gl.glBlendFunc( GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA ); // Set Alpha Blend Function
//Log.d(TAG, "Frames per second: " + fps + " (" + numFrames
// + " frames in " + fpsE-lapsed + " ms)");
//}
glText.begin(1.0f, 1.0f, 1.0f, 1.0f); // Begin Text Rendering (Set Color WHITE)
// Keep track of number of frames
drawn
numFrames++;
long fpsElapsed =
Sys-tem.currentTimeMillis() - fpsStartTime;
//if (fpsElapsed > 1 * 1000) { // every 5 seconds
float fps = (numFrames *
1000.0F) / fpsElapsed;
// glText.draw( "Frames per
second : "+ fps + " (" + numFrames + " frames in " + fpsElapsed + " ms)",150, 30); // Draw Test String
fpsStartTime =
Sys-tem.currentTimeMillis();
numFrames = 0;
//}
glText.end(); // End Text Rendering
// disable texture + alpha
gl.glDisable( GL10.GL_BLEND ); // Disable Alpha Blend
gl.glDisable( GL10.GL_TEXTURE_2D ); // Disable Texture Mapping
gl.glPopMatrix();
// // segitiga
// gl.glPushMatrix();
// //GLU.gluLookAt(gl, 0, 0, 0.01f,
0f, 0f, 0f, 0f, 1.0f, 0.0f); //
// gl.glTranslatef(50.0f, 60.0f,
0.0f);
// gl.glScalef(80.0f, 80.0f, 0.0f);
// gl.glRotatef(180, 1.0f, 0.0f,
0.0f);
// gl.glRotatef(mAngle, 0.0f, 1.0f,
0.0f);
// gl.glTranslatef(-0.5f, -0.5f,
0.0f);
// objectball1.draw_segitiga(gl);
// gl.glPopMatrix();
// update
moveWithCollisionDetection(this);
set((int)-radius, (int)-radius, mywidth, myheight);
// Update the rotational angle after each refresh
if (RunMode==1) {
// re-Calculate animation parame-ters
if (mAngle > 360.0) { //CurrentAngle -= 360.0*Math.floor(CurrentAngle/360.0);
mAngle=0.0f;
mAngle += AnimateStep; }
} }
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
gl.glClearColor(0.5f, 0.5f, 0.5f, 1.0f); // Set color's clear-value to black
gl.glClearDepthf(1.0f); // Set depth's clear-value to farthest
gl.glEnable(GL10.GL_DEPTH_TEST); // Ena-bles depth-buffer for hidden
// surface removal
gl.glDepthFunc(GL10.GL_LEQUAL); // The type of depth testing to do
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST); // nice
// perspective
// view
gl.glShadeModel(GL10.GL_SMOOTH); // Ena-ble smooth shading of color
gl.glDisable(GL10.GL_DITHER); // Disable dithering for better
// performance
// Create the GLText
glText = new ESText( gl, context.getAssets() );
// Load the font from file (set size + pad-ding), creates the texture
// NOTE: after a successful call to this the font is ready for rendering!
glText.load( "Roboto-Regular.ttf", 14, 2, 2 ); // Create Font (Height: 14 Pixels / X+Y Padding 2 Pixels)
//gl.glDisable(GL10.GL_DITHER); // Disa-ble dithering for better
// performance
// Setup Texture, each time the surface is created (NEW)
objectball_hole.loadBallTexture(gl, con-text,0);
objectball1.loadBallTexture(gl, context,1);
objectball2.loadBallTexture(gl, context,0); objectball3.loadBallTexture(gl, context,1);
Ena-ble texture (NEW)
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
mywidth=width;
myheight=height;
/*
if (height == 0)
height = 1; // To prevent divide by zero
float aspect = (float) width / height;
mywidth=width; myheight=height;
// Set the viewport (display area) to cover the entire window
gl.glViewport(0, 0, width, height);
// Setup perspective projection, with as-pect ratio matches viewport
gl.glMatrixMode(GL10.GL_PROJECTION); // Select projection matrix
gl.glLoadIdentity(); // Reset projection matrix
gl.glViewport( 0, 0, width, height );
// Setup orthographic projection
gl.glMatrixMode( GL10.GL_PROJECTION ); // Activate Projection Matrix
gl.glLoadIdentity(); // Load Identity Matrix
gl.glOrthof( // Set Ortho Projection
(Left,Right,Bottom,Top,Front,Back) 0, width,
0, height, 1.0f, -10.0f );
// Save width and height
//this.width = width; // Save Current Width
//this.height = height; // Save Current Height
gl.glMatrixMode(GL10.GL_MODELVIEW); // Se-lect model-view matrix
gl.glLoadIdentity(); // Reset
public float getxMax() { return xMax;
}
public void setxMax(int xmax) { xMax = xmax;
}
public float getxMin() { return xMin;
}
public void setxMin(int xmin) { xMin = xmin;
}
public float getyMax() { return yMax;
}
public void setyMax(int ymax) { yMax = ymax;
}
public float getyMin() { return yMin;
}
public void setyMin(int ymin) { yMin = ymin;
}
public float getspeedX() { return speedX;
}
public void setspeedX(float speedX_) { speedX = speedX_;
}
public float getspeedY() { return speedY;
}
public void setspeedY(float speedY_) { speedY = speedY_;
}
public void moveWithCollisionDetection(ESRender esRender) {
// Get new (x,y) position x += speedX;
y += speedY;
// Detect collision and react
if (x + radius > esRender.getxMax()) { speedX = -speedX;
x = esRender.getxMax() - radius; }
else if (x - radius < esRender.getxMin()) {
speedX = -speedX;
x = esRender.getxMin() + radius; }
y = esRender.getyMax() - radius; } else if (y - radius <
esRen-der.getyMin()) {
speedY = -speedY;
y = esRender.getyMin() + radius; }
}
public void set(int x, int y, int width, int height) {
xMin = x;
//xMax = x + width - 1; xMax = x + width; yMin = y;
//yMax = y + height - 1; yMax = y + height; }
}
ESSurfaceView.java
package com.texture_mapping;
import android.content.Context; import android.opengl.GLSurfaceView; import android.util.Log;
import android.view.KeyEvent; import android.view.MotionEvent;
/**
* A view container where OpenGL ES graphics can be drawn on screen.
* This view can also be used to capture touch events, such as a user
* interacting with drawn objects. */
public class ESSurfaceView extends GLSurfaceView {
private final ESRender esRender; private float previousX;
private float previousY;
public ESSurfaceView(Context context) { super(context);
// Set the Renderer for drawing on the GLSur-faceView
esRender = new ESRender(context); setRenderer(esRender);
// To enable keypad
// To enable touch mode
this.setFocusableInTouchMode(true);
// Render the view only when there is a change in the drawing data
// merender hanya ketika ada perubahan/ event
//setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY); }
//private final float TOUCH_SCALE_FACTOR = getWidth() / getHeight();
private float mPreviousX; private float mPreviousY;
@Override
public boolean onTouchEvent(MotionEvent v) { // MotionEvent reports input details from the touch screen
// and other input controls. In this case, we are only
// interested in events where the touch posi-tion changed.
float currentX = v.getX(); float currentY = v.getY();
float deltaX, deltaY;
//float scalingFactor = 0.50f /
((esRen-der.xMax > esRender.yMax) ? esRender.yMax //: esRender.xMax);
switch (v.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.v("Test Action Down", "action down working");
//break;
requestRender();
//case MotionEvent.ACTION_POINTER_UP:
//Log.v("Test Action
ACTION_POINTER_UP", "action working");
//requestRender();
//case MotionEvent.ACTION_MOVE:
//Log.v("Test Action
ACTION_POINTER_DOWN", "action working");
//requestRender();
//case MotionEvent.ACTION_UP:
//Log.v("Test Action Up", "action up working");
//requestRender(); case MotionEvent.ACTION_MOVE:
// Modify rotational angles according to movement
deltaX = currentX - previousX;
deltaY = currentY - previousY;
(del-taX/getWidth()));
//esRender.setspeedY(esRender.getspeedY()+ (del-taY/getHeight()));
esRen-der.setspeedX(esRender.getspeedX()+ deltaX/100);
esRen-der.setspeedY(esRender.getspeedY()+ deltaY/100);
requestRender();
}
// Save current x, y
previousX = currentX;
previousY = currentY;
return true; // Event handled
//break; }
// Key-up event handler
@Override
public boolean onKeyUp(int keyCode, KeyEvent
event) {
switch (keyCode) {
case KeyEvent.KEYCODE_A: // mengurangi
kecepatan object
if((esRender.getspeedX()- 0.05f
>0) ){
esRen-der.setspeedX(esRender.getspeedX()- 0.05f);
}
if((esRender.getspeedX()- 0.05f
<0) ){
esRender.setspeedX(0.0f);
}
if((esRender.getspeedY()- 0.05f
>=0)){
esRen-der.setspeedY(esRender.getspeedY()- 0.05f);
}
if((esRender.getspeedY()- 0.05f
<0) ){
esRender.setspeedY(0.0f);
}
Log.v("Test Action KEYCODE_A",
"action working");
break;
case KeyEvent.KEYCODE_Z:
Log.v("Test Action KEYCODE_Z",
"action working");
break;
}
return true; // Event handled
}
MainActivity.java
package com.texture_mapping;
import com.texture_mapping.R;
import android.opengl.GLSurfaceView; import android.os.Bundle;
import android.app.Activity; import android.view.Menu; import android.view.Window;
import android.view.WindowManager;
public class MainActivity extends Activity {
/** The OpenGL view */
private GLSurfaceView glSurfaceView;
@Override
protected void onCreate(Bundle savedInstanceS-tate) {
super.onCreate(savedInstanceState); //setContentView(R.layout.activity_main);
// requesting to turn the title OFF requestWindowFeature(Window.FEATURE_NO_TITLE); // making it full screen
getWin-dow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCR EEN,
WindowManag-er.LayoutParams.FLAG_FULLSCREEN);
// Initiate the Open GL view and
// create an instance with this activity glSurfaceView = new ESSurfaceView(this);
// set our renderer to be the main renderer with
// the current activity context
//glSurfaceView.setRenderer(new ESRender()); setContentView(glSurfaceView);
}
/**
* Remember to resume the glSurface */
@Override
protected void onResume() { super.onResume();
glSurfaceView.onResume(); }
/**
@O