Здравствуйте. Такая проблема. Нужно, чтобы на вращающейся фигуре отображались тени в зависимости от источника света. В данном случае получилось только затемнить фигуру полностью. Подскажите, в чем проблема, пожалуйста.
Код:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls,OpenGL;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormPaint(Sender: TObject);
procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
procedure FormMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure FormResize(Sender: TObject);
procedure FormMouseWheel(Sender: TObject; Shift: TShiftState;
WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
procedure FormDestroy(Sender: TObject);
procedure FormKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
private
{ Private declarations }
DC : HDC;
hrc: HGLRC;
ry : GLfloat;
light0_position: array [0..3] of glfloat;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
const
CW = 8; //количество точек объекта
CP = 12; //количество полигонов
type
T3DPoint = record
X, Y, Z: Integer;
end;
T2DPoint = TPoint;
var
W: array [1..CW] of T3DPoint; //мировые координаты
V: array [1..CW] of T2DPoint; //видовые координаты
Z: array [1..CW] of Integer; //глубина точек
P: array [1..CP] of record //полигоны
A: array [1..3] of Byte; //номера точек, из которых состоит полигон
mZ: Integer; //среднее значение глубины полигона
end;
Sort: array [1..CP] of Byte; //массив для сортировки
Scale: Integer; //масштаб
Teta, Phi: Single; //углы
BufMain, BufEmpty: TBitMap; //буферы для вывода и очистки
MDown: Boolean; //нажата ли кнопка мыши
MPos: T2DPoint; //положение курсора мыши
procedure Get2D;
var I: Integer;
begin
//преобразование мировых координат в видовые с помощью
//матрицы преобразований
for I := 1 to CW do
begin
V[I].X := Round(Scale * (
W[I].X*(- Sin(Teta)) +
W[I].Y*( Cos(Teta)))) + Form1.Width shr 1;
V[I].Y := Round(Scale * (
W[I].X*( Cos(Phi) * Cos(Teta)) +
W[I].Y*( Cos(Phi) * Sin(Teta)) +
W[I].Z*(- Sin(Phi)))) + Form1.Height shr 1;
Z[I] := Round(Scale * (
W[I].X*(- Sin(Phi) * Cos(Teta)) +
W[I].Y*(- Sin(Phi) * Sin(Teta)) +
W[I].Z*(- Cos(Phi))));
end;
//нахождение средней глубины полигонов:
//так как данная глубина кроме сортировки нигде не используется, то
//можно опустить деление на 3 - это увеличит производительность
//алгоритма, сохранив его функциональность
for I := 1 to CP do
P[I].mZ := Z[P[I].A[1]] + Z[P[I].A[2]] + Z[P[I].A[3]];
end;
procedure DrawTriangle(A1, A2, A3: T2DPoint);
var
A: array [1..3] of T2DPoint;
begin
A[1] := A1;
A[2] := A2;
A[3] := A3;
BufMain.Canvas.Polygon(A);
end;
procedure DrawPolygon(A1, A2, A3: T2DPoint);
var Nz: Integer;
begin
//сначала нужно посчитать Z-составляющую нормали, чтобы знать,
//нужно ли вообще рисовать полигон
Nz := A1.X * (A2.Y - A3.Y) + A2.X * (A3.Y - A1.Y) + A3.X * (A1.Y - A2.Y);
//если полигон виден, то нарисовать его
if Nz < 0 then
DrawTriangle(A1, A2, A3);
end;
procedure DrawObject;
var
B: Boolean;
I: Integer;
begin
//очистить буфер от старого изображения
BufMain.Canvas.Draw(0, 0, BufEmpty);
//сортировка граней
B := True;
while B do
begin
B := False;
for I := 1 to (CP - 1) do
//если глубина меньше, то переместить ближе к концу массива
if (P[Sort[I]].mZ < P[Sort[I + 1]].mZ) then
begin
Sort[I] := Sort[I] + Sort[I + 1];
Sort[I + 1] := Sort[I] - Sort[I + 1];
Sort[I] := Sort[I] - Sort[I + 1];
B := True;
end;
end;
//нарисовать полигоны
for I := 1 to CP do
DrawPolygon(V[P[Sort[I]].A[1]], V[P[Sort[I]].A[2]], V[P[Sort[I]].A[3]]);
//вывести содержимое на экран
Form1.Canvas.Draw(0, 0, BufMain);
end;