Bezier Yüzeyi Üretimi ve Işıklandırma Hesabı (C++ / OpenGL )

ekran

#include <stdio.h>
#include <math.h>
#include <GL/glut.h>
 
// 16 adet bezier noktası
GLfloat k[4][4][3] = {
   {{-1.5, -1.5, 4.0}, {-0.5, -1.5, 2.0}, 
    {0.5, -1.5, -1.0}, {1.5, -1.5, 2.0}}, 
   {{-1.5, -0.5, 1.0}, {-0.5, -0.5, 1.0}, 
    {1.5, -0.5, 0.0}, {1.5, -0.5, -1.0}}, 
   {{-1.5, 0.5, 4.0}, {-1.5, 0.5, 0.0}, 
    {0.5, 0.5, 3.0}, {1.5, 0.5, 4.0}}, 
   {{-1.5, 1.5, -2.0}, {-0.5, 1.5, -2.0}, 
    {0.5, 1.5, 0.0}, {3.5, 1.5, -1.0}}
};
 
// Işık kaynağının kordinatı
GLfloat light[3] = {0.5f,1.5f,0.0f} ;
 
// bezier yüzeyinin gerçekçiliği
int hassasiyet = 30;
 
// Kamera yönü için dönüş açısı
float angle = 0.0f;
// Kameranın yönünü temsil eden asıl vektör
float lx=0.0f,lz=-1.0f;
// Kameranın XZ konumu
float x=0.0f, z=5.0f;
// tuş durumları. Bu değişkenler sıfır olacak
// Hiç tuş basımı olmadığında
float deltaAngle = 0.0f;
float deltaMove = 0;
int xOrigin = -1;
 
int faktoriyel(int s){
	if(s <= 1) return 1;
	return s * faktoriyel(s - 1);
}
int permutasyon(int n,int i){
	return faktoriyel(n)/(faktoriyel(i)*faktoriyel(n-i));
}
float ust(float x,int k){
	return (float)pow((double)x,(double)k);
}
 
// Bi,n(u) Bezierin için n.dereceden binom fonksiyonu
float B(int i,int n,float u){
	return ((float)permutasyon(n,i)) * ust(u,i) * ust((1.0f-u),(n-i));
}
 
// p(u,v) - Bezier noktasını veren fonksiyon
float p(float u,float v,int d/* d : dimesion boyut 0x 1y 2z */){
	int i,j; /* cache */
	float out=0; /* çıktı */
 
	for (i = 0; i < 4; i++)
		for (j = 0; j < 4; j++){
			out = out + B(i,3,u) * B(j,3,v) * k[i][j][d];
		}
	return out;
}
 
 
/* 2 nokta arasındaki farkı bulur */
float d(float x1,float y1,float z1,float x2,float y2,float z2){
	return (float)(sqrt((double)(ust((x2-x1),2) + ust((y2-y1),2) + ust((z2-z1),2))));
}
 
 
 
