Эксперт
Сергей
Сергей
Задать вопрос
Мы готовы помочь Вам.

Задание

Написать программу, создающую трёхмерное изображение цилиндрической поверхности (цилиндра) с текстурой. На изображении должны присутствовать также мировые координатные оси (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”):

screenshot 11 11

 

Полный пример решения:

 

 

// Макрос для включения поддержки 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,

&params,

&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;

}

screenshot 10 12

Была ли полезна данная статья?
Да
60.96%
Нет
39.04%
Проголосовало: 1099

или напишите нам прямо сейчас:

⚠️ Пожалуйста, пишите в MAX или заполните форму выше.
В России Telegram и WhatsApp блокируют - сообщения могут не дойти.
Написать в MAXНаписать в TelegramНаписать в WhatsApp