Контрольная работа — «3D-программирование»
Задание
Написать программу, создающую трёхмерное изображение цилиндрической поверхности (цилиндра) с текстурой. На изображении должны присутствовать также мировые координатные оси (X, Y, Z) и координатные оси, соответствующие локальной системе координат выводимого объекта (цилиндра). При выводе цилиндра следует применить операции поворота, переноса и масштабирования. Программа должна предоставлять пользователю возможность осуществлять поворот и приближение/отдаление изображения при помощи мыши.
Параметры задания определяются по номеру зачётной книжки (N) по следующим формулам:
| Параметр | Обозначение | Формула
(N – номер зачётной книжки, Mod – операция взятия остатка от деления) |
| Высота цилиндра | H | H = 8.0 + (N Mod 400.0) / 1000.0 |
| Радиус цилиндра | R | R = 2.5 + (N Mod 100.0) / 100.0 |
| Масштабирование по оси X | Sx | Sx = 0.7 + (N Mod 600.0) / 1000.0 |
| Масштабирование по оси Y | Sy | Sy = 0.8 + (N Mod 400.0) / 1000.0 |
| Масштабирование по оси Y | Sz | Sz = 0.9 + (N Mod 200.0) / 1000.0 |
| Поворот по оси X (градусов) | Rx | Rx = -20 + (N Mod 400.0) / 10.0 |
| Поворот по оси Y (градусов) | Ry | Ry = -30 + (N Mod 600.0) / 10.0 |
| Поворот по оси Z (градусов) | Rz | Rz = -45 + (N Mod 900.0) / 10.0 |
| Перенос по оси X | Tx | Tx = -5 + (N Mod 250.0) / 25.0 |
| Перенос по оси Y | Ty | Ty = -4 + (N Mod 560.0) / 70.0 |
| Перенос по оси Z | Tz | Tz = -3 + (N Mod 360.0) / 60.0 |
Пример решения
Предположим, параметры задания следующие:
| Параметр | Обозначение | Значение |
| Высота цилиндра | H | 10 |
| Радиус цилиндра | R | 3 |
| Масштабирование по оси X | Sx | 1,5 |
| Масштабирование по оси Y | Sy | 1 |
| Масштабирование по оси Y | Sz | 1 |
| Поворот по оси X (градусов) | Rx | 0 |
| Поворот по оси Y (градусов) | Ry | 30 |
| Поворот по оси Z (градусов) | Rz | 45 |
| Перенос по оси X | Tx | 2 |
| Перенос по оси Y | Ty | 4 |
| Перенос по оси Z | Tz | 0 |
В полном коде решения, приведённом ниже, подставляем указанные значения параметров в код создания цилиндра (в функции InitD3D):
// Матрица мирового преобразования:
const D3DXMATRIX worldMatrix = MatrixIdentity() * Scale(1.5, 1, 1) * RotX(0) * RotY(30) * RotZ(45) * Trans(2, 4, 0);
const shared_ptr<GraphicObject_Base> ptr(new Cylinder(
device, // устройство вывода
10, // высота
3, // радиус
worldMatrix, // матрица мирового преобразования
L»MyTexture.bmp» // путь к файлу текстуры
));
vecGraphObjects.push_back(ptr);
Изображение текстуры удобно подготовить в графическом редакторе MS Word или аналогичном; текстуру следует сохранить в формате .bmp. Рисунок и размеры изображения следует подобрать из условий обеспечения качественного отображения.
Пример текстуры (файл “MyTexture.bmp”):

