Всем-всем, добрый день!!! Есть у меня одна простая задача, которая не решается почти год (не могу сказать, что я этим горжусь Нужно нарисовать КРУГ так, чтобы центр был светлым, а ближе к краям цвет плавно изменялся вплоть до черного (Рис.1)
Рис.1 Окружность залитая монохромным градиентом
И все хорошо если круг такого же размера как и на Рис.1, но как только размер увеличивается или же уменьшается контраст между центром и краями, то выплывают самые некрасивые вещи... [spoiler]
Во-первых появляются концентрические окружности (Рис.2).
Рис.2 Проявление концентрических окружностей
Во-вторых этот эффект ни чем не получается устранить: ни увеличением промежутков цветовой составляющей, ни изменением альфа-канала. При тех же значениях - тот же эффект! Грустно
Многие подумают что это похоже на 8 битное изображение. Тогда вопрос, как проверить какой режим OpenGL выбирает для рисования?
Заранее оговорюсь никаких шейдеров, текстур и тому подобного я не использую. Сейчас все рисуется так: 1) Круг рисуется, как набор из GL_TRIANGLE_FAN; 2) Центр окружности (вершина А треугольника АБЦ) имеет цвет glColor4fv(HI_color) - светлая середина; 3) Вершины Б и Ц - точки на окружности, имеют цвет glColor4fv(LOW_color) - темные края; 4) Градиент OpenGl рисует сам, как в Уроке 5.3 про треугольник со спектральным разложением.
Дело, мне кажется в том, что Джель "не понимает" цвета меньше значения 1/(byte)255 = (float)0.0039
ВОПРОС Какой предел имеют параметры цвета в модели RGBA (сотые, тысячные, десятитысячные (.00, .000, .0000))? До какой степени можно дробить эти параметры, чтобы была видна разница в цвете? И как можно обойти подобные ограничения по выводу цвета на экран?
ДЛЯ ЧЕГО ЭТО ВСЕ НУЖНО Нужно изменяя либо цвет, либо прозрачность (альфа-канал) добиться плавного растворения фигуры в цвете фона сцены так, чтобы четкие переходы не были видны.
Понравилась публикация? Сохраните ее, чтобы вернуться к изучению материала!
Проблема усложняется тем, что весь этот градиент планируется не «от балды» (как сейчас рисовать, а через задание функции градиента. Т.е. цвет может быть задан нелинейно. Такой вариант я уже запрограммировал, но там та же беда, с теми же цветовыми значениями: всё те же концентрические круги, овалы, линии и плавного перехода нет как ни крути.
Читал про разные подходы, как это можно устранить, предлагали: и bloom-эффект, и шейдеры использовать, и цветовую модель HDR, и про dithering читал, чего только не пишут!!!
Но ни где толком не сказано, КАК КОНКРЕТНО МОЖНО ЭТУ ПРОБЛЕМУ РЕШИТЬ!
Помогите люди добрые, хотя бы идею какую-нибудь свежую дайте, пожалуйста!
Пока ни каких соображений не появилось, кроме как переписать этот же код на Директе или Флеше и посмотреть на результат. Может быть там есть встроенный инструмент для удаления подобных дефектов.
for(int i=0;i>=r;r++) { glBegin(GL_POINT); glColor3f(плавный градиент зависит от i); for(int j=0; j<=9999; j+=0.01) float y = centerY + (y * sin(j)); float x = centerX + (r * cos(j)); glVertex2f(x,y); glEnd; } я зная что маньяк, r*9999 циклов — это хорошо, но там можно радианы в градусы перевести и оптимизировать количество обходов с 9999 до 360
блин, а можно же это всё через трианглы сделать… тогда и цвет вычислять не надо и радиусы обходить for(int i=0;i>=360;i++) { glColor3f(255,255,255); glVertex2f(centerX,centerY);
Круг рисуется по такому же алгоритму как ты предлагаешь — через трианглы. Все гуд, рисует правильно! Проблема в ЦВЕТЕ, точнее в отображении промежуточных оттенков цвета. Грубо говоря, моя программа не видит разницы между glColor3f(0.501f, 0.501f, 0.501f) и glColor3f(0.502f, 0.502f, 0.502f). Этот пример из головы навскидку, в программе не проверял, там может быть отличие не в «тысячных» разрядах, а в «стотысячных».
Я выложу картинку, которая отображает мою проблему.
Мне нужно получить в программе верхнюю полосу с плавным градиентом, а Джель закрашивает все фигуры как показано на нижней полоске. Т.е. определенный участок оттенка воспринимается как один и тот же цвет. Вопрос как это исправить?
Может быть какой-то особый цветовой режим нужно включить? Или еще что-то Пока в голову приходит только попиксельная обработка, но как её сделать не знаю.
Эсли такими же трианглами создать кружок, то не должно быть разницы… 0_оА она есть!!! При малом отличии соседних цветов и большом радиусе особенно видно становится. И я уже всякую надежду потерял это исправить
// Создание круга в памяти; private void GradienCircle(float[] HI_color, float[] LOW_color) { float rad = 0.3f; // Радиус круга; // Количество точек на окружности // чем больше, тем круг плавнее; int cv = 72; // Массив координат точек окружности; float[] va = new float[cv*2+2]; CreateCircle(rad, cv, va); // Создаем координаты окружности; ResizeBlurStep(1); // Обнулим дисплейные списки;
Gl.glPushMatrix(); // Создаем градиентно закрашеный круг в памяти; GradienCircle(HiColor, LowColor); // Отрисовуем список отображения; Gl.glCallList(LIST_net);
Я может не понял, но хочешь чтоб круг растворялся в фоне, почему тогда не привязал фон к LowColor. P. S. Еще обработчик resize не добавил в events, при изменении размера окна сцену не перерисовывает, а глюки выдает.
Ты такой эффект хочешь получить? Нет, мне нужно чтобы фон был (127, 127, 127); яркая точка в центре круга (0, 0, 0); темные края круга (255, 255, 255). И постепенно края и центр круга становятся такого же цвета, как и фончик
, что получилось, у себя артефактов(те внутренние кружки что у тя на скрине) не увидел. Круг равномерно исчезает, а потом появляется. Мне кажеться можно добиться более интересного эффекта если цвет краев заставить постепенно сливаться с цветом фона.
Круг равномерно исчезает, а потом появляется.Если бы это для игры какой-то, то все было бы супер, а тут точность нужна высокая. Потому что от этого эффекта зависит как я буду проводить калибровку конкретного монитора.
Вообще вместо круга лучше нарисовать сферу, а яркое пятно получить с помощью источника света(всех рассеянного, диффузного и отраженного) и присвоить материалу объекта зеркальное отражение(макс. фокусировку отражения). Получиться красивый зеркальный блик. А потом сделать постепенно уменьшение альфа(как сейчас и есть) и будет супер и без градиента.
Понимаешь еще в чем дело, даже при меньшем радиусе окружности получается тоже самое, с той лишь разницей, что эти кружочки ступенчатые меньше по размеру.
Попробовал, да.., видны..( Провел тест в фотошопе=): — создал фон (127, 127, 127); выделил окружность в центре сделал радиальный градиент центр=(255, 255, 255) края =(255, 255, 255)(у тя кстати в одном комменте наоборот, ошибся?)) — окружность рисовал на новый слой, потом менял непрозрачность(альфа) слоя, оказалось тоже есть артефакты хотя и меньшие. Я думаю меньше из за того что светлое пятно получилось больше, черный был только по краям(не знаю с чем это связано)
Может цветовой спектр изначально неудачен, не вписывается в 8 бит на цвет, мало=). Фон(127,127,127) находиться в середине от центра окружности до края, это само по себе под "зубья подводит". При том что у нас каждый бит использует одно значение. получается только 255 шагов в спектре, при высоком разрешении, хотя бы 1280Х720монитора, на окружность приходиться большая часть) ясно дело, что ступеньки выходят. Если размер окружности уменьшить ближе к значению 255(в пикселях) будет плавный переход. А так как монитор может потянуть только 8 бит на цвет(24 битовый режим). Остается, или же в цвет фона использовать еще биты(127,20,127) или на самой окружности. Давая другой цветовой спектр дополнительные биты сделают плавный переход, а то так получается у нас 8 битовый режим. Кстати 32 битный режим монитора, нужен только для оптимизации памяти, так как слово у 32 битных машин = 32 бита))) 4-ый бит не используется.(только в файлах для альфа)
Приплыли, замечательно… Даже не знаю куда теперь грести?!
Подскажи пожалуйста, как тогда в фотошопе сам механизм смешивания может быть реализован? Или тот же инструмент «Размытие» — если жесткость убрать, то там сколько угодно оттенков получить выйдет и при этом глаз не заметит перехода, только «Волшебной полочкой» оттенок можно будет уловить.
8 бит на цвет, мало=).Если размер окружности уменьшить ближе к значению 255(в пикселях) будет плавный переход.Это я уже понял методом тыка
Остается, или же в цвет фона использовать еще биты(127,20,127) или на самой окружности. Давая другой цветовой спектр дополнительные биты сделают плавный переходПро это совсем не понял. Цвет окружности уже не серый будет, или я ошибаюсь?
про HDRI читал, действительно есть над чем подумать, но дело в том, что я не пойму через что это можно реализовать в Джеле.
С чего начать код писать?
Вот еще не понятно: Вся сцена (и при необходимости и также отдельные ее части) выводится в floating-point-текстуру (FP16 или FP32). После этого данная текстура преобразуется тем или иным путем и в результате мы получаем обычное (не floating-point) изображение с приведеными цветами, которое и выводится.
Цитата из статьи.Каким конкретно «тем или иным путем»? Что мне нужно с этой текстурой сделать?
Почитал какую нашел информацию, да и ребята подсказали, буду пробовать сделать так: в Фотошопе создам текстуру 128*128, сделаю заливку серым (127,127,127) цветом, далее добавлю монохромный шум и изменяя прозрачность буду натягивать её поверх изображенной на сцене окружности (2-й рисунок этого топика). О результатах сих метаморфоз сообщу дополнительно
Читал про разные подходы, как это можно устранить, предлагали: и bloom-эффект, и шейдеры использовать, и цветовую модель HDR, и про dithering читал, чего только не пишут!!!
Но ни где толком не сказано, КАК КОНКРЕТНО МОЖНО ЭТУ ПРОБЛЕМУ РЕШИТЬ!
Помогите люди добрые, хотя бы идею какую-нибудь свежую дайте, пожалуйста!
for(int i=0;i>=r;r++)
{
glBegin(GL_POINT);
glColor3f(плавный градиент зависит от i);
for(int j=0; j<=9999; j+=0.01)
float y = centerY + (y * sin(j));
float x = centerX + (r * cos(j));
glVertex2f(x,y);
glEnd;
}
я зная что маньяк, r*9999 циклов — это хорошо, но там можно радианы в градусы перевести и оптимизировать количество обходов с 9999 до 360
for(int i=0;i>=360;i++)
{
glColor3f(255,255,255);
glVertex2f(centerX,centerY);
glVertex2f();
glVertex2f();
}
x,y=0;
for(int i=0;i>=360;i++)
{
glColor3f(255,255,255);
glVertex2f(centerX,centerY);
glColor3f(0,0,0);
glVertex2f(oldPoint.x,oldPoint.y);
Point.x=centerX + (r * sin(i/Math.PI*180));
Point.y=centerY + (r * cos(i/Math.PI*180));
glVertex2f(Point.x,Point.y);
oldPoint=Point;
}
Спасибо большое за советы, amid!
Но тут дело не в том, что у меня НЕ получается кружочек нарисовать.
Сейчас ниже новую ветку комментов создам.
Проблема в ЦВЕТЕ, точнее в отображении промежуточных оттенков цвета. Грубо говоря, моя программа не видит разницы между glColor3f(0.501f, 0.501f, 0.501f) и glColor3f(0.502f, 0.502f, 0.502f). Этот пример из головы навскидку, в программе не проверял, там может быть отличие не в «тысячных» разрядах, а в «стотысячных».
Я выложу картинку, которая отображает мою проблему.
Мне нужно получить в программе верхнюю полосу с плавным градиентом, а Джель закрашивает все фигуры как показано на нижней полоске. Т.е. определенный участок оттенка воспринимается как один и тот же цвет.
Вопрос как это исправить?
Пока в голову приходит только попиксельная обработка, но как её сделать не знаю.
И я уже всякую надежду потерял это исправить
Я могу выложить архив с программой для скачивания, чтобы тут не плодить новых веток.
С кодом такая ситуация:
// Инициализация OpenGL
void InitGl()
{
Glut.glutInitDisplayMode(Glut.GLUT_RGBA|
Glut.GLUT_DEPTH|Glut.GLUT_DOUBLE|
Glut.GLUT_ALPHA);
Gl.glEnable(Gl.GL_DEPTH_TEST);
Gl.glClearDepth(1.0f);
Gl.glDepthFunc(Gl.GL_LEQUAL);
Gl.glShadeModel(Gl.GL_SMOOTH);
Gl.glHint(Gl.GL_PERSPECTIVE_CORRECTION_HINT, Gl.GL_NICEST);
Gl.glEnable(Gl.GL_BLEND);
Gl.glBlendFunc(Gl.GL_SRC_ALPHA, Gl.GL_ONE_MINUS_SRC_ALPHA);
Gl.glEnable(Gl.GL_ALPHA_TEST);
}
// Изменение размеров сцены;
void ResizeGlScene()
{
Gl.glViewport(0, 0, OpenGlControl.Width, OpenGlControl.Height);
Gl.glMatrixMode(Gl.GL_PROJECTION);
Gl.glLoadIdentity();
Glu.gluPerspective(45.0f, (float)OpenGlControl.Width /
(float)OpenGlControl.Height, 0.1f, 100.0f);
Gl.glMatrixMode(Gl.GL_MODELVIEW);
Gl.glLoadIdentity();
}
// Создание круга в памяти;
private void GradienCircle(float[] HI_color, float[] LOW_color)
{
float rad = 0.3f; // Радиус круга;
// Количество точек на окружности
// чем больше, тем круг плавнее;
int cv = 72;
// Массив координат точек окружности;
float[] va = new float[cv*2+2];
CreateCircle(rad, cv, va); // Создаем координаты окружности;
ResizeBlurStep(1); // Обнулим дисплейные списки;
Gl.glPushMatrix();
Gl.glNewList(LIST_net, Gl.GL_COMPILE);
Gl.glBegin(Gl.GL_TRIANGLE_FAN);
// ОШИБКА В ОТОБРАЖЕНИИ ЦВЕТОВ ЗДЕСЬ
// Центр круга рисуется светлым;
Gl.glColor4fv(HI_color);
Gl.glVertex2f(va[0], va[1]);
// Остальные точки окружности темным;
Gl.glColor4fv(LOW_color);
for (int i=2; i<va.Length; i+=2)
{
Gl.glVertex2f(va, va[i+1]);
}
Gl.glVertex2f(va[2], va[3]);
Gl.glEnd();
Gl.glEndList();
Gl.glPopMatrix();
}
// Рисование сцены;
private void DrawGlScene()
{
float[] HiColor = { 1, 1, 1, 1 };
float[] LowColor = { 0, 0, 0, 1 };
HiColor[3] = LowColor[3] = CONTRAST_ALPHA / 100;
// Начинаем рисование с очистки экрана;
// Цвет фона сцены серый;
Gl.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
Gl.glClear(Gl.GL_COLOR_BUFFER_BIT | Gl.GL_DEPTH_BUFFER_BIT);
Gl.glLoadIdentity();
Gl.glTranslatef(0, 0, -1);
Gl.glPushMatrix();
// Создаем градиентно закрашеный круг в памяти;
GradienCircle(HiColor, LowColor);
// Отрисовуем список отображения;
Gl.glCallList(LIST_net);
Gl.glPopMatrix();
Gl.glFlush();
OpenGlControl.Invalidate();
}
Вот на исходники и пример программы.
А можно по-подробнее про спрайт и его реализацию для конкретного случая?
Ты такой эффект хочешь получить?
Я может не понял, но хочешь чтоб круг растворялся в фоне, почему тогда не привязал фон к LowColor.
P. S. Еще обработчик resize не добавил в events, при изменении размера окна сцену не перерисовывает, а глюки выдает.
Концентрические круги видны (( Ты пробовал запускать приложение в полноэкранном режиме (клавиша F2).
Провел тест в фотошопе=):
— создал фон (127, 127, 127);
выделил окружность в центре сделал радиальный градиент центр=(255, 255, 255) края =(255, 255, 255)(у тя кстати в одном комменте наоборот, ошибся?))
— окружность рисовал на новый слой, потом менял непрозрачность(альфа) слоя, оказалось тоже есть артефакты хотя и меньшие. Я думаю меньше из за того что светлое пятно получилось больше, черный был только по краям(не знаю с чем это связано)
Может цветовой спектр изначально неудачен, не вписывается в 8 бит на цвет, мало=).
Фон(127,127,127) находиться в середине от центра окружности до края, это само по себе под "зубья подводит". При том что у нас каждый бит использует одно значение. получается только 255 шагов в спектре, при высоком разрешении, хотя бы 1280Х720монитора, на окружность приходиться большая часть) ясно дело, что ступеньки выходят.
Если размер окружности уменьшить ближе к значению 255(в пикселях) будет плавный переход.
А так как монитор может потянуть только 8 бит на цвет(24 битовый режим).
Остается, или же в цвет фона использовать еще биты(127,20,127) или на самой окружности. Давая другой цветовой спектр дополнительные биты сделают плавный переход, а то так получается у нас 8 битовый режим.
Кстати 32 битный режим монитора, нужен только для оптимизации памяти, так как слово у 32 битных машин = 32 бита))) 4-ый бит не используется.(только в файлах для альфа)
Подскажи пожалуйста, как тогда в фотошопе сам механизм смешивания может быть реализован?
Или тот же инструмент «Размытие» — если жесткость убрать, то там сколько угодно оттенков получить выйдет и при этом глаз не заметит перехода, только «Волшебной полочкой» оттенок можно будет уловить.
8 бит на цвет, мало=).Если размер окружности уменьшить ближе к значению 255(в пикселях) будет плавный переход.Это я уже понял методом тыка
Остается, или же в цвет фона использовать еще биты(127,20,127) или на самой окружности. Давая другой цветовой спектр дополнительные биты сделают плавный переходПро это совсем не понял. Цвет окружности уже не серый будет, или я ошибаюсь?
С чего начать код писать?
Вот еще не понятно:
Вся сцена (и при необходимости и также отдельные ее части) выводится в floating-point-текстуру (FP16 или FP32).
После этого данная текстура преобразуется тем или иным путем и в результате мы получаем обычное (не floating-point) изображение с приведеными цветами, которое и выводится.
Цитата из статьи.Каким конкретно «тем или иным путем»? Что мне нужно с этой текстурой сделать?
С чего начать писать шейдер?
Я на C# сто лет не писал, как включить и использовать расширение в ТАО, понятия не имею. На с++ я использую Glew, а тут фиг его.
О результатах сих метаморфоз сообщу дополнительно
И к сожалению ничего не решилось
Сдам экзамены и буду снова ковырять — дело принципа!