Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Общие вопросы по .NET и C# > DirectX 4-мерная визуализация


Автор: marcusmae 16.4.2007, 18:07
Всем привет.

Под четырёхмерной визуализацией я понимаю визуализацию функции трёх переменных f(x,y,z), в которой  переменные откладываются по трём осям, а цвет служит индикатором того или иного значения функции (в лит-ре - volume visualization). Имею замысел сделать небольшую программку, скорее всего с использованием DirectX, которая могла бы это делать. Сразу скажу, что по четырёхмерке в сети очень мало наработок, имеющиеся - старые и закрытые, так что надо думать самому. Так что, если то, что я опишу далее, неосуществимо или можно сделать лучше - так и скажите, плз.

Положим, у меня имелись таблицы значений f(x,y,z), из которых я уже наштамповал стопку изображений с альфа-каналом. Каждое из этих изображений является срезом будующей визуализации по высоте, то есть, разместив их друг под другом, я получу желанный слоёный пирог. Проблема шага между слоями, в принципе, не стоит, поскольку промежуточные изображения можно сгенерить, воспользовавшись, например, интерполяционными полиномами. 

В чём же вопрос? = Затруднение вызывает вывод двухсторонних, полупрозрачных текстур (этих самых изображений) друг над другом с весьма малым шагом. Может быть, угостите советом/ссылкой или куском кода под DirectX?

ЗЫ: Пишу в раздел C#, однако готов разобраться и в плюсах.

Автор: mr.DUDA 17.4.2007, 10:22
Пример на XNA подойдёт ?

Автор: marcusmae 17.4.2007, 17:43
Цитата(mr.DUDA @ 17.4.2007,  10:22)
Пример на XNA подойдёт ?

Да, подойдёт.

Автор: mr.DUDA 17.4.2007, 18:59
Ok, только сразу предупреждаю не пугаться если с шейдерами не знаком smile

Исходник:
Код
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace WindowsGame1
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
        }


        Texture3D _texture;
        Effect _effect;
        VertexDeclaration _vertexFormat;
        VertexBuffer _vertexBuffer;

        protected override void LoadGraphicsContent(bool loadAllContent)
        {
            GraphicsDevice device = this.graphics.GraphicsDevice;

            // текстура
            _texture = Texture3D.FromFile(device, @"c:\NoiseVolume.dds");

            // шейдер
            CompiledEffect c_effect = Effect.CompileEffectFromFile(@"c:\my_shader.fx", null, null, CompilerOptions.None, TargetPlatform.Windows);
            _effect = new Effect(device, c_effect.GetEffectCode(), CompilerOptions.None, null);

            // вершины (будем рисовать квадрат из 2х треугольников)
            _vertexFormat = new VertexDeclaration(device, VertexPositionTexture.VertexElements);
            _vertexBuffer = new VertexBuffer(device, typeof(VertexPositionTexture), 6, ResourceUsage.WriteOnly);
            _vertexBuffer.SetData(new VertexPositionTexture[]
            {
                new VertexPositionTexture(new Vector3(-1f, -1f, 0), new Vector2(0, 0)),
                new VertexPositionTexture(new Vector3(0.75f, -1f, 0), new Vector2(1f, 0)),
                new VertexPositionTexture(new Vector3(-0.75f, 1f, 0), new Vector2(0, 1f)),
                new VertexPositionTexture(new Vector3(0.75f, -1f, 0), new Vector2(1f, 0)),
                new VertexPositionTexture(new Vector3(1f, 1f, 0), new Vector2(1f, 1f)),
                new VertexPositionTexture(new Vector3(-0.75f, 1f, 0), new Vector2(0, 1f))
            });
        }


        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice device = this.graphics.GraphicsDevice;
            device.Clear(Color.Black);

            // назначаем режимы рендеринга (render states)
            device.RenderState.DepthBufferEnable = false;
            device.RenderState.CullMode = CullMode.None;
            device.RenderState.AlphaBlendEnable = true;
            device.RenderState.SourceBlend = Blend.SourceAlpha;
            device.RenderState.DestinationBlend = Blend.InverseSourceAlpha;

            // назначаем вершинный буфер
            device.Vertices[0].SetSource(_vertexBuffer, 0, VertexPositionTexture.SizeInBytes);
            device.VertexDeclaration = _vertexFormat;

            // назначаем текстуру
            device.Textures[0] = _texture;

            // техника у нас одна
            _effect.CurrentTechnique = _effect.Techniques[0];
            float numLayers = (float)_texture.Depth;

            // проходим по каналам 3D-текстуры
            for (float iLayer = 0; iLayer < numLayers; iLayer++)
            {
                // определяем параметры эффекта
                _effect.Parameters["layerHeight"].SetValue(16f / numLayers);
                _effect.Parameters["layerY"].SetValue(1f - 2f * iLayer / numLayers);
                _effect.Parameters["layerIndex0to1"].SetValue(iLayer / numLayers);

                // рисуем квадрат с прозрачностью
                _effect.Begin();
                _effect.CurrentTechnique.Passes[0].Begin();
                device.DrawPrimitives(PrimitiveType.TriangleList, 0, 2);
                _effect.CurrentTechnique.Passes[0].End();
                _effect.End();
            }

            base.Draw(gameTime);
        }
    }
}


