Atualmente, estou trabalhando em um programa que deve gerar ruído aleatório em uma tela com base nas 'coordenadas' de um pixel. As coordenadas devem ter a mesma cor sempre que você reiniciar o programa. No entanto, usando o util.Random do Java, os resultados obtidos não são tão aleatórios quanto eu gostaria:
Eu pensei que se eu usasse as coordenadas combinadas (como em um número inteiro formado pelas duas coordenadas próximas umas das outras), cada coordenada teria um número diferente. Usando esse número como uma semente, eu esperava obter números aleatórios diferentes para cada coordenada para usar no valor rgb dessa coordenada.
Este é o código que eu usei:
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;
}
}
O padrão criado pelo programa é devido ao modo como a função Aleatória do java funciona ou estou fazendo algo errado e devo tentar uma abordagem diferente?
Atualização: Agora, tentei me livrar dos problemas relacionados à concatenação usando o seguinte código:
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;
}
De alguma forma, isso também forneceu uma (na minha opinião) imagem suficientemente aleatória:
Esse código, no entanto, é processado novamente três vezes por pixel. Mesmo que isso não seja um problema para mim no momento, considero alterar esse código caso precise de uma melhor performance posteriormente.
Respostas:
A
java.util.Random
classe de Java geralmente fornece sequências de números pseudo-aleatórios que são bons o suficiente para uso em jogos 1 . No entanto, essa característica se aplica apenas a uma sequência de várias amostras com base em uma semente. Quando você reinicializa o RNG com o aumento dos valores de sementes e olha apenas para o primeiro valor de cada sequência, as características de aleatoriedade não serão tão boas.O que você poderia fazer:
Em vez de usar um gerador de números aleatórios, use uma função de resumo da mensagem para transformar um par de coordenadas em um valor de cor. A saída da maioria dos MDFs é imprevisível o suficiente para realizar a maioria dos testes de aleatoriedade. A saída geralmente é superior aos 24 bits necessários para um valor RGB, mas truncá-los normalmente não é problema.
Para melhorar o desempenho, você pode combinar a geração de resumo de mensagens com pedaços. Gere pequenos pedaços de pixels, que são grandes o suficiente para usar todo o comprimento de uma saída da sua função Digest.
1 quando for absolutamente essencial que ninguém possa prever o próximo número, use o mais lento, mas menos previsível
java.security.SecureRandom
fonte
Nesse caso, você desejará usar uma função de ruído determinístico, como o ruído Perlin ou simplex .
( Veja esta pergunta para obter mais informações sobre o ruído Perlin com algumas fotos bonitas. )
Na maioria das vezes, o uso de uma
random()
função interna ou similar fornecerá valores diferentes toda vez que o programa for executado, pois eles podem usar o relógio como entrada ou algum outro valor pseudo-aleatório.Outra opção é gerar um "mapa de ruído" uma vez, offline, e depois usá-lo como sua fonte de números aleatórios mais tarde.
Na sua implementação, você está concatenando as representações de string de xe
y
. Isso é ruim, pois não é exclusivo em todo o domínio. Por exemplo,Boa sorte!
fonte
Vamos ver o que você está fazendo exatamente:
Tudo isso soa bem, mas você está recebendo um padrão porque:
Pixel em 1,11 e pixel em 11,1 são semeados no número 111, portanto eles certamente terão a mesma cor.
Além disso, desde que você sempre ande da mesma maneira, poderá usar apenas um gerador, sem precisar usar um para cada pixel. Um para toda a imagem serve! Ainda haverá algum tipo de padrão por causa da pseudo-aleatoriedade. O @David_Lively está certo sobre o uso de algum algoritmo Noise, que fará com que pareça mais aleatório.
fonte
Faça um gerador de cores e depois produza suas cores para o seu azulejo. Semente apenas uma vez! Você não precisa propagar mais do que isso, pelo menos por peça.
E o uso será como segue:
Com isso, se você não estiver satisfeito com o resultado, mude a
Random
semente. Além disso, você só precisa armazenar / comunicar a semente e os tamanhos para que todos os clientes tenham a mesma imagem.fonte
Em vez de usar o Random, considere usar um resumo de hash como MD5. Ele fornece um valor 'aleatório' difícil de prever com base em uma determinada entrada, mas sempre o mesmo valor para a mesma entrada.
Exemplo:
NOTA: Não sei de onde vem Color.rgb888 (..); portanto, não sei qual é o intervalo permitido. 0-255 é normal embora.
Melhorias a considerar:
fonte
Outros apontaram que uma maneira de obter o comportamento desejado é usar uma função hash, também conhecida como "função de resumo da mensagem". O problema é que eles geralmente são baseados em algoritmos como o MD5, que é criptograficamente seguro (ou seja, muito, muito, muito aleatório), mas muito lento. Se você usar uma função de hash criptográfico toda vez que precisar de um pixel aleatório, terá problemas de desempenho bastante graves.
No entanto, existem funções de hash não criptográficas que podem produzir valores aleatórios o suficiente para o seu objetivo, além de rápidos. O que eu geralmente busco é murmurar . Eu não sou um usuário Java, mas parece que há pelo menos uma implementação Java disponível. Se você achar que realmente precisa que cada pixel seja gerado a partir de suas coordenadas, em vez de gerá-los todos de uma vez e armazená-los em uma textura, essa seria uma boa maneira de fazê-lo.
fonte
Eu usaria um primo acima de 2000 (resolução típica máxima)
Isso minimizará (ou eliminará sementes duplicadas)
fonte
Random
é aleatório o suficiente. Você está usando errado por dois motivos principais.Integer.valueOf(Integer.toString(x)+Integer.toString(y))
entre os pixels que você está propagando.Eu usaria apenas algumas variações do código a seguir, onde você pode escolher uma função de hash (não use Integer.getHashCode) nas respostas em /programming/9624963/java-simplest-integer- cerquilha
onde a função hash poderia ser
fonte
Você pode tentar usar a hora atual do relógio do sistema como uma semente como esta:
Espero que produza um valor mais aleatório.
fonte
Aqui está uma função de sombreador estático de uma linha que eu criei - poltergeist (Noisy Ghost).
É necessária uma coordenada 2D e uma semente e é renderizada em monotonia, conforme solicitado. É executado em fps em tempo real, independentemente da resolução da tela. É para isso que servem as GPUs.
Qualquer resolução, qualquer textura, em qualquer dispositivo (móvel também) que suporte GL (que é praticamente qualquer tela).
Veja-o funcionando aqui, agora!
https://www.shadertoy.com/view/ltB3zD
Você pode incluir facilmente esse shader no seu programa java usando o opengl padrão ou em qualquer navegador usando o webgl padrão.
Apenas por diversão, eu jogo a luva para qualquer um vencer o Poltergeist em qualidade e desempenho em todos os dispositivos. Regras barulhentas do fantasma! Invicto!
fonte