Смекни!
smekni.com

Текст программы 19 2 Результат работы программы 21 2 Пружина 22 2 Введение 22 (стр. 2 из 3)

При отображении куба прорисовываем только те ребра, которые видны наблюдателю. Определяется это с помощью направление нормали: если координата z нормали положительная, значит, отображаем ребра грани и нормаль, иначе нет.

2.1.2.3. Текст программы

Kub_form.cpp

#include <vcl.h>

#pragma hdrstop

#include "Kub2.h"

#include "Kub_form_2.h"

//-------------------------------------------------------

#pragma package(smart_init)

#pragma resource "*.dfm"

TForm1 *Form1;

//-------------------------------------------------------

__fastcall TForm1::TForm1(TComponent* Owner)

: TForm(Owner)

{

disp=new Display(200,200,600,600,0.01,0.01,Form1->Canvas);

kub=new Kub();

}

//-------------------------------------------------------

void __fastcall TForm1::Timer1Timer(TObject *Sender)

{

disp->Clear();

Vector v(10,10,-3);

v=v/(!v);

Matrix A=Rotate(v,0.1);

kub->Transform(A);

kub->Show();

}

Kub.h

#include "Disp.h"

#include "Vector.h"

#include "Matrix.h"

Display * disp;

class Kub

{

Vector Ver[8],Norm[6],points[6];

int Gran[6][4];

public:

Kub()

{

Ver[0]=Vector(0,0,0);

Ver[1]=Vector(1,0,0);

Ver[2]=Vector(1,1,0);

Ver[3]=Vector(0,1,0);

Ver[4]=Vector(0,0,1);

Ver[5]=Vector(1,0,1);

Ver[6]=Vector(1,1,1);

Ver[7]=Vector(0,1,1);

Norm[0]=(Ver[1]-Ver[0])^(Ver[4]-Ver[0]);

Norm[1]=(Ver[2]-Ver[1])^(Ver[5]-Ver[1]);

Norm[2]=(Ver[7]-Ver[3])^(Ver[2]-Ver[3]);

Norm[3]=(Ver[4]-Ver[0])^(Ver[3]-Ver[0]);

Norm[4]=(Ver[5]-Ver[4])^(Ver[7]-Ver[4]);

Norm[5]=(Ver[3]-Ver[0])^(Ver[1]-Ver[0]);

for(int i=0;i<6;i++)

{

Norm[i]=Norm[i]/!Norm[i];

}

for(int i=0;i<4;i++)

{

Gran[4][i]=i+4;

}

Gran[5][0]=0;

Gran[5][1]=3;

Gran[5][2]=2;

Gran[5][3]=1;

Gran[0][0]=0;

Gran[0][1]=1;

Gran[0][2]=5;

Gran[0][3]=4;

Gran[1][0]=1;

Gran[1][1]=5;

Gran[1][2]=6;

Gran[1][3]=2;

Gran[2][0]=2;

Gran[2][1]=3;

Gran[2][2]=7;

Gran[2][3]=6;

Gran[3][0]=3;

Gran[3][1]=0;

Gran[3][2]=4;

Gran[3][3]=7;

Vector s=Vector(0,0,0);

for(int j=0;j<6;j++)

{

s=(0, 0, 0);

for(int i=0;i<4;i++)

{

s=s+Ver[Gran[j][i]];

}

s=s/4;

points[j]=s;

}

}

void Show()

{

for(int j=0;j<6;j++)

{

// отображаем только видимые ребра и нормали

if(Norm[j].z>0)

{

disp->MoveTo(Ver[Gran[j][0]].x,Ver[Gran[j][0]].y);

for(int i=1;i<4;i++)

{

disp->LineTo(Ver[Gran[j][i]].x,Ver[Gran[j][i]].y);

}

disp->LineTo(Ver[Gran[j][0]].x,Ver[Gran[j][0]].y);

disp->MoveTo(points[j].x,points[j].y);

disp->LineTo(Norm[j].x+points[j].x,Norm[j].y+points[j].y);

}//if

}

}

void Transform(Matrix & M)

{

for(int i=0;i<6;i++)

{

points[i]=M*points[i];

}

for(int i=0;i<8;i++)

{

Ver[i]=M*Ver[i];

}

Matrix M1=M;

M1.Invert();

M1.Transpose();

for(int i=0;i<6;i++)

{

Norm[i]=M1*Norm[i];

}

}

};

2.1.2.4. Результат работы программы

Результат работы программы рисования куба с нормалями приведен на Рис. 7.

Рис. 7

2.2. OpenGL

2.2.1. Поверхность

2.2.1.1. Введение

