Большой поплавок для шейдерного исследователя Мандельброта - PullRequest
2 голосов
/ 04 февраля 2010

Мне удалось создать простой проводник Мандельброта с использованием Open Gl и CGFX SDK, предоставленный NVidia.Он работает хорошо, но в настоящее время основан на плавающей запятой и поэтому не имеет большой «глубины» - поскольку расстояние от самого низкого комплексного числа до самого большого уменьшается, точность теряется, и результирующее изображение «пикселируется».

К сожалению, CGFX, похоже, не поддерживает двойную точность, и даже тогда двойная точность ограничена моими намерениями.Поскольку CGFX из-за его предполагаемого дизайна не имеет класса bignum, я подумал, что будет лучше создать свой собственный.

Мне удалось создать прототип в C ++ - который использует только целые числа без знака -но когда я попытался переместить его в CGFX, FX Composer 2.5 не смог его скомпилировать.Поскольку я использую только целые числа без знака, умножение и сложение, код содержит много операций сдвига битов, которые в соответствии с FX Composer 2.5 недоступны в моем профиле.

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

Так что, если у кого-то есть ответ на любой из этих вопросов, я был бы благодарен:

  1. Поддерживает ли CGFX или любой другой язык шейдеров операторы сдвига битов для целых чисел без знака и с плавающей точкой (Требуется для преобразования чисел с плавающей точкой в ​​большие)?

  2. Поддерживает ли CGFX или любой другой язык шейдеров двойную точность или большую плавающую точку?

  3. Есть ли более утонченный математический способ решения моей проблемы, чем создание большого класса с плавающей точкой?

Если таковые имеютсяВам нужно больше разъяснений или фрагментов кода, не стесняйтесь спрашивать.

Ответы [ 2 ]

2 голосов
/ 04 февраля 2010

Если вы строго выполняете набор Мандельброта, вам лучше использовать представление с фиксированной точкой.Возможно, вы захотите начать с 5 бит слева от радиуса и одним знаковым битом.Таким образом, для 32-битного у вас будет 26 справа от десятичной дроби.для 64 бит вы получите 58 бит справа, что лучше двойной точности.Также с математикой с фиксированной точкой все битовые сдвиги будут фиксированными, а не переменными, необходимыми для плавающей запятой.

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

1 голос
/ 13 марта 2010

Чтобы ответить на ваш вопрос относительно битовых операций

OpenGL 3.1 / GLSL 1.40 (ядро) и расширение OpenGL GL_ARB_gpu_shader4 добавляет поддержку целочисленной арифметики без знака и битовых операций, таких как сдвиги, побитовое ИЛИ и побитовое И. Благодаря этой функциональности в GLSL конструкторы int (uint) и uint (int) делают то, что вы ожидаете, если у вас есть фон C или C ++. Он рассматривает наиболее значимый бит буквально как знак, поэтому вы можете использовать конструкторы вместо приведения. Более поздние версии GLSL также позволяют вам устанавливать точность для чисел с плавающей запятой, но не так много графических карт пока поддерживают аппаратную двойную точность.

Дополнительные предложения

Я с Пхалером на этом. То, что вы хотите, это фиксированная точка, а не тип с плавающей точкой. Учитывая, что набор Мандельброта живет в радиусе 2 в комплексной плоскости, вам нужно только 3 бита для целочисленной части. Вместо того, чтобы делать квадратный корень, проверьте, больше ли значение квадрата z больше 4. Вам нужно будет принять во внимание переполнение / недополнение со знаком. Как рассчитать общие арифметические флаги описано ниже. Я не проверял их в GLSL, но логика логична.

Расчет арифметических флагов

Легенда:

C = флаг переноса (переполнение без знака)
V = флаг переполнения
Z = нулевой флаг (равенство)
N = отрицательный флаг

Алгоритмы

Given: `dst = src1 + src2` then:
C = (unsigned)dst < (unsigned)src1 || (unsigned)dst < (unsigned)src2
V = ((signed)dst < (signed)src1) != ((signed)src2 < 0)
Z = !dst
N = (unsigned)dst & (1<<31)

Для вычисления этих флагов требуется много ветвлений, поэтому не удивляйтесь, если ваш GPU ненавидит вас за это. Когда вы можете извлечь их, реализация длинного умножения и сложения с переносом не должна быть проблемой.

...