my_shader.fx
Код
uniform sampler3D Tex;

// параметры для вертексного шейдера
uniform float layerHeight;
uniform float layerY;

// параметры для пиксельного шейдера
uniform float layerIndex0to1;


void vs_main
(
    float4 pos : POSITION,
    float2 texCoord : TEXCOORD,
    
    out float4 oPos : POSITION,
    out float2 oTexCoord : TEXCOORD
)
{
    // координаты вершин - сдвигаем и масштабируем Y чтобы показать слои друг над другом в перспективе
    oPos = pos;
    oPos.y = oPos.y * layerHeight + layerY;

    // координаты в волюметрической текстуре
    oTexCoord = texCoord;
}


float4 ps_main(float2 texCoords: TEXCOORD0) : COLOR
{
    // составляем 3-мерные текстурные координаты из 2-мерных и номера слоя (0..1)
    float3 texCoords3D = float3(texCoords, layerIndex0to1);

    // получаем цвет пиксела
    return tex3D(Tex, texCoords3D);
}


technique SimpleTexturing
{
    pass p0
    {
        vertexshader = compile vs_2_0 vs_main();
        pixelshader = compile ps_2_0 ps_main(); 
    }
}


Трехмерная текстура может быть любая. Шейдер и текстуру можно положить в любую директорию, только пути подправить в коде.

Отрисованный результат можно забрать из бэкбуфера в текстуру (device.ResolveBackBuffer) и к примеру сохранить в файл.

Автор: marcusmae 17.4.2007, 23:25
Цитата(mr.DUDA @  17.4.2007,  18:59 Найти цитируемый пост)
только сразу предупреждаю не пугаться если с шейдерами не знаком 

Не знаком. Не пугаюсь, наборот, оч любопытно.

С XNA ранее не работал, но сейчас поставлю и буду обучаться (кажется, это того стоит).  smile

Большое спасибо за подробный пример!  smile 

Автор: mr.DUDA 18.4.2007, 09:39
Я отредактировал предыдущий пост, добавил перспективу (см. скрин).  В первом варианте слои "склеивались" в один квадрат повёрнутый к наблюдателю. На скрине - шумовая текстура без прозрачности (других не было). Можно поиграться с настройкой параметров (строки 78 и 79), чтобы все слои "бутерброда" были видны.

Автор: Lеstat 19.4.2007, 18:50
Не подскажете как можно выводить то, что рисует XNA на свою форму?

Автор: mr.DUDA 19.4.2007, 22:47
Цитата(Lеstat @  19.4.2007,  18:50 Найти цитируемый пост)
Не подскажете как можно выводить то, что рисует XNA на свою форму?

Это второй вопрос smile
С ходу не отвечу, но видимо достаточно выполнить GraphicsDevice.Reset передав туда PresentationParameters с указанием собственного контрола в DeviceWindowHandle.

Автор: Kvazilol 20.4.2007, 01:34
прошу прощения, а как понормальному поставить XNA ? у меня оно пишет что требуется VisualStudio Express но я не собираюсь сносить Final и ставить это убожесто 

Автор: Lеstat 20.4.2007, 02:41
покапался и вот что нашел...  интересные статейки
http://www.ziggyware.com/readarticle.php?article_id=82
http://blogs.msdn.com/shawnhar/archive/2007/01/23/using-xna-with-winforms.aspx
"сам шучу, сам смеюсь" ©  smile 

а вот на тему как поставить без экспресса... так бегло просморел
http://www.xnadev.ru/modules.php?name=Forums&file=viewtopic&t=132
http://www.xnadev.ru/modules.php?name=Forums&file=viewtopic&t=87&start=0&postdays=0&postorder=asc&highlight=
http://www.xnadev.ru/modules.php?name=Forums&file=viewtopic&t=60

Автор: mr.DUDA 20.4.2007, 09:36
Kvazilol, 
Модератор: Пожалуйста, один топик - один вопрос.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)