Проблемная прорисовка эффекта 3d-стиля - PullRequest
2 голосов
/ 14 декабря 2011

Я ломал голову, пытаясь понять, как оживить эффект. Это связано с вопросом, который я задал на math.stackexchange.com.

https://math.stackexchange.com/questions/91120/equal-division-of-rectangles-to-make-total/

В качестве примечания, я не реализовывал алгоритм рисования, который был определен в вопросе выше, - вместо этого использовал свой собственный, чтобы изменить перспективу, чтобы она выглядела более сжатой.

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

enter image description here

Мой код следующий,

        List<double> sizes = new List<double>();
        private void Form1_Load(object sender, EventArgs e)
        {
            for (int y = 1; y < 10; y++)
            {
                double s = ((240 / 2) / y) / 4;
                sizes.Add(s);
            }
            sizes.Add(0);
        }

        int offset = 0;
        private void button1_Click(object sender, EventArgs e)
        {
            Bitmap b = new Bitmap(320, 480);
            Graphics g = Graphics.FromImage(b);

            Color firstColor = Color.DarkGray;
            Color secondColor = Color.Gray;    
            Color c = firstColor;

            int yOffset = 0;
            for(int i = 0; i < sizes.Count; i++)
            {
                c = (i % 2 == 0) ? firstColor : secondColor;

                int y = (int)Math.Round(b.Height - yOffset - sizes[i]);
                int height = (int)Math.Round(sizes[i]);

                g.FillRectangle(new SolidBrush(c), new Rectangle(0, y + offset, b.Width, height + offset));
                yOffset += (int)sizes[i];
            }

            this.BackgroundImage = b;
            offset+=1;
        }

Каждое нажатие кнопки должно приводить к изменению размера и смещению прямоугольников. Тем не менее, мои прямоугольники не растут, как они должны. Моя логика прекрасно работает, но просто не работает, поскольку движение идет.

Итак, мой вопрос:

Существует ли существующий алгоритм для этого эффекта, о котором я не знаю, или это что-то довольно простое, о чем я слишком много думаю? Буду очень признателен за любую помощь в исправлении моей логики или в правильном направлении.

Ответы [ 2 ]

3 голосов
/ 14 декабря 2011

Интересно ...

(видео ответа здесь: http://youtu.be/estq62yz7v0)

Я бы сделал это так:

Во-первых, отбросьте все рисование RECTANGLE и нарисуйте свой эффект построчно. Вот так:

for (int y=start;y<end;y++) 
{
    color = DetermineColorFor(y-start);
    DrawLine(left, y, right, y, color);
}

Это, конечно, псевдокод, который не стоит беспокоить GDI + или чем-то еще.

Здесь все понятно, кроме того, как кодировать DetermineColorFor() метод. Этот метод должен будет вернуть цвет линии на заданной ПРОЕКТНОЙ высоте. projection diagram

Теперь на картинке у вас есть:

  • Ваша точка зрения (X) - не знал, как нарисовать глаз
  • красная линия (это ваш экран - проекционная плоскость)
  • ваш фон (чередующиеся полосы внизу)
  • и несколько проектирующих линий, которые должны помочь вам разработать DetermineColorFor() метод

Подсказка - используйте сходство треугольников для перехода от экранных координат к координатам «бара».
Следующий совет - когда вы находитесь в «барных» координатах, используйте оператор по модулю для определения цвета.

Я добавлю больше подсказок, если это необходимо, но было бы здорово, если бы вы решили это самостоятельно.


Меня как-то вдохновил вопрос, и я создал код для решения. Вот оно:

int _offset = 0;
double period = 20.0;
private void timer1_Tick(object sender, EventArgs e)
{
    for (int y = Height / 3; y < Height; y++)
    {
        using (Graphics g = CreateGraphics())
        {
            Pen p = new Pen(GetColorFor(y - Height / 3));
            g.DrawLine(p, 0, y, Width, y);
            p.Dispose();
        }
    }
    _offset++;
}

private Color GetColorFor(int y)
{
    double d = 10.0;
    double h = 20.0;
    double z = 0.0;
    if (y != 0)
    {
        z = d * h / (double)y + _offset;
    }
    double l = 128 + 127 * Math.Sin(z * 2.0 * Math.PI / period);
    return Color.FromArgb((int)l, (int)l, (int)l);
}

Эксперимент с:

  • d - расстояние от глаза до проекционного экрана
  • h - высота глаза от 'бара'
  • period - ширина полосы на полосе

У меня был таймер в форме и событие правильно подключено. Продолжительность таймера составила 20 мс.

0 голосов
/ 14 декабря 2011

Учитывая, что вы говорите здесь о 2D рендеринге, насколько я понимаю, мне кажется, что вы собираетесь заново изобрести колесо. Потому что то, что вам нужно, ИМХО; используется Матричные преобразования , уже доступные в GDI + для 2D-рендеринга.

Пример применения его в GDI +: GDI + и MatrixTranformations

Для этого они используют System.Drawing.Drawing2D.Matrix класс, который находится внутри Graphics .

Самым лучшим из когда-либо использованных фреймворков для 2D-рендеринга является Piccolo2D , который я с большим успехом использовал в большом реальном проекте. Обязательно используйте это для ваших проектов 2D рендеринга, но сначала вам нужно немного изучить его.

Надеюсь, это поможет.

...