Поверхность задана формулой:

Z (x, y) = (sin x2 + cos y2 ) xy

2.2.1.2. Решение

Функцию будем искать учитывая:

x

[– 0,8; 0,8]

y

[– 1,5; 1,5]

Шаг итерации равен 0,03.

Для правильного отображения освещения необходимо найти нормали в каждой точке поверхности.

F (x, y, z) = 0, z = f(x, y), т.е. F = f(x, y) – z = 0,

Следовательно, нормали вычислим так:

Найдем частные производные:

= 2 x x y cos x2+(sin x2 + cos y2) y

= – 2 x y y sin y2+x (sin x2 + cos y2)

2.2.1.3. Текст программы

double Z(double x,double y)

{

double z=(sin(x*x)+cos(y*y))*x*y;

return z;

}

double dZx(double x,double y)

{

double pr=2*x*x*y*cos(x*x)+(sin(x*x)+cos(y*y))*y;

return pr;

}

//-------------------------------------------------------------------

double dZy(double x,double y)

{

double pr=(-2)*x*y*y*sin(y*y)+x*(sin(x*x)+cos(y*y));

return pr;

}

//-------------------------------------------------------------------

void Draw()

{

Vector Norm;

glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);

for(double x=-0.8; x<0.8; x=x+0.03)

{

for(double y=-1.5; y<1.5; y=y+0.03)

{

glBegin (GL_QUADS);

glTexCoord2d(0, 0);

Norm=Vector(dZx(x,y),dZy(x,y),-1);

glNormal3d(Norm.x,Norm.y,Norm.z);

glVertex3d(x,y,Z(x,y));

glTexCoord2d(0, 1);

Norm=Vector(dZx(x+1,y),dZy(x+1,y),-1);

glNormal3d(Norm.x,Norm.y,Norm.z);

glVertex3d(x+1,y,Z(x+1,y));

glTexCoord2d(1,1);

Norm=Vector(dZx(x+1,y+1),dZy(x+1,y+1),-1);

glNormal3d(Norm.x,Norm.y,Norm.z);

glVertex3d(x+1,y+1,Z(x+1,y+1));

glTexCoord2d(1,0);

Norm=Vector(dZx(x,y+1),dZy(x,y+1),-1);

glNormal3d(Norm.x,Norm.y,Norm.z);

glVertex3d(x,y+1,Z(x,y+1));

glEnd();

}

}

}

//----------------------- Рисование сцены --------------------------

void __fastcall TFormMain::DrawObjects()

{

glBindTexture(GL_TEXTURE_2D,texture1);

Draw();

}

2.2.1.4. Результат работы программы

Результат работы программы рисования поверхности приведен на Рис. 8.

Рис. 8

2.2.2. Пружина

2.2.2.1. Введение

Пружина – модификация тора, получаемая из последнего путем распространения вдоль оси OZ, при этом большой радиус не меняется.

Формула пружины:

x = (R + r cos(f)) sin(k w),

y = (R + r cos(f)) cos(k w),

z = r sin(f) + k w,

где k – константа, определяющая шаг витков спирали по высоте. Углы f и w должны изменяться в полном круговом диапазоне, например от 0 до 360.

2.2.2.2. Решение

Поверхность пружины полностью определена формулами (см. пункт «2.2.2.1. Введение»).

Для правильного отображения освещения необходимо найти нормали в каждой точке поверхности пружины. Нормали вычислим, используя класс VECTOR, где нормали определяются в соответствии правилу:

1. Берем два вектора лежащих в одной плоскости полигона и исходящих из одной точки

и
.

Координаты этих векторов определяются так:

V1 (x1, y1, z1), V2(x2, y2, z2) – две вершины, тогда вектор, проходящий через эти точки равен

= (x2-x1, y2-y1, z2-z1)

2. Вычисляем

, векторное произведение векторов
и

=
x
= ( (ay bz – az by), (ax bz – az bx), (ax by – ay bx) )

и
, значит
– нормаль к полигону.

Затем на поверхность пружины накладываем текстуру, которую берем из bmp-файла.

2.2.2.3. Текст программы

void DrawPruzina(double R,double r,double x,double y,double z)

{

const int N=50; // число хорд в окружности

const int M=200; // число окружностей в пружине

const int k=2; // константа, определяющая число витков пружины

Vector V[N][M];

Vector Norm[N][M];

Vector NormV[N][M];

glTranslatef(x,y,z);

glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);

//вычисление вершин

for(int i=0;i<N;i++)