void bezirYuzey(void){ // bu fonksiyon bezier yüzeyi oluşturur
int i,j,v;
float I,f,x[4],y[4],z[4],nx,ny,nz,nd,lx,ly,lz,ld,alfa,calfa,k=0.0000001f;
 
	// ışığın birim vektörünü hesaplayalım
	ld = d(0.0f,0.0f,0.0f,light[0],light[1],light[2]);
	lx = light[0]/ld;
	ly = light[1]/ld;
	lz = light[2]/ld;
 
 
   glPointSize(2.0);
      for (i = 0; i < hassasiyet; i++) 
		for (j = 0; j < hassasiyet; j++) {
			// yüzeyin noktalarını hesapla
			x[0] = p(1.00f*i/hassasiyet,1.00f*j/hassasiyet,0);
			x[1] = p(1.00f*i/hassasiyet,1.00f*(j+1)/hassasiyet,0);
			x[2] = p(1.00f*(i+1)/hassasiyet,1.00f*(j+1)/hassasiyet,0);
			x[3] = p(1.00f*(i+1)/hassasiyet,1.00f*j/hassasiyet,0);
			y[0]= p(1.00f*i/hassasiyet,1.00f*j/hassasiyet,1);
			y[1]= p(1.00f*i/hassasiyet,1.00f*(j+1)/hassasiyet,1);
			y[2]= p(1.00f*(i+1)/hassasiyet,1.00f*(j+1)/hassasiyet,1);
			y[3]= p(1.00f*(i+1)/hassasiyet,1.00f*j/hassasiyet,1);
			z[0] = p(1.00f*i/hassasiyet,1.00f*j/hassasiyet,2);
			z[1] = p(1.00f*i/hassasiyet,1.00f*(j+1)/hassasiyet,2);
			z[2] = p(1.00f*(i+1)/hassasiyet,1.00f*(j+1)/hassasiyet,2);
			z[3] = p(1.00f*(i+1)/hassasiyet,1.00f*j/hassasiyet,2);
 
			// normal vektorü  hesaplayalım
			nx = ((y[1] - y[2]) * (z[2] - z[3])) - ((z[1] - z[2]) * (y[2] - y[3]));
			ny = ((z[1] - z[2]) * (x[2] - x[3])) - ((x[1] - x[2]) * (z[2] - z[3]));
			nz = ((x[1] - x[2]) * (y[2] - y[3])) - ((y[1] - y[2]) * (x[2] - x[3]));
			// normal vektörünün uzunluğu
			nd = d(0.0f,0.0f,0.0f,nx,ny,nz);
			// normal vektörünü, birim vektor haline getirelin
			nx /= nd;
			ny /= nd;
			nz /= nd;
 
 
 
			//alfa ; ışık vektörü ile normal vektörü arasındaki açıdır
			// <n,l> = |n|*|l|*cosALFA; n ve l nin uzunluğu 1dir
			alfa = (float)acos((double)((nx*lx) + (ny*ly) + (nz*lz)));
 
			// calfa = cos(alfa)'dır'
			calfa = (float)cos((double)alfa);
 
			// f : normal(orta nokta) ile ışık kaynağı arası mesafe
			f = d(light[0],light[1],light[2],p(1.00f*(i+0.5f)/hassasiyet,1.00f*(j+0.5f)/hassasiyet,0),p(1.00f*(i+0.5f)/hassasiyet,1.00f*(j+0.5f)/hassasiyet,1),p(1.00f*(i+0.5f)/hassasiyet,1.00f*(j+0.5f)/hassasiyet,2));
 
			// ışık şiddetini hesapla
			I = 1.0f*calfa / (f+k); // ışık fonksiyonu
 
   		   glColor3f(I*0.05f,I,I); // ışıklandırmaya göre yüze renk ver
 
		   glBegin(GL_QUADS); // yüzeyi çiz
			   for(v = 0; v< 4;v++ )
			         glVertex3f(x[v],y[v],z[v]);
		   glEnd();
 
		}
 
}
 
 
 
void changeSize(int w, int h) { //penceri boyutu değişirse
	// sıfırla bölmeyi önle.
	if (h == 0)
		h = 1;
 
	float ratio = w * 1.0 / h;
 
	// Projection Matrisini aktif et
	glMatrixMode(GL_PROJECTION);
 
	// Matrisi resetle
	glLoadIdentity();
 
	// viewport olarak tüm pencereyi set et
	glViewport(0, 0, w, h);
 
	// uygun perspektifi set et.
	gluPerspective(45.0f, ratio, 0.1f, 100.0f);
 
	// Modelview’e geç
	glMatrixMode(GL_MODELVIEW);
}
 
 
void computePos(float deltaMove) { // kamere pozisyonu hesapla
	x += deltaMove * lx * 0.1f;
	z += deltaMove * lz * 0.1f;
}
 
void renderScene(void) {
	int i,j;
	if (deltaMove)
		computePos(deltaMove);
 
	// Color ve Depth Bufferları temizle
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
	// dönüşümleri Resetle
 
	glLoadIdentity();
 
	// kamerayı set et
	gluLookAt(
	x, 1.0f, z,
	x+lx, 1.0f, z+lz,
	0.0f, 1.0f, 0.0f);
 
	// bezier noktalarını çiz
   glPointSize(5.0);
   glColor3f(1.0, 0.0, 0.0);
   glBegin(GL_POINTS);
      for (i = 0; i < 4; i++) 
	for (j = 0; j < 4; j++) 
         glVertex3fv(&k[i][j][0]);
   glEnd();
 
   glPointSize(10.0);
   glColor3f(1.0, 1.0, 0.0);
   glBegin(GL_POINTS);
         glVertex3fv(&light[0]);
   glEnd();
 
 
   // bezier yüzeyini çız
   bezirYuzey();
 
   // bezier yüzeyin noktalarını hareket ver
   /*k[3][3][2] = k[3][3][2] + 0.01f;
   k[1][2][2] = k[1][2][2] - 0.01f;*/
   light[2] += 0.01f;
   light[1] -= 0.001f;
 
   glutSwapBuffers();
}
 
