При отображении куба прорисовываем только те ребра, которые видны наблюдателю. Определяется это с помощью направление нормали: если координата z нормали положительная, значит, отображаем ребра грани и нормаль, иначе нет.
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];
}
}
};
Результат работы программы рисования куба с нормалями приведен на Рис. 7.
Рис. 7
2.2. OpenGL
Поверхность задана формулой:
Z (x, y) = (sin x2 + cos y2 ) xy
Функцию будем искать учитывая:
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)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();
}
Результат работы программы рисования поверхности приведен на Рис. 8.
Рис. 8
Пружина – модификация тора, получаемая из последнего путем распространения вдоль оси 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.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-файла.
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);