Como alternativa, você pode usar um mapa de cubo com uma textura do céu em vez de usar ruído perlin. E também acho que isso fará com que sua cena pareça melhor devido a mais detalhes e variações no mapeamento do ambiente. Foi exatamente o que fiz quando implementei meu raytracer.
Outro motivo pelo qual recomendo isso é que o ambiente não precisa ser apenas nuvens. Pode ter montanhas, pode ser uma cena interna, pode ser uma cena de Marte. Usando um mapa de cubo, a única coisa que você precisa fazer é trocar a textura e pronto.
Portanto, o primeiro passo será encontrar um mapa de cubo que atenda às suas necessidades. Ele pode ser armazenado como seis texturas separadas ou como uma única textura como a abaixo. Verifique também este link para obter mais informações sobre como criar seu próprio:
Em seguida, no seu código, recomendo criar uma CubeMap
classe para encapsular os cálculos de amostragem. Essa classe deve saber como carregar a textura do mapa do cubo e, com um raio , deve saber em qual face e em qual posição a amostra. Na minha implementação, achei mais fácil armazenar cada uma das seis faces em objetos de textura separados e ramificar com base na direção do raio:
class CubeMap
{
public void Load(string path);
public Color GetSample(Ray ray);
private Texture[6] faces;
}
Caso você ainda não tenha uma Texture
aula, crie sua própria. Pode ser tão simples quanto uma matriz bidimensional de cores. Portanto, apenas como referência, e sem garantia da eficiência ou solidez dessa implementação, eis o código que usei no meu projeto - CubeMap e CubeFace .