// -----------------------------------//
//KLAVYE
// -----------------------------------
void processNormalKeys(unsigned char key, int xx, int yy) {
	if (key == 27)
		exit(0);
}
void pressKey(int key, int xx, int yy) {
	switch (key) {
		case GLUT_KEY_UP : deltaMove = 0.5f; break;
		case GLUT_KEY_DOWN : deltaMove = -0.5f; break;
	}
}
void releaseKey(int key, int x, int y) {
	switch (key) {
		case GLUT_KEY_UP :
		case GLUT_KEY_DOWN : deltaMove = 0;break;
	}
}
 
// -----------------------------------
//
//FARE
// -----------------------------------
void mouseMove(int x, int y) {// Bu sadece, sol düğme basılı olduğu zaman doğru olacak
	if (xOrigin >= 0) {
		// deltaAngle’i güncelle
		deltaAngle = (x - xOrigin) * 0.001f;
		// kamera'nın yönünü güncelle
		lx = sin(angle + deltaAngle);
		lz = -cos(angle + deltaAngle);
	}
}
void mouseButton(int button, int state, int x, int y) {
	// Sadece eğer sol düğme basılırsa harekete başla
	if (button == GLUT_LEFT_BUTTON) {
		// Düğme bırakıldığı zaman
		if (state == GLUT_UP) {
			angle += deltaAngle;
			xOrigin = -1;
		}
		else {// state = GLUT_DOWN
			xOrigin = x;
		}
	}
}
 
// -----------------------------------
//
//MAIN
// -----------------------------------
int main(int argc, char **argv) {
	// GLUT’u ilkle ve pencereyi yarat
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
	glutInitWindowPosition(100,100);
	glutInitWindowSize(900,900);
	glutCreateWindow("Bezier Egrisi");
	// callbackleri kaydet
	glutDisplayFunc(renderScene);
	glutReshapeFunc(changeSize);
	glutIdleFunc(renderScene);
	glutIgnoreKeyRepeat(1);
	glutKeyboardFunc(processNormalKeys);
	glutSpecialFunc(pressKey);
	glutSpecialUpFunc(releaseKey);
	// iki yeni fonksiyon burada
	glutMouseFunc(mouseButton);
	glutMotionFunc(mouseMove);
	// OpenGL ilklemeleri
	glEnable(GL_DEPTH_TEST);
	glEnable(GL_CULL_FACE);
 
	// GLUT olay işleme döngüsüne gir
	glutMainLoop();
	return 0;
}

Bezir Eğrisi üretimi ( C ve OpenGL, glut ile )

bezier

#include <stdlib.h>
#include <GL/glut.h>

#define EKRAN 720

/*
   ### CC BY-SA Lisansı ###

http://ozgurlisanslar.org.tr/creative-commons/attribution-sharealike-cc-by-sa/

   Faruk Can tarafından geliştirildi.
   Hakları Saklıdır. ve Faruk Can'a aittir
   Lütfen alıntı yaptığınızı belirtiniz.
   omer@farukcan.net
*/

GLfloat p[4][2] = {
    {-0.9f,0}, // p0
    {0.1f,0.9f}, // p1
    {0.5,0.9f}, // p2
    {0.9f,0} // p3
}; // 4 adet bezier noktası

int hassasiyet = 5; // bezier eğirisinin kaç çizgiden oluşacağını belirler 

// fonk - draw - görüntüyü çizer
void draw (void)
{

   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // önceki görüntüyü temizle

   bezierEgrisi(hassasiyet);
   bezierNoktalari();

   glFlush();

}//enddraw