Полный пример решения:
// Макрос для включения поддержки Windows NT 4.0 и выше:
#define _WIN32_WINNT 0x0400
/* Заголовочные файлы: */
#include <vector>
#include <functional>
#include <memory>
#include «windows.h»
#include «windowsx.h»
#include «comip.h»
#include «d3d9.h»
#include «d3dx9.h»
#include «D3d9types.h»
/* Библиотечные файлы DirectX: */
#pragma comment (lib, «d3d9.lib»)
#pragma comment (lib, «d3dx9.lib»)
/* Библиотечный файл для поддержки интеллектуального указателя _com_ptr_t: */
#pragma comment(lib, «comsuppw.lib»)
using namespace std;
#define TEST_EXPR(Expr) if (! (Expr)) throw runtime_error(«Test failed: «#Expr);
// ============================
/* Макрос для объявления типов интеллектуальных указателей на COM-интерфейсы (DirectX): */
#ifdef DECL_COM_PTR_BY_IID
#error DECL_COM_PTR_BY_IID already defined!!!
#else
#define DECL_COM_PTR_BY_IID(T) \
typedef _com_ptr_t<_com_IIID<T, &IID_##T> > T##Ptr;
#endif // DECL_COM_PTR_BY_IID
// ============================
/* Объявления типов интеллектуальных указателей на интерфейсы DirectX, используемые в программе:*/
DECL_COM_PTR_BY_IID(IDirect3D9) // Среда выполнения Direct3D
DECL_COM_PTR_BY_IID(IDirect3DDevice9) // Устройство вывода
DECL_COM_PTR_BY_IID(IDirect3DVertexBuffer9) // Буфер вершин
DECL_COM_PTR_BY_IID(ID3DXMesh) // Пространственная сетка
DECL_COM_PTR_BY_IID(IDirect3DTexture9) // Текстура
DECL_COM_PTR_BY_IID(ID3DXBuffer) // Буфер
// =====================================
/* Получение единичной матрицы: */
D3DXMATRIX MatrixIdentity() { D3DXMATRIX m; ::D3DXMatrixIdentity(&m); return m; }
/* Получение матриц преобразований: */
// Поворот относительно оси X:
D3DXMATRIX RotX(const float degree) { D3DXMATRIX m; ::D3DXMatrixRotationX(&m, D3DXToRadian(degree)); return m; }
// Поворот относительно оси Y:
D3DXMATRIX RotY(const float degree) { D3DXMATRIX m; ::D3DXMatrixRotationY(&m, D3DXToRadian(degree)); return m; }
// Поворот относительно оси Z:
D3DXMATRIX RotZ(const float degree) { D3DXMATRIX m; ::D3DXMatrixRotationZ(&m, D3DXToRadian(degree)); return m; }
// Перенос по осям X, Y, Z:
D3DXMATRIX Trans(const float dx, const float dy, const float dz)
{ D3DXMATRIX m; ::D3DXMatrixTranslation(&m, dx, dy, dz); return m; }
// Масштабирование по осям X, Y, Z:
D3DXMATRIX Scale(const float sx, const float sy, const float sz)
{ D3DXMATRIX m; ::D3DXMatrixScaling(&m, sx, sy, sz); return m; }
// =====================================
/* Информация о вершине (для трёхмерных изображений без освещения, c собственным цветом) (*) */
struct Vertex_XYZ_DIFFUSE
{
// Дескриптор формата FVF:
enum { eFormat = D3DFVF_XYZ | D3DFVF_DIFFUSE, };
FLOAT x_, y_, z_; // координаты узла в пространстве
DWORD color_; // цвет вершины
//
Vertex_XYZ_DIFFUSE() { ::ZeroMemory(this, sizeof(*this)); }
Vertex_XYZ_DIFFUSE(const FLOAT x, const FLOAT y, const FLOAT z, const COLORREF color)
: x_(x), y_(y), z_(z)
, color_(D3DCOLOR_XRGB(GetRValue(color), GetGValue(color), GetBValue(color)))
{}
Vertex_XYZ_DIFFUSE(const D3DXVECTOR3& vecCoord, const COLORREF color)
: x_(vecCoord.x), y_(vecCoord.y), z_(vecCoord.z)
, color_(D3DCOLOR_XRGB(GetRValue(color), GetGValue(color), GetBValue(color)))
{}
};
// =====================================
// =====================================
/* Информация о вершине (для трёхмерных изображений без освещения, но с текстурой) (*): */
struct Vertex_XYZ_TEX
{
// Дескриптор формата FVF:
enum { eFormat = D3DFVF_XYZ | D3DFVF_TEX1, };
FLOAT x_, y_, z_; // координаты узла в пространстве
FLOAT tu_, tv_; // координаты текстуры (в диапазоне [0; 1]):
//
Vertex_XYZ_TEX() { ::ZeroMemory(this, sizeof(*this)); }
};
// ========================================
/* Получение описания буфера вершин: */
D3DVERTEXBUFFER_DESC GetVertexBufferDescr(
IDirect3DVertexBuffer9Ptr& vertexBufferPtr
)
{
D3DVERTEXBUFFER_DESC d;
vertexBufferPtr->GetDesc(&d);
return d;
}
// =========================================
// =========================================
// Получение кол-ва вершин в буфере:
template<class VertexType>
UINT GetNumberOfVerticesInBufferT(
IDirect3DVertexBuffer9Ptr& vertexBufferPtr // буфер вершин
)
{
const D3DVERTEXBUFFER_DESC vertexBuffDescr =
GetVertexBufferDescr(vertexBufferPtr);
// Проверка формата:
const DWORD format = vertexBuffDescr.FVF;
TEST_EXPR(format == VertexType::eFormat)
// Проверка размера:
TEST_EXPR((vertexBuffDescr.Size % sizeof(VertexType)) == 0)
return vertexBuffDescr.Size / sizeof(VertexType);
}
// =====================================
// =====================================
/* Объект для блокирования буфера вершин и получения доступа к его данным: */
template<class VertexType>
struct VertexBufferLock
{
private:
IDirect3DVertexBuffer9Ptr& vertexBuffer_;
VOID* pData_;
UINT nVertices_;
public:
VertexBufferLock(IDirect3DVertexBuffer9Ptr& vertexBuffer)
: vertexBuffer_(vertexBuffer)
, pData_(NULL)
, nVertices_(GetNumberOfVerticesInBufferT<VertexType>(vertexBuffer))
{
if (FAILED(this->vertexBuffer_->Lock(
0, // смещение от начала буфера
0, // кол-во блокируемых байт (‘0’ — блокирование всего буфера)
&this->pData_, // [out] — указатель на область данных
0 // флаги (не используются)
)))
throw runtime_error(«Unable lock vertex buffer.»);
}
~VertexBufferLock() { this->vertexBuffer_->Unlock(); }
VOID* GetDataPointer() const { return this->pData_; }
UINT GetNumberOfVertices() const { return this->nVertices_; }
VertexType& At(const UINT iVertex)
{
TEST_EXPR(this->pData_)
TEST_EXPR(iVertex < this->nVertices_)
VertexType* const pVertex = reinterpret_cast<VertexType*>(this->pData_) + iVertex;
return *pVertex;
}
};
// =================================================
/* Объект для установки текущей текстуры: */
struct TextureSentry
{
private:
IDirect3DDevice9Ptr devicePtr_; // устройство вывода
IDirect3DTexture9Ptr texturePtr_; // текстура
public:
TextureSentry(const IDirect3DDevice9Ptr& devicePtr, const IDirect3DTexture9Ptr& texturePtr)
: devicePtr_(devicePtr), texturePtr_(texturePtr)
{
this->devicePtr_->SetTexture(0, this->texturePtr_); // set current texture
}
~TextureSentry() { this->devicePtr_->SetTexture(0, NULL); /* set NULL texture */ }
};
// =======================================
/* Создание буфера вершин: */
template<class VertexType>
void SetVertexBufferT(
IDirect3DDevice9Ptr& devicePtr, // устройство вывода
IDirect3DVertexBuffer9Ptr& vertexBufferPtr, // буфер вершин
const vector<VertexType>& vecVertices // данные для помещения в буфер вершин
)
{
// Очистка старых данных:
if (vertexBufferPtr)
vertexBufferPtr.Release();
if (vecVertices.empty())
return;
// Кол-во узлов:
const UINT nVertices = UINT(vecVertices.size());
// Формат вершины (FVF):
const DWORD format = VertexType::eFormat;
// Длина буфера в байтах:
const UINT dataLenBytes = nVertices * sizeof VertexType;
// Создание нового буфера:
if (FAILED(devicePtr->CreateVertexBuffer(
dataLenBytes, // длина в байтах
0, // тип использования
format, // формат вершины
D3DPOOL_MANAGED, // тип размещения буфера (буфер в памяти видеокарты)
&vertexBufferPtr, // [out]
NULL // reserved
)))
throw runtime_error(«SetVertexBuffer(): creation of vertex buffer failed.»);
// Копирование данных в буфер:
{
const VertexBufferLock<VertexType> lockBuffer(vertexBufferPtr); // блокирование буфера
memcpy(lockBuffer.GetDataPointer(), &vecVertices.at(0), dataLenBytes);
}
}
// ========================================
// ========================================
/* Рисование графических примитивов из буфера: */
template<typename VertexType>
void Paint_Primitives(
IDirect3DDevice9Ptr& devicePtr, // устройсво вывода
IDirect3DVertexBuffer9Ptr& vertexBufferPtr, // буфер вершин
const D3DPRIMITIVETYPE& primitiveType, // тип примитивов
const UINT nPrimitives // кол-во примитивов
)
{
const D3DVERTEXBUFFER_DESC vertexBuffDescr =
GetVertexBufferDescr(vertexBufferPtr);
const DWORD format = vertexBuffDescr.FVF;
const UINT vertexSizeBytes = sizeof VertexType;
if (FAILED(devicePtr->SetFVF(format)))
throw runtime_error(«SetFVF failed.»);
if (FAILED(devicePtr->SetStreamSource(
0, // номер потока вывода
vertexBufferPtr, // буфер вершин
0, // смещение от начала буфера до первой выводимой вершины
vertexSizeBytes // шаг (размер одной вершины в байтах)
)))
throw runtime_error(«SetStreamSource failed.»);
// Рисование примитивов:
if (FAILED(devicePtr->DrawPrimitive(
primitiveType, // тип примитивов
0, // индекс певвой вершины
nPrimitives // кол-во примитивов
)))
throw runtime_error(«DrawPrimitive failed.»);
}
// =====================================
/* Обобщённый буфер вершин: */
template<class VertexType>
struct VertexBuffT
{
private:
IDirect3DDevice9Ptr devicePtr_; // устройсво вывода
IDirect3DVertexBuffer9Ptr vertexBufferPtr_; // буфер вершин
//
public:
/* Конструктор для создания буфера без текстуры: */
VertexBuffT(const IDirect3DDevice9Ptr& devicePtr /* устройсво вывода */)
: devicePtr_(devicePtr)
{}
VertexBufferLock<VertexType> Lock() { return VertexBufferLock<VertexType>(this->vertexBufferPtr_); }
/* Создание буфера по списку вершин: */
void SetVertices(const vector<VertexType>& vecVertices /* список вершин */)
{
if (this->vertexBufferPtr_)
this->vertexBufferPtr_.Release();
SetVertexBufferT<VertexType>(this->devicePtr_, this->vertexBufferPtr_, vecVertices);
}
// Рисование списка треугольников (‘TRIANGLELIST’):
void Paint_TRIANGLELIST()
{
// Кол-во вершин в буфере:
const UINT nVertices = GetNumberOfVerticesInBufferT<VertexType>(this->vertexBufferPtr_);
// Кол-во треугольников:
const UINT nPrimitives = nVertices / 3;
TEST_EXPR(nVertices % nPrimitives == 0)
Paint_Primitives<VertexType>(
this->devicePtr_,
this->vertexBufferPtr_,
D3DPT_TRIANGLELIST, // тип вывода — независимые треугольники
nPrimitives
);
}
// Рисование списка прямых отрезков (‘LINELIST’):
void Paint_LINELIST()
{
// Кол-во вершин в буфере:
const UINT nVertices = GetNumberOfVerticesInBufferT<VertexType>(this->vertexBufferPtr_);
// Кол-во отрезков:
const UINT nPrimitives = nVertices / 2;
TEST_EXPR(nVertices % nPrimitives == 0)
Paint_Primitives<VertexType>(
this->devicePtr_,
this->vertexBufferPtr_,
D3DPT_LINELIST, // тип вывода — независимые отрезки
nPrimitives
);
}
};
// =================================================
/* Вспомогательная функция для добавления позиций узлов прямоугольного элемента как двух
треугольников: */
void AddVerticesForOneSquareAs2TriangesTex(
/*
2 —- 4
| |
1 —- 3
*/
const Vertex_XYZ_TEX& pt1,
const Vertex_XYZ_TEX& pt2,
const Vertex_XYZ_TEX& pt3,
const Vertex_XYZ_TEX& pt4,
vector<Vertex_XYZ_TEX>& vecVertPosTriangleList // [out] — позиции узлов, заданные как набор треугольников «trianglelist»
)
{
// Первый треугольник:
vecVertPosTriangleList.push_back(pt1);
vecVertPosTriangleList.push_back(pt2);
vecVertPosTriangleList.push_back(pt3);
// Второй треугольник:
vecVertPosTriangleList.push_back(pt3);
vecVertPosTriangleList.push_back(pt2);
vecVertPosTriangleList.push_back(pt4);
}
// ======================================
/* Создание узлов цилиндрической поверхности (*): */
void BuildVertPosCylinder(
const float height, // высота
const float radius, // радиус
const UINT nBelts, // кол-во поясов цилиндра
const UINT nSectors, // кол-во секторов
vector<Vertex_XYZ_TEX>& vecVertPosTriangleList // [out] — узлы (список треугольников)
)
{
TEST_EXPR(height > 0)
TEST_EXPR(radius > 0)
TEST_EXPR(nBelts > 0)
TEST_EXPR(nSectors > 0)
// Длина окружности цилиндра:
const float circleLength = 2.f * D3DX_PI * radius;
// Наборы узлов в поясах цилиндра:
vector<vector<Vertex_XYZ_TEX> > vecPointBelts;
// Проход по поясам:
for (UINT iBelt = 0; iBelt < nBelts; ++iBelt)
{
// Относительная высота пояса:
const float beltHeightRel = (float(iBelt) / float(nBelts — 1));
// Абсолютная высота пояса:
const float beltHeightAbs = height * beltHeightRel;
// Координата текстуры ‘tv’ (0.0 — 1.0):
const float tv = 1.f — beltHeightRel;
vector<Vertex_XYZ_TEX> vecBelt; // узлы пояса
// Стартовая точка на окружности:
const D3DXVECTOR3 ptBeltStart(radius, beltHeightAbs, 0);
// Проход по секторам:
for (UINT iSector = 0; iSector < nSectors + 1; ++iSector)
{
// Угол поворота сектора (в радианах):
const float angleSectorRadian = 2.f * D3DX_PI * (float(iSector) / float(nSectors));
// Матрица поворота:
D3DXMATRIX mRot;
D3DXMatrixRotationY(&mRot, angleSectorRadian);
// Положение узла:
D3DXVECTOR3 ptCur;
::D3DXVec3TransformCoord(&ptCur, &ptBeltStart, &mRot); // применение матрицы поворота
// Длина дуги:
const float arcDist = circleLength * float(iSector) / float(nSectors);
// Координата текстуры ‘tu’ (0.0 — 1.0):
const float tu = 1.f — arcDist / circleLength;
// Узел:
Vertex_XYZ_TEX vertexCur;
vertexCur.x_ = ptCur.x;
vertexCur.y_ = ptCur.y;
vertexCur.z_ = ptCur.z;
vertexCur.tu_ = tu;
vertexCur.tv_ = tv;
vecBelt.push_back(vertexCur);
}
vecPointBelts.push_back(vecBelt);
}
// Создание треугольников:
// Проход по поясам:
for (UINT iBelt = 0; iBelt < (nBelts — 1) /* не рассматриваем последний пояс */; ++iBelt)
{
const vector<Vertex_XYZ_TEX>& vecBelt = vecPointBelts.at(iBelt);
const vector<Vertex_XYZ_TEX>& vecBeltNext = vecPointBelts.at(iBelt + 1);
// Проход по секторам:
for (UINT iSector = 0; iSector < nSectors; ++iSector)
{
const Vertex_XYZ_TEX& pt1 = vecBelt.at(iSector);
const Vertex_XYZ_TEX& pt2 = vecBeltNext.at(iSector);
const Vertex_XYZ_TEX& pt3 = vecBelt.at(iSector + 1);
const Vertex_XYZ_TEX& pt4 = vecBeltNext.at(iSector + 1);
// Добавление узлов к списку (как 2-х треугольников):
AddVerticesForOneSquareAs2TriangesTex(pt1, pt2, pt3, pt4, vecVertPosTriangleList /*out*/);
}
}
}
// =========================================================
/* Вспомогательная функция для рисования символа отрезками: */
void MakeSymbol(
const wchar_t symbol, // символ
const D3DXVECTOR3& topLeft, // левый верхний угол
const float height, // высота символа
const float width, // ширина символа
const COLORREF color, // цвет
vector<Vertex_XYZ_DIFFUSE>& vecTextLines // [out] — список узлов (два узла на отрезок)
)
{
const D3DXVECTOR3 bottomLeft(topLeft.x, topLeft.y — height, topLeft.z); // левый нижний угол
const D3DXVECTOR3 topRight(topLeft.x + width, topLeft.y, topLeft.z); // правый верхний угол
const D3DXVECTOR3 bottomRight(topLeft.x + width, topLeft.y — height, topLeft.z); // правый нижний угол
vector<std::pair<D3DXVECTOR3, D3DXVECTOR3> > vecLines; // список отрезков (две точки на отрезок)
switch (symbol)
{
case ‘X’:
{
vecLines.push_back(std::make_pair(topLeft, bottomRight));
vecLines.push_back(std::make_pair(topRight, bottomLeft));
}
break;
case ‘Y’:
{
const D3DXVECTOR3 center = topLeft + ((bottomRight — topLeft) * 0.5);
vecLines.push_back(std::make_pair(topLeft, center));
vecLines.push_back(std::make_pair(topRight, bottomLeft));
}
break;
case ‘Z’:
{
vecLines.push_back(std::make_pair(topLeft, topRight));
vecLines.push_back(std::make_pair(topRight, bottomLeft));
vecLines.push_back(std::make_pair(bottomLeft, bottomRight));
}
break;
default:
throw runtime_error(«MakeSymbol(): unsupported symbol.»);
}
// Преобразование к формату ‘Vertex_XYZ_DIFFUSE’:
for (auto pairPoints : vecLines)
{
vecTextLines.push_back(Vertex_XYZ_DIFFUSE(pairPoints.first, color));
vecTextLines.push_back(Vertex_XYZ_DIFFUSE(pairPoints.second, color));
}
}
// =========================================================
// ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((
// =========================================================
/* Базовый класс графических объектов: */
struct GraphicObject_Base
{
~GraphicObject_Base() {}
virtual void Paint() = 0;
};
// ========================================
/* Координатные оси: */
struct Axes : public GraphicObject_Base
{
IDirect3DDevice9Ptr devicePtr_; // устройство вывода
VertexBuffT<Vertex_XYZ_DIFFUSE> vertexBuff_; // буфер вершин
//
Axes(
const IDirect3DDevice9Ptr& devicePtr, // устройство вывода
const float axisLengthX, // длина оси X
const float axisLengthY, // длина оси Y
const float axisLengthZ // длина оси Z
)
: devicePtr_(devicePtr)
, vertexBuff_(devicePtr)
{
vector<Vertex_XYZ_DIFFUSE> vecVertices;
const float symbolHeight = 0.5f; // высота символа
const float symbolWidth = 0.3f; // ширина символа
// Ось X:
{
const COLORREF color = RGB(255, 0, 0);
vecVertices.push_back(Vertex_XYZ_DIFFUSE(0, 0, 0, color));
vecVertices.push_back(Vertex_XYZ_DIFFUSE(axisLengthX, 0, 0, color));
MakeSymbol(‘X’, D3DXVECTOR3(axisLengthX, 0, 0), symbolHeight, symbolWidth, color, vecVertices);
}
// Ось Y:
{
const COLORREF color = RGB(0, 255, 0);
vecVertices.push_back(Vertex_XYZ_DIFFUSE(0, 0, 0, color));
vecVertices.push_back(Vertex_XYZ_DIFFUSE(0, axisLengthY, 0, color));
MakeSymbol(‘Y’, D3DXVECTOR3(0, axisLengthY, 0), symbolHeight, symbolWidth, color, vecVertices);
}
// Ось Z:
{
const COLORREF color = RGB(0, 0, 255);
vecVertices.push_back(Vertex_XYZ_DIFFUSE(0, 0, 0, color));
vecVertices.push_back(Vertex_XYZ_DIFFUSE(0, 0, axisLengthZ, color));
MakeSymbol(‘Z’, D3DXVECTOR3(0, 0, axisLengthZ), symbolHeight, symbolWidth, color, vecVertices);
}
// Создание буфера вершин:
this->vertexBuff_.SetVertices(vecVertices);
}
virtual void Paint()
{
// Вывод списка отрезков:
this->vertexBuff_.Paint_LINELIST();
}
};
// ========================================
/* Цилиндр (*): */
struct Cylinder : public GraphicObject_Base
{
IDirect3DDevice9Ptr devicePtr_; // устройство вывода
VertexBuffT<Vertex_XYZ_TEX> vertexBuff_; // буфер вершин
IDirect3DTexture9Ptr texturePtr_; // текстура
Axes axes_; // собственные оси
//
Cylinder(
const IDirect3DDevice9Ptr& devicePtr, // устройство вывода
const float height, // высота
const float radius, // радиус
const D3DXMATRIX& worldMatrix, // матрица мирового преобразования
const wstring& strTextureFilePathName // путь к файлу текстуры
)
: devicePtr_(devicePtr)
, vertexBuff_(devicePtr)
, axes_(devicePtr, radius * 1.2f, height * 1.2f, radius * 1.2f)
{
// Создание текстуры:
if (FAILED(D3DXCreateTextureFromFile(
this->devicePtr_,
strTextureFilePathName.c_str(),
&this->texturePtr_
)))
throw runtime_error(«Cylinder(): невозможно создать текстуру.»);
/* Создание узлов цилиндрической поверхности: */
vector<Vertex_XYZ_TEX> vecVertPosTriangleList; // [out] — узлы (список треугольников)
BuildVertPosCylinder(
height, // высота
radius, // радиус
20, // кол-во поясов цилиндра
20, // кол-во секторов
vecVertPosTriangleList // [out] — узлы (список треугольников)
);
// Применение матрицы преобразования к цилиндру:
for (Vertex_XYZ_TEX& v : vecVertPosTriangleList)
{
D3DXVECTOR3 pt(v.x_, v.y_, v.z_);
::D3DXVec3TransformCoord(&pt, &pt, &worldMatrix);
v.x_ = pt.x;
v.y_ = pt.y;
v.z_ = pt.z;
}
// Создание буфера вершин:
this->vertexBuff_.SetVertices(vecVertPosTriangleList);
// Применение матрицы преобразования к собственным осям:
{
VertexBufferLock<Vertex_XYZ_DIFFUSE> lockAxes(this->axes_.vertexBuff_.Lock());
for (UINT iVertex = 0; iVertex < lockAxes.GetNumberOfVertices(); ++iVertex)
{
Vertex_XYZ_DIFFUSE& v = lockAxes.At(iVertex);
D3DXVECTOR3 pt(v.x_, v.y_, v.z_);
::D3DXVec3TransformCoord(&pt, &pt, &worldMatrix);
v.x_ = pt.x;
v.y_ = pt.y;
v.z_ = pt.z;
}
}
}
private:
virtual void Paint()
{
{
// Установка текущей текстуры:
const TextureSentry texture(this->devicePtr_, this->texturePtr_);
// Вывод списка треугольников:
this->vertexBuff_.Paint_TRIANGLELIST();
}
// Вывод собственных осей:
this->axes_.Paint();
}
};
// =========================================================
// ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((
// =========================================================
// =============================
/* Глобальные переменные: */
IDirect3D9Ptr d3d; // Среда выполнения Direct3D
IDirect3DDevice9Ptr device; // Устройство вывода
POINT ptOld; // Предыдущая точка при перемещении мыши
bool bDragging = false; /* Флаг, показывающий, что перемещение мыши
должно сопровождаться вращением камеры вокруг точки просмотра */
D3DXVECTOR3 ptLootAt; // Точка, на которую направлена камера
D3DXVECTOR3 ptEye; // Точка, в которой находится камера
// Графические объекты:
vector<std::shared_ptr<GraphicObject_Base> > vecGraphObjects;
// =============================
// Инициализация Direct3D (*):
void InitD3D(const HWND hWnd)
{
/* Создание среды вывода Direct3D: */
d3d = Direct3DCreate9(D3D_SDK_VERSION);
/* Параметры создания устройства: */
D3DPRESENT_PARAMETERS params = {0};
params.Windowed = TRUE; /* Вывод графики в окно (не полноэкранный режим) */
params.hDeviceWindow = hWnd; /* Окно вывода (дескриптор) */
params.SwapEffect = D3DSWAPEFFECT_DISCARD; /* Не сохранять содержимое кадров */
params.BackBufferFormat = D3DFMT_X8R8G8B8; /* 32-битный формат заднего буфера */
params.BackBufferWidth = 1200; /* Ширина заднего буфера */
params.BackBufferHeight = 800; /* Высота заднего буфера */
params.EnableAutoDepthStencil = TRUE;
params.AutoDepthStencilFormat = D3DFMT_D16;
/* Создание устройства вывода: */
d3d->CreateDevice(D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
hWnd,
D3DCREATE_HARDWARE_VERTEXPROCESSING,
¶ms,
&device);
device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
device->SetRenderState(D3DRS_LIGHTING, FALSE);
device->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
// Создание графических объектов:
// Цилиндр:
{
// Матрица мирового преобразования:
const D3DXMATRIX worldMatrix = MatrixIdentity() * Scale(1.5, 1, 1) * RotX(0) * RotY(30) * RotZ(45) * Trans(2, 4, 0);
const shared_ptr<GraphicObject_Base> ptr(new Cylinder(
device, // устройство вывода
10, // высота
3, // радиус
worldMatrix, // матрица мирового преобразования
L»MyTexture.bmp» // путь к файлу текстуры
));
vecGraphObjects.push_back(ptr);
}
// Координатные оси:
vecGraphObjects.push_back(shared_ptr<GraphicObject_Base>(new Axes(device, 10, 15, 10)));
/* Инициализация положения камеры: */
ptLootAt = D3DXVECTOR3(0.0f, 5.f, 0.0f);
ptEye = D3DXVECTOR3(28.0f, 1.5f, -5.0f);
}
// ========================================
/* Вывод кадра (*): */
void RenderFrame(const HWND hwnd)
{
/* Очитска буфера рисования: */
device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
D3DCOLOR_XRGB(255, 255, 255), 1.0f, 0);
/* Матрица вида: */
D3DXMATRIX matView;
D3DXMatrixLookAtLH(&matView,
&ptEye, /* Позиция камеры */
&ptLootAt, /* Точка, на которую направлена камера */
&D3DXVECTOR3(0.0f, 1.0f, 0.0f)); /* Направление верха камеры */
device->SetTransform(D3DTS_VIEW, &matView);
/* Матрица проекции: */
D3DXMATRIX matProjection;
/* Получение размера клиентской области окна вывода: */
RECT rectClient = { 0 };
::GetClientRect(hwnd, &rectClient);
const int clientHeight = rectClient.bottom — rectClient.top;
const int clientWidth = rectClient.right — rectClient.left;
float aspect = 1;
if (clientHeight > 0)
aspect = float(clientWidth) / float(clientHeight);
D3DXMatrixPerspectiveFovLH(&matProjection,
D3DXToRadian(45), /* Угол обзора */
aspect, /* Отношение ширины к высоте */
0.1f, /* Расстояние до ближней плоскости отсечения */
100.0f); /* Расстояние до дальней плоскости отсечения */
device->SetTransform(D3DTS_PROJECTION, &matProjection);
/* Начало рисования: */
device->BeginScene();
/* Вывод графических объектов: */
for (const std::shared_ptr<GraphicObject_Base>& ptr : vecGraphObjects)
ptr->Paint();
/* Конец рисования: */
device->EndScene();
device->Present(NULL, NULL, NULL, NULL);
}
// ===================================================
/* Обработка оконных сообщений: */
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam)
{
try
{
switch (message)
{
case WM_LBUTTONDOWN:
{ /* Нажатие левой кнопки мыши: */
ptOld.x = GET_X_LPARAM(lParam);
ptOld.y = GET_Y_LPARAM(lParam);
bDragging = true;
}
break;
case WM_LBUTTONUP:
{ /* Отпускание левой кнопки мыши: */
bDragging = false;
}
break;
case WM_MOUSEMOVE:
{ /* Движение мыши: */
if (bDragging)
{
POINT pt = {0};
pt.x = GET_X_LPARAM(lParam);
pt.y = GET_Y_LPARAM(lParam);
const int dx = pt.x — ptOld.x;
const int dy = pt.y — ptOld.y;
if (! ((abs(dx) > 0) || (abs(dy) > 0)))
break;
/* Поворот камеры относительно оси Y: */
{
/* Вектор, идущий от точки ‘LookAt’ до положения камеры: */
const D3DXVECTOR3 vDir = ptEye — ptLootAt;
/* Угол поворота: */
const float angleY = float(dx) * 0.03f;
/* Поворот относительно оси Y: */
D3DXMATRIX mRotateY;
D3DXMatrixRotationY(&mRotateY, angleY);
D3DXVECTOR4 v2;
D3DXVec3Transform(&v2, &vDir, & mRotateY);
ptEye = ptLootAt + D3DXVECTOR3(v2.x, v2.y, v2.z);
}
/* Поворот в вертикальной плоскости: */
{
/* Вектор, идущий от точки ‘LookAt’ до положения камеры: */
const D3DXVECTOR3 vDir = ptEye — ptLootAt;
/* Угол поворота: */
const float angleVert = float(dy) * 0.03f;
/* Получение направления оси, вокруг которой следует выполнить поворот.
Ось поворота должна быть перпендикулярна направлению vDir и оси Y;
используем для этого векторное произведение: */
D3DXVECTOR3 vAxis;
D3DXVec3Cross(&vAxis, &vDir, &D3DXVECTOR3(0, 1, 0));
/* Поворот относительно оси vAxis: */
D3DXMATRIX mRotate;
D3DXMatrixRotationAxis(&mRotate, &vAxis, angleVert);
D3DXVECTOR4 v2;
D3DXVec3Transform(&v2, &vDir, & mRotate);
ptEye = ptLootAt + D3DXVECTOR3(v2.x, v2.y, v2.z);
}
ptOld = pt;
}
}
break;
case WM_MOUSEWHEEL:
{ /* Прокручивание колёсика мыши: */
const int zDelta = GET_WHEEL_DELTA_WPARAM(wParam);
/* Вектор, идущий от точки ‘LookAt’ до положения камеры: */
const D3DXVECTOR3 vDir = ptEye — ptLootAt;
/* Коэффициент увеличения/уменьшения расстояния: */
const float k = 1.f + float(zDelta) * 0.0008f;
/* Вычисление нового положения камеры: */
ptEye = ptLootAt + vDir * k;
}
break;
case WM_DESTROY:
{
PostQuitMessage(0);
}
break;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
catch(…)
{
::MessageBox(NULL, L»Ошибка ‘WindowProc'», L»Ошибка», MB_ICONERROR | MB_OK);
}
return 0;
}
// =====================================================
/* Главная функция приложения: */
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
try
{
/* Регистрация оконного класса: */
WNDCLASSEX wc = {0};
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.lpszClassName = L»MyClass»;
RegisterClassEx(&wc);
/* Создание окна: */
const HWND hWnd = CreateWindowEx(NULL,
wc.lpszClassName, /* Имя оконного класса */
L»Программа DirectX»,
WS_OVERLAPPEDWINDOW | WS_VISIBLE, /* Стиль окна */
0, 0, /* Начальное положение окна */
1000, 800, /* Начальный размер окна */
NULL,
NULL,
hInstance,
NULL
);
/* Инициализация DirectX: */
InitD3D(hWnd);
/* Главный цикл обработки оконных сообщений: */
MSG msg = {0};
while (true)
{
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if (msg.message == WM_QUIT)
break;
RenderFrame(hWnd);
}
}
catch (const std::exception& err)
{
::MessageBoxA(NULL, err.what(), «Ошибка в ‘WinMain'», MB_ICONERROR | MB_OK);
}
catch(…)
{
::MessageBox(NULL, L»Неизвестная ошибка», L»Ошибка в ‘WinMain'», MB_ICONERROR | MB_OK);
}
return 0;
}

или напишите нам прямо сейчас:
Здравствуйте. Скажите пожалуйста, планирую поступать в магистратуру на факультет Психологии « Психология личности»в РГГУ скажите пожалуйста, есть ли у вас, ответы на вступительные экзамены? так как, планирую, сделать акцент на бюджет. Спасибо.
Арсений, здравствуйте! Прошу Вас прислать всю необходимую информацию на почту info@otlichnici.ru и написать что необходимо выполнить. Я посмотрю описание к заданиям и подскажу вам по стоимости и срокам выполнения.
Дистанционная помощь в защите ВКР
Анастасия, здравствуйте! Прошу Вас прислать всю необходимую информацию на почту info@otlichnici.ru и написать что необходимо выполнить. Я посмотрю описание к заданиям и подскажу вам по стоимости и срокам выполнения.
Здравствуйте. Нужна срочно практическая часть вкр, третья глава. Скину похожие работы, на которые можно ориентироваться
Александр, здравствуйте! Прошу Вас прислать всю необходимую информацию на почту info@otlichnici.ru и написать что необходимо выполнить. Я посмотрю описание к заданиям и подскажу вам по стоимости и срокам выполнения.
вкр по теме: экологический туризм России : анализ состояния, проблемы и перспективы
Людмила, здравствуйте! Прошу Вас прислать всю необходимую информацию на почту info@otlichnici.ru и написать что необходимо выполнить. Я посмотрю описание к заданиям и подскажу вам по стоимости и срокам выполнения.
Здравствуйте вы защищаете ВКР?
Ольга, здравствуйте! Прошу Вас прислать всю необходимую информацию на почту info@otlichnici.ru и написать что необходимо выполнить. Я посмотрю описание к заданиям и подскажу вам по стоимости и срокам выполнения.
Написать магистерскую ВКР на тему «Совершенствование логистических бизнес-процессов на примере торговой компании». Не менее 100 страниц.
Миша, здравствуйте! Прошу Вас прислать всю необходимую информацию на почту info@otlichnici.ru и написать что необходимо выполнить. Я посмотрю описание к заданиям и подскажу вам по стоимости и срокам выполнения.
Здравствуйте нужна работа Вкр
Лена, здравствуйте! Прошу Вас прислать всю необходимую информацию на почту info@otlichnici.ru и написать что необходимо выполнить. Я посмотрю описание к заданиям и подскажу вам по стоимости и срокам выполнения.
Написать ВКР 3 раздела Тема строительство строительство жилого дома с применением каркасно-монолитных технологий Антиплагиат от 75% ПЗ и чертежи
Владимир, здравствуйте! Прошу Вас прислать всю необходимую информацию на почту info@otlichnici.ru и написать что необходимо выполнить. Я посмотрю описание к заданиям и подскажу вам по стоимости и срокам выполнения.