Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
13
Добавлен:
20.06.2014
Размер:
323.07 Кб
Скачать

2

ФЕДЕРАЛЬНОЕ АГЕНТСТВО ПО ОБРАЗОВАНИЮ

ГОСУДАРСТВЕННОЕ ОБРАЗОВАТЕЛЬНОЕ УЧРЕЖДЕНИЕ

ВЫСШЕГО ПРОФЕССИОНАЛЬНОГО ОБРАЗОВАНИЯ

ЛИПЕЦКИЙ ГОСУДАРСТВЕННЫЙ ТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ

КАФЕДРА АВТОМАТИЗИРОВАННЫХ СИСТЕМ УПРАВЛЕНИЯ

Лабораторная работа №4

по дисциплине

«Компьютерная графика»

на тему:

«Реализация базовых алгоритмов трехмерной графики»

Студент

Филатов А.А.

подпись, дата

фамилия, инициалы

Группа

АС-09-1

Принял

Назаркин О.А.

ученая степень, звание

подпись, дата

фамилия, инициалы

Липецк 2010

1.Задание

Реализовать приложение, выполняющее построение полуцилиндра, освещенного точечным источником света.

2.Теория

В 3D-графике применяется понятие камеры, снимающей гипотетическое трехмерное пространство и выдающей его плоское изображение на экран. Камеру можно размещать в разных точках пространства, направлять на разные точки, изменять ее угол обзора и.т.д. Подлежащая отображению сцена создается в виде совокупности трехмерных графических примитивов, на которые разбиты все объекты сцены.

Модель трехмерного тела задана в некоторой системе координат, чаще всего связанной своим началом с какой-либо «ключевой» точкой тела (например с центром сферы). Эта локальная система координат может быть преобразована в глобальную (мировую) систему, которая и подлежит отображению. Преобразование координат задается матрицами. Отсутствие преобразования - единичная матрица, иначе матрица должна быть отличной от единичной.

Помимо мирового преобразования Direct3D применяет еще преобразование обзора и перспективное преобразование.

Преобразование обзора определяет позицию и направление камеры.

Здесь задается положение наблюдателя в пространстве, точка сцены, на которую направлен взгляд, и вектор направления вверх.

Перспективное преобразование определяет эффект перспективы - искажение параллельности линий.

3.Алгоритм

1. По заданным параметрам (количество примитивов основания цилиндра, высота, радиус, угол цилиндра (задает сектор цилиндра для отображения: для полуцилиндра угол равен 180˚)) расчет координат вершин цилиндра. Расчет нормалей.

2. Заполнение массива вершин в порядке, необходимом для вывода модели в режиме TriangleList.

3. Заполнение индексного массива, в котором номера всех вершин располагаются по порядку (ввиду учета особенности режима вывода TriangleList в первом пункте).

4. Вывод модели в режиме TriangleList.

4.Листинг программы

using System;

using System.Collections.Generic;

using Microsoft.Xna.Framework;

using Microsoft.Xna.Framework.Audio;

using Microsoft.Xna.Framework.Content;

using Microsoft.Xna.Framework.GamerServices;

using Microsoft.Xna.Framework.Graphics;

using Microsoft.Xna.Framework.Input;

using Microsoft.Xna.Framework.Net;

using Microsoft.Xna.Framework.Storage;

namespace DrawUserPrimitives