// fonk - c - bezier noktalarını oluşturan formül c(t) = p0*(1-t)^3 + 3p1*t*(1-t)^2 + 3p2t^2(1-t) + p3t^3
GLfloat c (
    /* in */ GLfloat t,
    /* in */ int y)
{

    /*out*/ return p[0][y]*(1.0f-t)*(1.0f-t)*(1.0f-t) + 
            3*p[1][y]*t*(1.0f-t)*(1.0f-t) + 
            3*p[2][y]*t*t*(1.0f-t) + 
            p[3][y]*t*t*t;
} //endc

// fonk - bezierEgrisi - bezir egrisi çizer
void bezierEgrisi (
   /* in */        int hassasiyet )
{
   /* cache */    int i;

   glColor3f(1.0, 1.0, 1.0); // beyaz renkte çiz

   glBegin(GL_LINE_STRIP);

    for(i = 0 ; i<=hassasiyet ; i++)
        glVertex3f(c(1.00f*i/hassasiyet,0),c(1.00f*i/hassasiyet,1),0.0f);

   glEnd();
}

// fonk - bezierNoktalari - bezir noktalarını çizer
void bezierNoktalari (
    /* - */ void)
{
   /* cache */ int i;

   glColor3f(1.0, 0.0, 0.0); // kırmızı renkte çiz
   glPointSize(5.0f); // 5kat büyük nokta
   glBegin(GL_POINTS);
    for (i = 0; i < 4; i++)
        glVertex3f(p[i][0],p[i][1],0.0f);
   glEnd();

}

// fonk - farkkare - iki nokta arası farkın karesidir
float farkkare(float x,float y,float m,float n){
    return (m-x)*(m-x) + (n-y)*(n-y); 
} 

// mouse ün koordinat düzlemini, opengl koordinat düzlemi çevirirler.
float ekran2koorx(float x){
    return (((float)x/(float)EKRAN))*2 -1;
}
float ekran2koory(float x){
    return (((float)x/(float)EKRAN))*-2 + 1;
}

// yeri değiştirmek üzere seçilen noktadır
int secili_nokta=0;
// fonk - mousea tıklandığında en yakın noktayı seçer
void bezir_noktasi_sec( int x, int y){
    float min=2.0f,d;
    int i;
    for (i = 0; i < 4; i++){
        d = farkkare(ekran2koorx(x),ekran2koory(y),p[i][0],p[i][y]);
        printf("fark nokta %f\n",d );

        if( d < min){
            min = d;
            secili_nokta = i;            
        }
    }
    printf("secili nokta %i\n",secili_nokta );
}

// fonk - seçili noktanın koordinatlarını değiştirir
void bezir_noktasi_degistir(int x, int y){
 p[secili_nokta][0] = ekran2koorx(x);
 p[secili_nokta][1] = ekran2koory(y);
}

void keyboard(unsigned char key, int x, int y){
    printf("%c %i | %i %i \n",key,key,x,y );
    if(key==43) hassasiyet+=1; // hassasiyeti arttır + tuşu
    if(key==45) hassasiyet-=1; // hassasiyeti azalt - tuşu
    if(key==104) printf("hassasiyet : %i\n",hassasiyet ); // h tuşu
}
void skeyboard(unsigned char key, int x, int y){
    printf("skey %i | %i %i \n",key,key,x,y );
}

void mouse(int buton,int durum,int x,int y){
    printf("mouse %i %i %i %i\n",buton,durum,x,y );
    if(buton==0 && durum==0) bezir_noktasi_sec(x,y); // mouse tıklmasında en yakın nokta sec
    else if((buton==0 && durum==1) ) bezir_noktasi_degistir(x,y); // en yakın noktayı değiştir
}

int main(int argc, char** argv)
{
   glutInit(&argc, argv);
   glutInitDisplayMode (GLUT_ALPHA | GLUT_RGBA);

   glutInitWindowSize (EKRAN, EKRAN); //pencere boyutu
   glutInitWindowPosition (100, 100); // pencerenin ana konumu

   glutCreateWindow (argv[0]);

   glutIdleFunc(draw);
   glutKeyboardFunc(keyboard);
   glutSpecialFunc(skeyboard);
   glutMouseFunc(mouse);

   glutMainLoop();

   return 0;
}