{

for(int j=0;j<M;j++)

{

V[i][j].x=(R+r*cos(i*2*3.14/N))*sin(j*k*2*3.14/M);

V[i][j].y=(R+r*cos(i*2*3.14/N))*cos(j*k*2*3.14/M);

V[i][j].z=r*sin(i*2*3.14/N)+k*j*3.14/M;

}

}

//вычисление нормалей к полигонам

for(int i=0;i<N-1;i++)

{

for(int j=0;j<M-1;j++)

{

Norm[i][j]=(V[i+1][j]-V[i][j])^(V[i][j+1]-V[i][j]);

Normalize( Norm[i][j]);

}

}

for(int i=0;i<N-1;i++)

{

Norm[i][M-1]=(V[i+1][M-1]-V[i][M-1])^(V[i][0]-V[i][M-1]);

Normalize(Norm[i][M-1]);

}

for(int j=0;j<M-1;j++)

{

Norm[N-1][j]=(V[0][j]-V[N-1][j])^(V[N-1][j+1]-V[N-1][j]);

Normalize(Norm[N-1][j]);

}

Norm[N-1][M-1]=(V[0][M-1]-V[N-1][M-1])^(V[N-1][0]-V[N-1][M-1]);

Normalize( Norm[N-1][M-1]);

//вычисление нормалей к вершинам

for(int i=1;i<N;i++)

{

for(int j=1;j<M;j++)

{

NormV[i][j]=(Norm[i][j]+Norm[i-1][j]+Norm[i][j-1]+Norm[i-1][j-1])/4;

Normalize(NormV[i][j]);

}

}

for(int i=1;i<N;i++)

{

NormV[i][0]=(Norm[i][0]+Norm[i-1][0]+Norm[i][M-1]+Norm[i-1][M-1])/4;

Normalize(NormV[i][0]);

}

for(int j=1;j<M;j++)

{

NormV[0][j]=(Norm[0][j]+Norm[N-1][j]+Norm[0][j-1]+Norm[N-1][j-1])/4;

Normalize(NormV[0][j]);

}

NormV[0][0]=(Norm[0][0]+Norm[N-1][0]+Norm[0][M-1]+Norm[N-1][M-1])/4;

Normalize(NormV[0][0]);

// рисуем пружину

glBegin(GL_QUADS);

for(int i=0;i<N-1;i++)

{

for(int j=0;j<M-1;j++)

{

glNormal3d(NormV[i][j].x,NormV[i][j].y,NormV[i][j].z);

glTexCoord2d((double)i/N,(double)j/M);

glVertex3d(V[i][j].x,V[i][j].y,V[i][j].z);

glNormal3d(NormV[i+1][j].x,NormV[i+1][j].y,NormV[i+1][j].z);

glTexCoord2d((double)(i+1)/N,(double)j/M);

glVertex3d(V[i+1][j].x,V[i+1][j].y,V[i+1][j].z);

glNormal3d(NormV[i+1][j+1].x,NormV[i+1][j+1].y,NormV[i+1][j+1].z);

glTexCoord2d((double)(i+1)/N,(double)(j+1)/M);

glVertex3d(V[i+1][j+1].x,V[i+1][j+1].y,V[i+1][j+1].z);

glNormal3d(NormV[i][j+1].x,NormV[i][j+1].y,NormV[i][j+1].z);

glTexCoord2d((double)i/N,(double)(j+1)/M);

glVertex3d(V[i][j+1].x,V[i][j+1].y,V[i][j+1].z);

}

}

glEnd();

}

//-------------------------- Рисование сцены ------------------------------

void __fastcall TFormMain::DrawObjects()

{

glBindTexture(GL_TEXTURE_2D,texture1);

DrawPruzina(3,1,0,0,0);

}

//------------------- Загружаем текстуру из файла -------------------------

void __fastcall TFormMain::SetupTextures()

{

bitmap = new Graphics::TBitmap;

bitmap->LoadFromFile("pic.bmp");

GLubyte bits1[64][64][4];

GLubyte bits2[64][64][4];

GLubyte bits3[64][64][4];

for(int i = 0; i < 64; i++)

{

for(int j = 0; j < 64; j++)

{

bits1[i][j][0]= (GLbyte)GetRValue(bitmap->Canvas->Pixels[i][j]);

bits1[i][j][1]= (GLbyte)GetGValue(bitmap->Canvas->Pixels[i][j]);

bits1[i][j][2]= (GLbyte)GetBValue(bitmap->Canvas->Pixels[i][j]);

bits1[i][j][3]= (GLbyte)255;

}

}

glPixelStorei(GL_UNPACK_ALIGNMENT, 4);

glGenTextures(1, &texture1);

glBindTexture(GL_TEXTURE_2D, texture1);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);