#directx #3d-modelling
Вопрос:
Для моей игры я добавил «Кисти», которые представляют собой 3D-коробки, которые будут использоваться для создания геометрии уровня. Я хотел добавить возможность выворачивать кисти наизнанку, чтобы внешний вид стал внутренним и т. Д. Я почти уверен, что знаю, как это сделать, но я хотел убедиться, что это действительно стандартная практика. Прежде всего, вот фотография моего объема кисти в двигателе:
Я создаю этот объем кисти с помощью следующего кода:
public void Rebuild()
{
/**
* No faces are present; empty the StaticBrushVolume
*/
if (this.FaceVisibility == BrushVolumeFaceVisibility.None)
{
if (_bufferBinding.Buffer != null)
{
_bufferBinding.Buffer.Dispose();
}
this.FaceCount = 0;
_drawCount = 0;
return;
}
this.FaceCount = CountVisibleFaces(this.FaceVisibility);
Vertex[] vertices = new Vertex[this.FaceCount * 6];
float width = this.Width;
float height = this.Height;
float depth = this.Depth;
float uvX = width / (float)this.DiffuseMaterial.Width;
float uvY = height / (float)this.DiffuseMaterial.Height;
float uvZ = depth / (float)this.DiffuseMaterial.Width;
// Generate Front Face
int index = 0;
if (this.FaceVisibility.HasFlag(BrushVolumeFaceVisibility.Front))
{
Vector3 normal = new Vector3(0, 0, -1);
vertices[index ] = new Vertex(new Vector3(-width, height, -depth), new Vector2(uvX, 0), normal);
vertices[index ] = new Vertex(new Vector3(width, height, -depth), new Vector2(0, 0), normal);
vertices[index ] = new Vertex(new Vector3(width, -height, -depth), new Vector2(0, uvY), normal);
vertices[index ] = new Vertex(new Vector3(-width, height, -depth), new Vector2(uvX, 0), normal);
vertices[index ] = new Vertex(new Vector3(-width, -height, -depth), new Vector2(uvX, uvY), normal);
vertices[index ] = new Vertex(new Vector3(width, -height, -depth), new Vector2(0, uvY), normal);
}
// Generate East Face
if (this.FaceVisibility.HasFlag(BrushVolumeFaceVisibility.Left))
{
Vector3 normal = new Vector3(1, 0, 0);
vertices[index ] = new Vertex(new Vector3(width, -height, depth), new Vector2(0, uvY), normal);
vertices[index ] = new Vertex(new Vector3(width, -height, -depth), new Vector2(uvZ, uvY), normal);
vertices[index ] = new Vertex(new Vector3(width, height, -depth), new Vector2(uvZ, 0), normal);
vertices[index ] = new Vertex(new Vector3(width, height, -depth), new Vector2(uvZ, 0), normal);
vertices[index ] = new Vertex(new Vector3(width, height, depth), new Vector2(0, 0), normal);
vertices[index ] = new Vertex(new Vector3(width, -height, depth), new Vector2(0, uvY), normal);
}
// Generate South Face
if (this.FaceVisibility.HasFlag(BrushVolumeFaceVisibility.Back))
{
Vector3 normal = new Vector3(0, 0, 1);
vertices[index ] = new Vertex(new Vector3(width, height, depth), new Vector2(uvX, 0), normal);
vertices[index ] = new Vertex(new Vector3(-width, height, depth), new Vector2(0, 0), normal);
vertices[index ] = new Vertex(new Vector3(-width, -height, depth), new Vector2(0, uvY), normal);
vertices[index ] = new Vertex(new Vector3(-width, -height, depth), new Vector2(0, uvY), normal);
vertices[index ] = new Vertex(new Vector3(width, -height, depth), new Vector2(uvX, uvY), normal);
vertices[index ] = new Vertex(new Vector3(width, height, depth), new Vector2(uvX, 0), normal);
}
// Generate West Face
if (this.FaceVisibility.HasFlag(BrushVolumeFaceVisibility.Right))
{
Vector3 normal = new Vector3(-1, 0, 0);
// Clockwise
vertices[index ] = new Vertex(new Vector3(-width, height, depth), new Vector2(uvZ, 0), normal);
vertices[index ] = new Vertex(new Vector3(-width, -height, depth), new Vector2(uvZ, uvY), normal);
vertices[index ] = new Vertex(new Vector3(-width, -height, -depth), new Vector2(0, uvY), normal);
vertices[index ] = new Vertex(new Vector3(-width, -height, -depth), new Vector2(0, uvY), normal);
vertices[index ] = new Vertex(new Vector3(-width, height, -depth), new Vector2(0, 0), normal);
vertices[index ] = new Vertex(new Vector3(-width, height, depth), new Vector2(uvZ, 0), normal);
// Counter Clockwise
//vertices[index ] = new Vertex(new Vector3(-width, -height, -depth), new Vector2(0, uvY), normal);
//vertices[index ] = new Vertex(new Vector3(-width, -height, depth), new Vector2(uvZ, uvY), normal);
//vertices[index ] = new Vertex(new Vector3(-width, height, depth), new Vector2(uvZ, 0), normal);
//vertices[index ] = new Vertex(new Vector3(-width, height, depth), new Vector2(uvZ, 0), normal);
//vertices[index ] = new Vertex(new Vector3(-width, height, -depth), new Vector2(0, 0), normal);
//vertices[index ] = new Vertex(new Vector3(-width, -height, -depth), new Vector2(0, uvY), normal);
}
// Generate Top Face
if (this.FaceVisibility.HasFlag(BrushVolumeFaceVisibility.Top))
{
Vector3 normal = new Vector3(0, 1, 0);
vertices[index ] = new Vertex(new Vector3(width, height, depth), new Vector2(uvX, uvZ), normal);
vertices[index ] = new Vertex(new Vector3(-width, height, depth), new Vector2(0, uvZ), normal);
vertices[index ] = new Vertex(new Vector3(-width, height, -depth), new Vector2(0, 0), normal);
vertices[index ] = new Vertex(new Vector3(-width, height, -depth), new Vector2(0, 0), normal);
vertices[index ] = new Vertex(new Vector3(width, height, -depth), new Vector2(uvX, 0), normal);
vertices[index ] = new Vertex(new Vector3(width, height, depth), new Vector2(uvX, uvZ), normal);
}
// Generate Bottom Face
if (this.FaceVisibility.HasFlag(BrushVolumeFaceVisibility.Bottom))
{
Vector3 normal = new Vector3(0, -1, 0);
vertices[index ] = new Vertex(new Vector3(-width, -height, depth), new Vector2(uvX, uvZ), normal);
vertices[index ] = new Vertex(new Vector3(width, -height, depth), new Vector2(0, uvZ), normal);
vertices[index ] = new Vertex(new Vector3(width, -height, -depth), new Vector2(0, 0), normal);
vertices[index ] = new Vertex(new Vector3(-width, -height, depth), new Vector2(uvX, uvZ), normal);
vertices[index ] = new Vertex(new Vector3(-width, -height, -depth), new Vector2(uvX, 0), normal);
vertices[index ] = new Vertex(new Vector3(width, -height, -depth), new Vector2(0, 0), normal);
}
if (this._bufferBinding.Buffer != null)
{
this._bufferBinding.Buffer.Dispose();
}
this._drawCount = vertices.Length;
Buffer vertexBuffer = Buffer.Create(Device, BindFlags.VertexBuffer, vertices);
this._bufferBinding = new VertexBufferBinding(vertexBuffer, 32, 0); // 32 is Vertex Size In Bytes
}
Я оставил там записку, в которой показывал свои текущие мысли о том, как перевернуть лицо изнутри наружу. Довольно просто, я думал просто изменить порядок намотки. Мой двигатель по умолчанию использует обмотку по часовой стрелке, поэтому, если бы я перевернул обмотку для каждой грани против часовой стрелки, она выглядела бы как внутренняя часть двигателя. Это тоже работает. Впрочем, и это может быть глупым вопросом. Но является ли это стандартом? Я попытался Погуглить, как Блендер реализует «Пересчет внутри», но я не могу найти в Интернете ничего, обсуждающего фактические детали реализации.
Кто-нибудь знает, является ли стандартная практика переключения грани с внешней стороны на внутреннюю так же проста, как изменение порядка намотки?
Комментарии:
1. Я знаю, что мне также нужно будет перевернуть нормали и, вполне возможно, даже иметь другую текстуру и макет.
Ответ №1:
Я совершенно уверен, что инвертирование порядка намотки-это то, как это достигается. Мне также пришлось инвертировать координаты и нормали текстур, чтобы текстуры отображались правильно. Вот gif, показывающий результат моей реализации:
В этом gif я просто нажимаю клавишу, чтобы переключиться в «Режим корпуса» объема кисти.
Источник для этого примера находится на моем pastebin:
Вот краткий пример того, как я переворачиваюсь с внешнего на внутреннее и т. Д.
if (this.FaceVisibility.HasFlag(BrushVolumeFaceVisibility.Front))
{
if (this.HullMode == BrushVolumeHullMode.Interior)
{
Vector3 normal = new Vector3(0, 0, 1);
vertices[index ] = new Vertex(new Vector3(-width, height, -depth), new Vector2(0, 0), normal);
vertices[index ] = new Vertex(new Vector3(width, height, -depth), new Vector2(uvX, 0), normal);
vertices[index ] = new Vertex(new Vector3(width, -height, -depth), new Vector2(uvX, uvY), normal);
vertices[index ] = new Vertex(new Vector3(width, -height, -depth), new Vector2(uvX, uvY), normal);
vertices[index ] = new Vertex(new Vector3(-width, -height, -depth), new Vector2(0, uvY), normal);
vertices[index ] = new Vertex(new Vector3(-width, height, -depth), new Vector2(0, 0), normal);
}
else
{
Vector3 normal = new Vector3(0, 0, -1);
vertices[index ] = new Vertex(new Vector3(width, -height, -depth), new Vector2(0, uvY), normal);
vertices[index ] = new Vertex(new Vector3(width, height, -depth), new Vector2(0, 0), normal);
vertices[index ] = new Vertex(new Vector3(-width, height, -depth), new Vector2(uvX, 0), normal);
vertices[index ] = new Vertex(new Vector3(-width, height, -depth), new Vector2(uvX, 0), normal);
vertices[index ] = new Vertex(new Vector3(-width, -height, -depth), new Vector2(uvX, uvY), normal);
vertices[index ] = new Vertex(new Vector3(width, -height, -depth), new Vector2(0, uvY), normal);
}
}
Следует отметить, что моя реализация совсем не элегантна, потому что я жестко закодировал перевернутое состояние в ветвь if, в зависимости от режима корпуса. Программное обеспечение, подобное Blender, вероятно, имеет более экстравагантный способ сделать это, потому что им приходится перебирать гораздо больший (и динамичный) набор треугольников. Вероятно, существует причудливый алгоритм для инвертирования порядка намотки и координат текстуры. Однако я понятия не имею, что это может быть, потому что в Интернете нет материалов для этого.
Если кто-нибудь знает лучший способ сделать это, я бы очень хотел его увидеть.