{

public class Game1 : Microsoft.Xna.Framework.Game

{

Matrix worldMatrix;

Matrix viewMatrix;

Matrix projectionMatrix;

BasicEffect basicEffect;

VertexDeclaration vertexDeclaration;

VertexPositionColor[] axis;

VertexPositionNormalTexture[] vertexCylinder, vertexRound1, vertexRound2;

VertexBuffer vertexBuffer;

static float aspect;

static float FOV = MathHelper.PiOver4;

Vector3 CamPosition = new Vector3(500.0f, 350.0f, 500.0f);

Vector3 CamTarget;

float CamRotation = (float)Math.PI * 7f / 6f;

bool isIzometric = false;

bool oFree = true;

bool pFree = true;

FillMode fillMode = FillMode.Solid;

int nRoundPolygon = 7;

float Angle=180f;

float Radius=100f;

float Height=200f;

short[] lineListIndices;

short[] triangleStripIndices;

short[] triangleFanIndices;

GraphicsDeviceManager graphics;

public Game1()

{

graphics = new GraphicsDeviceManager(this);

Content.RootDirectory = "Content";

}

protected override void Initialize()

{

aspect = (float)graphics.GraphicsDevice.Viewport.Width / (float)graphics.GraphicsDevice.Viewport.Height;

axis = new VertexPositionColor[6];

vertexRound1 = new VertexPositionNormalTexture[3*nRoundPolygon];

vertexRound2 = new VertexPositionNormalTexture[3*nRoundPolygon];

vertexCylinder = new VertexPositionNormalTexture[3*(2 * nRoundPolygon + 2)];

InitializeTransform(vertexRound1);

InitializeEffect(vertexRound1);

InitializePointListRound(vertexRound1, 0, Angle, Radius);

InitializePointListRound(vertexRound2, Height, Angle, Radius);

InitializePointListCylinder(vertexCylinder, vertexRound1, vertexRound2, Height, Angle, Radius);

InitializateAxis(axis);

InitIndexMassCoord(axis);

InitIndexMassCylinder(vertexRound1);

InitIndexMassRound(vertexRound1);

IsMouseVisible = true;

base.Initialize();

}

protected override void LoadContent()

{

}

protected override void UnloadContent()

{

}

private void InitializeTransform(VertexPositionNormalTexture[] pointList)

{

viewMatrix = Matrix.CreateLookAt(CamPosition, CamTarget, new Vector3(0.0f, 1.0f, 0.0f));

projectionMatrix = Matrix.CreatePerspectiveFieldOfView(FOV, aspect, 1.0f, 10000.0f);

}

private void InitializeEffect(VertexPositionNormalTexture[] pointList)

{

vertexDeclaration = new VertexDeclaration(GraphicsDevice,VertexPositionNormalTexture.VertexElements);

basicEffect = new BasicEffect(GraphicsDevice, null);

basicEffect.VertexColorEnabled = true;

worldMatrix = Matrix.CreateTranslation(GraphicsDevice.Viewport.Width / 2f - 150,GraphicsDevice.Viewport.Height / 2f - 50, 0);

basicEffect.World = worldMatrix;

basicEffect.View = viewMatrix;

basicEffect.Projection = projectionMatrix;

}

private void InitializateAxis(VertexPositionColor[] axis)

{

axis[0] = new VertexPositionColor(new Vector3(0, 0, 0) ,Color.Black);

axis[1] = new VertexPositionColor(new Vector3(10000, 0, 0), Color.Black);

axis[2] = new VertexPositionColor(new Vector3(0, 0, 0), Color.Black);

axis[3] = new VertexPositionColor(new Vector3(0, 10000, 0), Color.Black);

axis[4] = new VertexPositionColor(new Vector3(0, 0, 0), Color.Black);

axis[5] = new VertexPositionColor(new Vector3(0, 0, 10000), Color.Black);

}

private void InitializePointListCylinder(VertexPositionNormalTexture[] pointList, VertexPositionNormalTexture[] pointList1, VertexPositionNormalTexture[] pointList2, float Height, float Angle, float Radius)

{

vertexDeclaration = new VertexDeclaration(GraphicsDevice, VertexPositionNormalTexture.VertexElements);

for (int i = 0; i < nRoundPolygon-2; i++)

{

pointList[i * 6] = pointList1[3*i+1];

pointList[i * 6 + 1] = pointList2[3 * i + 1];

pointList[i * 6 + 2] = pointList1[3*i + 2];

pointList[i * 6 + 3] = pointList1[3 * i + 2];

pointList[i * 6 + 4] = pointList2[3 * i + 1];

pointList[i * 6 + 5] = pointList2[3 * i + 2];

Vector3 a = pointList2[3 * i + 1].Position, b = pointList1[3 * i + 2].Position;

a.Z = b.Z = 0;

pointList[i * 6].Normal = pointList[i * 6 + 1].Normal = pointList[i * 6 + 4].Normal = a;

pointList[i * 6 + 2].Normal = pointList[i * 6 + 3].Normal = pointList[i * 6 + 5].Normal = b;

};

pointList[6 * (nRoundPolygon - 2)] = pointList1[1];

pointList[6 * (nRoundPolygon - 2) + 1] = pointList2[1];

pointList[6 * (nRoundPolygon - 2) + 2] = pointList1[0];

pointList[6 * (nRoundPolygon - 2) + 3] = pointList1[0];

pointList[6 * (nRoundPolygon - 2) + 4] = pointList2[1];

pointList[6 * (nRoundPolygon - 2) + 5] = pointList2[0];

pointList[6 * (nRoundPolygon - 1)] = pointList1[3 * (nRoundPolygon - 3) + 2];

pointList[6 * (nRoundPolygon - 1) + 1] = pointList2[3 * (nRoundPolygon - 3) + 2];

pointList[6 * (nRoundPolygon - 1) + 2] = pointList1[0];

pointList[6 * (nRoundPolygon - 1) + 3] = pointList1[0];

pointList[6 * (nRoundPolygon - 1) + 4] = pointList2[3 * (nRoundPolygon - 3) + 2];

pointList[6 * (nRoundPolygon - 1) + 5] = pointList2[0];

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

{

pointList[6 * (nRoundPolygon - 2) + i].TextureCoordinate = new Vector2(pointList[6 * (nRoundPolygon - 2) + i].Position.Y, pointList[6 * (nRoundPolygon - 2) + i].Position.Z);

pointList[6 * (nRoundPolygon - 2) + i].Normal = new Vector3(-1,0,0);

}

vertexBuffer = new VertexBuffer(GraphicsDevice, VertexPositionNormalTexture.SizeInBytes * (pointList.Length), BufferUsage.None);

vertexBuffer.SetData<VertexPositionNormalTexture>(pointList);

}

private void InitializePointListRound(VertexPositionNormalTexture[] pointList, float z, float Angle, float Radius)

{

vertexDeclaration = new VertexDeclaration(GraphicsDevice, VertexPositionNormalTexture.VertexElements);

for (int i = 0; i < nRoundPolygon-2; i++)

{

pointList[3*i] = new VertexPositionNormalTexture(new Vector3(0, 0, z), new Vector3(0, 0, 1), new Vector2(0, 0));

float angle = (float)i / (float)(nRoundPolygon - 2) * MathHelper.ToRadians(Angle);

float x = Radius * (float)Math.Sin(angle);

float y = Radius * (float)Math.Cos(angle);

pointList[3 * i + 1] = new VertexPositionNormalTexture(new Vector3(x, y, z), new Vector3(0, 0, 1), new Vector2(0, 0));

angle = (float)(i + 1) / (float)(nRoundPolygon - 2) * MathHelper.ToRadians(Angle);

x = Radius * (float)Math.Sin(angle);

y = Radius * (float)Math.Cos(angle);

pointList[3 * i + 2] = new VertexPositionNormalTexture(new Vector3(x, y, z), new Vector3(0, 0, 1), new Vector2(0, 0));

};

vertexBuffer = new VertexBuffer(GraphicsDevice, VertexPositionNormalTexture.SizeInBytes * (pointList.Length), BufferUsage.None);

vertexBuffer.SetData<VertexPositionNormalTexture>(pointList);

}

private void InitIndexMassCoord(VertexPositionColor[] pointList)

{

lineListIndices = new short[12];

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

{

lineListIndices[i] = (short)(i);

}

}

private void InitIndexMassCylinder(VertexPositionNormalTexture[] pointList)

{

triangleStripIndices = new short[6 * nRoundPolygon + 6];

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

{

triangleStripIndices[i] = (short)i;

}

}

private void InitIndexMassRound(VertexPositionNormalTexture[] pointList)

{

triangleFanIndices = new short[3*nRoundPolygon];

for (int i = 0; i < 3*nRoundPolygon; i++)

{

triangleFanIndices[i] = (short)i;

}

}

protected override void Update(GameTime gameTime)

{

CamPref();

UpdateCamPosition();

Draw(gameTime);

base.Update(gameTime);

}

void UpdateCamPosition()

{

KeyboardState keyboardState = Keyboard.GetState();

//Поворот влево

if (keyboardState.IsKeyDown(Keys.NumPad7))

{

CamRotation += 0.05f;

}

//Поворот вправо

if (keyboardState.IsKeyDown(Keys.NumPad9))

{

CamRotation -= 0.05f;

}

//Передвижение влево

if (keyboardState.IsKeyDown(Keys.NumPad4))

{

CamPosition.X += 3.0f * (float)Math.Cos(CamRotation);

CamPosition.Z -= 3.0f * (float)Math.Sin(CamRotation);

}

//Передвижение вправо

if (keyboardState.IsKeyDown(Keys.NumPad6))

{

CamPosition.X -= 3.0f * (float)Math.Cos(CamRotation);

CamPosition.Z += 3.0f * (float)Math.Sin(CamRotation);

}

//Передвижение вперед

if (keyboardState.IsKeyDown(Keys.NumPad8))

{

CamPosition.X += 3.0f * (float)Math.Sin(CamRotation);

CamPosition.Z += 3.0f * (float)Math.Cos(CamRotation);

}

//Передвижение назад

if (keyboardState.IsKeyDown(Keys.NumPad5))

{

CamPosition.X -= 3.0f * (float)Math.Sin(CamRotation);

CamPosition.Z -= 3.0f * (float)Math.Cos(CamRotation);

}

//Передвижение вверх

if (keyboardState.IsKeyDown(Keys.NumPad1))

{

CamPosition.Y += 2.0f;

}

//Передвижение вниз

if (keyboardState.IsKeyDown(Keys.NumPad2))

{

CamPosition.Y -= 2.0f;

}

//Увеличение числа вершин

if (keyboardState.IsKeyDown(Keys.O) && oFree)

{

nRoundPolygon += 1;

Initialize();

}

//Уменьшение числа вершин

if (keyboardState.IsKeyDown(Keys.P) && pFree)

{

if (nRoundPolygon > 4)

nRoundPolygon -= 1;

Initialize();

}

//Увеличние угла

if (keyboardState.IsKeyDown(Keys.K))

{

if (Angle <= 359.0f)

{

Angle += 1f;

Initialize();

}

}

//Уменьшение угла

if (keyboardState.IsKeyDown(Keys.L))

{

if (Angle >= 2.0f)

{

Angle -= 1f;

Initialize();

}

}

if (keyboardState.IsKeyDown(Keys.D1))

{

fillMode = FillMode.Point;

}

if (keyboardState.IsKeyDown(Keys.D2))

{

fillMode = FillMode.WireFrame;

}

if (keyboardState.IsKeyDown(Keys.D3))

{

fillMode = FillMode.Solid;

}

//Сброс

if (keyboardState.IsKeyDown(Keys.C))

{

CamPosition = new Vector3(500.0f, 350.0f, 500.0f);

CamRotation = (float)Math.PI * 7f / 6f;

nRoundPolygon = 7;

Angle = 180f;

Radius = 100f;

Height = 200f;

fillMode = FillMode.Solid;

viewMatrix = Matrix.CreateLookAt(new Vector3(0.0f, -0.2f, 500.0f), Vector3.Zero, Vector3.Up);

projectionMatrix = Matrix.CreateOrthographicOffCenter(0, (float)GraphicsDevice.Viewport.Width, (float)GraphicsDevice.Viewport.Height, 0, 1.0f, 1000.0f);

Initialize();

}

//Изометрическая проекция

if (keyboardState.IsKeyDown(Keys.I))

{

CamPosition = new Vector3(500.0f, 500.0f, 500.0f);

CamTarget = Vector3.Zero;

isIzometric = true;

viewMatrix = Matrix.CreateLookAt(new Vector3(0.0f, -0.2f, 500.0f), Vector3.Zero, Vector3.Up);

projectionMatrix = Matrix.CreateOrthographicOffCenter(0, (float)GraphicsDevice.Viewport.Width, (float)GraphicsDevice.Viewport.Height, 0, 1.0f, 1000.0f);

Initialize();

}

if (keyboardState.IsKeyUp(Keys.I))

{

if (isIzometric)

{

CamPosition = new Vector3(500.0f, 350.0f, 500.0f);

CamRotation = (float)Math.PI * 7f / 6f;

viewMatrix = Matrix.CreateLookAt(new Vector3(0.0f, -0.2f, 500.0f), Vector3.Zero, Vector3.Up);

projectionMatrix = Matrix.CreateOrthographicOffCenter(0, (float)GraphicsDevice.Viewport.Width, (float)GraphicsDevice.Viewport.Height, 0, 1.0f, 1000.0f);

Initialize();

isIzometric = false;

}

}

oFree = keyboardState.IsKeyUp(Keys.O);

pFree = keyboardState.IsKeyUp(Keys.P);

}

void CamPref()

{

if (!isIzometric)

{

CamTarget.X = CamPosition.X + (float)Math.Sin(CamRotation);

CamTarget.Y = CamPosition.Y;

CamTarget.Z = CamPosition.Z + (float)Math.Cos(CamRotation);

}

viewMatrix = Matrix.CreateLookAt(CamPosition, CamTarget, Vector3.Up);

projectionMatrix = Matrix.CreatePerspectiveFieldOfView(FOV, aspect, 1.0f, 10000.0f);

}

protected override void Draw(GameTime gameTime)

{

GraphicsDevice.Clear(Color.SteelBlue);

GraphicsDevice.VertexDeclaration = vertexDeclaration;

basicEffect.Begin();

basicEffect.EnableDefaultLighting();

basicEffect.DirectionalLight0.Direction = new Vector3(-1, 0, 0);

basicEffect.DirectionalLight0.DiffuseColor = Vector3.One;

basicEffect.DirectionalLight1.Direction = new Vector3(0, 1, 0);

basicEffect.DirectionalLight2.Direction = new Vector3(-1, -1, -1);

basicEffect.DirectionalLight0.Enabled = basicEffect.DirectionalLight1.Enabled = basicEffect.DirectionalLight2.Enabled = true;

basicEffect.View = viewMatrix;

basicEffect.World = worldMatrix;

basicEffect.Projection = projectionMatrix;

foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes)

{

pass.Begin();

GraphicsDevice.RenderState.FillMode = fillMode;

GraphicsDevice.RenderState.CullMode = CullMode.None;

DrawRound(vertexRound1);

DrawRound(vertexRound2);

DrawCylinder(vertexCylinder);

DrawCoord(axis);

pass.End();

}

basicEffect.End();

base.Draw(gameTime);

}

private void DrawnRoundPolygon(VertexPositionNormalTexture[] pointList)

{

GraphicsDevice.RenderState.PointSize = 10;

GraphicsDevice.DrawUserPrimitives<VertexPositionNormalTexture>(PrimitiveType.PointList,pointList,0,nRoundPolygon);

}

private void DrawCoord(VertexPositionColor[] axis)

{

GraphicsDevice.DrawUserIndexedPrimitives<VertexPositionColor>(PrimitiveType.LineList, axis, 0, 6, lineListIndices, 0, 3);

}

private void DrawCylinder(VertexPositionNormalTexture[] pointList)

{

GraphicsDevice.DrawUserIndexedPrimitives<VertexPositionNormalTexture>(PrimitiveType.TriangleList, pointList, 0, 6 * nRoundPolygon + 6, triangleStripIndices, 0, 2 * nRoundPolygon);

}

private void DrawRound(VertexPositionNormalTexture[] pointList)

{

GraphicsDevice.DrawUserIndexedPrimitives<VertexPositionNormalTexture>(PrimitiveType.TriangleList, pointList, 0, 3*nRoundPolygon, triangleFanIndices, 0, nRoundPolygon);

}

}

}