В настоящее время я работаю над программой, которая должна генерировать случайный шум на экране, основываясь на «координатах» пикселя. Координаты должны иметь одинаковый цвет при каждом перезапуске программы. Однако, используя утилиту Java.Random, результаты, которые я получаю, не так случайны, как хотелось бы:
Я думал, что если бы я использовал объединенные координаты (как в одном целом числе, сформированном из обеих координат рядом друг с другом), у каждой координаты был бы другой номер. Используя это число в качестве начального числа, я ожидал получить разные случайные числа для каждой координаты, чтобы использовать их для значения rgb этой координаты.
Это код, который я использовал:
public class Generate {
static Random Random;
public static int TileColor(int x, int y){
Random = new Random(Integer.valueOf(Integer.toString(x)+Integer.toString(y)));
int b = 1 + Random.nextInt(50);
int g = 1 + Random.nextInt(50);
int r = 1 + Random.nextInt(50);
int color = -Color.rgb888(r, g, b);
return color;
}
}
Является ли шаблон, который создает программа, из-за того, как работает функция java Random, или я делаю что-то не так, и мне следует попробовать другой подход?
Обновление: теперь я попытался избавиться от проблем, связанных с конкатенацией, используя следующий код:
public static int TileColor(int x, int y){
Randomy = new Random(y);
Randomx = new Random(x);
Random = new Random(Integer.valueOf(Integer.toString(Randomx.nextInt(1234))+Integer.toString(Randomy.nextInt(1234))));
int b = 1 + Random.nextInt(100);
int g = 1 + Random.nextInt(100);
int r = 1 + Random.nextInt(100);
int color = -Color.rgb888(r, g, b);
return color;
}
Каким-то образом это также дало (на мой взгляд) достаточно случайное изображение:
Этот код, однако, повторяется три раза на пиксель. Несмотря на то, что сейчас это не проблема для меня, я думаю об изменении этого кода на тот случай, если позже мне понадобится улучшенная производительность.
Ответы:
java.util.Random
Класс Java обычно дает вам последовательности псевдослучайных чисел, которые достаточно хороши для использования в играх 1 . Однако эта характеристика применяется только к последовательности из нескольких выборок на основе начального числа. Когда вы повторно инициализируете ГСЧ с увеличивающимися начальными значениями и просматриваете только первое значение каждой последовательности, характеристики случайности будут не такими хорошими.Что вы могли бы сделать вместо этого:
Вместо использования генератора случайных чисел используйте функцию дайджеста сообщения, чтобы превратить пару координат в значение цвета. Вывод большинства MDF достаточно непредсказуем, чтобы выполнить большинство тестов на случайность. Выходные данные обычно превышают 24 бита, необходимые для значения RGB, но их усечение обычно не составляет проблем.
Для повышения производительности вы можете комбинировать генерацию дайджеста сообщений с кусками. Создайте небольшие куски пикселей, которые достаточно велики, чтобы использовать всю длину одного вывода вашей функции дайджеста.
1, когда абсолютно необходимо, чтобы никто не мог предсказать следующее число, используйте более медленное, но менее предсказуемое
java.security.SecureRandom
источник
В этом случае вы захотите использовать детерминированную шумовую функцию, такую как шум Перлина или симплексный шум .
( См. Этот вопрос для получения дополнительной информации о шуме Perlin с некоторыми красивыми картинками. )
В большинстве
random()
случаев использование встроенной или аналогичной функции будет давать вам разные значения при каждом запуске программы, поскольку они могут использовать часы в качестве входных данных или какое-либо другое псевдослучайное значение.Другой вариант - создать «карту шума» один раз в автономном режиме, а затем использовать ее в качестве источника случайных чисел.
В вашей реализации вы объединяете строковые представления x и
y
. Это плохо, поскольку это не уникально для всего домена. Например,Удачи!
источник
Давайте посмотрим, что вы делаете точно:
Все это звучит хорошо, но вы получаете образец, потому что:
Пиксель в 1,11 и пиксель в 11,1 засевают номер 111, поэтому они наверняка имеют одинаковый цвет.
Кроме того, если вы всегда выполняете циклы одинаково, вы можете использовать только один генератор, не нужно использовать один для каждого пикселя. Один на весь образ подойдет! Из-за псевдослучайности все еще будут какие-то паттерны. @David_Lively прав в использовании некоторого алгоритма Шума, он сделает его более случайным.
источник
Сделайте генератор цветов, а затем произведите ваши цвета для вашей плитки. Семя только один раз! Вам не нужно высевать больше, по крайней мере, за плитку.
И использование будет как следовать:
С этим, если вы не довольны результатом, просто поменяйте
Random
семена. Кроме того, вам нужно только хранить / передавать семена и размеры, чтобы у всех клиентов было одинаковое изображение.источник
Вместо использования Random, рассмотрите возможность использования хеш-дайджеста, такого как MD5. Это обеспечивает трудно прогнозируемое «случайное» значение на основе определенного ввода, но всегда одинаковое значение для одного и того же ввода.
Пример:
ПРИМЕЧАНИЕ: я не знаю, откуда берется Color.rgb888 (..), поэтому я не знаю, каков допустимый диапазон. 0-255 нормально, хотя.
Улучшения для рассмотрения:
источник
Другие отмечают, что один из способов получить желаемое поведение - использовать хеш-функцию, известную как «функция дайджеста сообщения». Проблема в том, что они часто основаны на таких алгоритмах, как MD5, которые криптографически безопасны (то есть действительно, действительно, действительно случайны), но очень медленны. Если вы используете криптографическую хэш-функцию каждый раз, когда вам нужен случайный пиксель, вы столкнетесь с довольно серьезными проблемами производительности.
Тем не менее, существуют некриптографические хеш-функции, которые могут выдавать значения, которые являются достаточно случайными для вашей цели, а также быстрыми. То, к чему я обычно обращаюсь, - это бормотание . Я не пользователь Java, но, кажется, есть хотя бы одна доступная реализация Java . Если вы обнаружите, что вам действительно нужно, чтобы каждый пиксель генерировался из его координат, а не генерировал их все сразу и сохранял их в текстуре, то это был бы хороший способ сделать это.
источник
Я бы использовал простое число более 2000 (максимальное типичное разрешение).
Это позволит минимизировать (или устранить дублирующиеся семена)
источник
Random
достаточно случайно Вы используете это неправильно по двум основным причинам.Integer.valueOf(Integer.toString(x)+Integer.toString(y))
между пикселями, которые вы засеваете.Я бы просто использовал несколько вариантов следующего кода, где вы можете выбрать хеш-функцию (не используйте Integer.getHashCode) из ответов на /programming/9624963/java-simplest-integer- гашиш
где хэш-функция может быть
источник
Вы можете попробовать использовать текущее время системы в качестве начального числа:
Надеюсь, это даст более случайное значение.
источник
Вот одна строковая статическая функция, которую я придумал - poltergeist (Noisy Ghost).
Он принимает двухмерную координату и начальное число и отображает монотонно по запросу. Он работает в режиме реального времени, независимо от разрешения экрана. Это то, для чего нужны графические процессоры.
Любое разрешение, любая текстура, на любом устройстве (в том числе и на мобильном), поддерживающем GL (что практически одинаково с экраном).
Посмотри, как это работает, прямо сейчас!
https://www.shadertoy.com/view/ltB3zD
Вы можете легко включить этот шейдер в свою Java-программу, используя стандартный opengl, или в любом браузере, использующем стандартный webgl.
Ради интереса я бросаю вызов любому, кто превзойдет Poltergeist по качеству и производительности на всех устройствах. Шумный призрак правил! Непобедимый!
источник