Raycife: Agora com sombras

Apesar de ter aumentado consideravelmente a granularidade (tá parecendo coisa de z-buffer ou algo do tipo), corrigi um bug besta pelo qual as sombras não estavam aparecendo: O raio de luz estava com a direção invertida (luz – ponto_de_verificação, e não ponto_de_verificação – luz)…

Abaixo, o resultado: 100×100 pixels e 100 raios/pixel (26 minutos, mas usando o computador enquanto processava):

Próximos passos: resolver essa bronca de granularidade e adicionar reflexão especular.

Status do projeto: raycife+

First full window of raycife

Esse é o estado atual, apenas com iluminação ambiente e a componente difusa (e um belo bug de ordenação). A imagem de referência pode ser encontrada no fim dessa página.

Dados: Janela 200×200 com 20 raios por pixel.

Tempo de processamento num Celeron 440 com 1 GB de RAM: +-15 minutos (muito lento…)

Profiling python com cprofile

Durante o desenvolvimento do raycife+, a performance estava ficando impraticável, chegando a cerca de 3 a 4 minutos para uma cena simples de 100×100 pixels e 7 objetos no meu velho celeron. Seguindo as dicas desse site, rodei o cprofile e pude ver onde poderia ganhar tempo.

No arquivo principal do programa esse código que executa a função main com os argumentos fornecidos na string e salva o resultado num arquivo de log.

if __name__ == '__main__':
    import cProfile
    cProfile.run('main(["raycifeplus.py", "./samples/cornellroomsmall.sdl"])' filename='raycife.cprof')

Para ler o resultado do arquivo de saída:

from pstats import Stats
stats = Stats("raycife.cprof")
stats.sort_stats('time').print_stats()

Exemplo da saída:

Mon Apr 21 11:23:35 2008    raycife.cprof

37298787 function calls in 237.746 CPU seconds

Ordered by: internal time

ncalls  tottime  percall  cumtime  percall filename:lineno(function)
1  168.955  168.955  237.734  237.734 ./raycifeplus.py:71(render)
26660558   46.400    0.000   46.409    0.000 /home/lauro/dev/raytracer/raycifeplus/gameobjects/vector3.py:165(__iter__)
5723042    9.791    0.000    9.807    0.000 /home/lauro/dev/raytracer/raycifeplus/gameobjects/vector3.py:265(__sub__)
2422914    4.633    0.000    4.636    0.000 /home/lauro/dev/raytracer/raycifeplus/gameobjects/vector3.py:369(__rmul__)
2422914    4.114    0.000    4.125    0.000 /home/lauro/dev/raytracer/raycifeplus/gameobjects/vector3.py:224(__add__)
10000    2.927    0.000    4.841    0.000 ./raycifeplus.py:80(render_pixel)
1472    0.478    0.000    0.916    0.001 ./raycifeplus.py:99(trace_point)
841    0.129    0.000    0.299    0.000 /home/lauro/dev/raytracer/raycifeplus/objfile.py:30(intersect)
1    0.119    0.119    0.182    0.182 /home/lauro/dev/raytracer/raycifeplus/pnm.py:18(write)
10000    0.044    0.000    0.044    0.000 /home/lauro/dev/raytracer/raycifeplus/pnm.py:15(set_pixel)

Nesse caso, deu para ver que parte do tempo era perdido no módulo vector3, uma implementação de vetores em 3 dimensões usando python.

No próximo vou falar sobre uma tentativa rápida de implementar a mesma funcionalidade usando C++ e criando o binding usando o SIP.

Nota: O código acima ainda poderia ser refinado para receber argumentos na linha de comando mas como é apenas um teste rápido, pode ficar p/ depois uma flag “-p” para habilitar o profiling.

Nota2: Sim, eu sei que a otimização prematura é a raíz de todo mal mas nesse caso é um teste pontual que não vai mudar o algoritmo, além de poder conhecer novas tecnologias 🙂

A distribuição Linux perfeita!

Linux evolution comic

Traduzindo:

– Eu tenho 32 configurações do Linux rodando virtualizadas. E também tenho um algoritmo genético realizando seleção e mutação para produzir…

– A distribuição Linux definitiva!!!

– <pinguim de boné> Já existe, se chama Ubuntu.

– Eu não acredito em criacionismo…

Fonte: zoitz

‘Use’ o Google no seu site (com Python!)

Pelo menos é o que dá a entender o conceito do AppEngine.

Você desenvolve usando Python (Vem com django instalado, apesar de algumas mudanças \o/ ), manda o código e lá é hospedado e servido pela infra estrutura do Google. O pacote gratuito dá direito a 500MB de espaço e cpu/tráfego para +- 5 milhões de page views. Há suporte para acesso aos serviços de dados (Datastore/BigTable) e contas (Google Accounts).

Virtualizando as janelas

O Centro de Informática da UFPE faz parte do MSDN Academic Alliance e como resultado temos acesso a alguns softwares da MS. Semana passada baixei a imagem do Windows XP e estava (ainda estou) com preguiça de fazer backup -> instalar windows -> instalar ubuntu -> instalar programas, portanto parti p/ virtualização.

Como primeira opção, já que estava instalado, tentei o QEMU. Muito lento, mesmo com o kqemu instalado. Começava a copiar uns arquivos e parava. Quando estava com o controle do mouse e teclado (grab), o computador ficava completamente sem responder (Tinha que matar o processo via ssh).

Então a solução seguinte foi o VMWare Player, apesar da bronca de criar uma nova imagem p/ ele. No QEMU basta uma imagem simples de HD ou CD mas o VMWare tem um formato próprio com uns arquivos extras.

Para isso, usei um script de Marcelo ‘setanta’ Lira, que ele usa no INdT p/ criar o Maemo SDK VMWare Appliance. Bastou modificar algumas variáveis dentro dele, como a imagem a ser usada (ele usa a do Xubuntu) e o caminho padrão com os dados.

Resultado: Nesse exato momento, rodando o XP redondo, mas claro que não como um desktop decidado mas para o que preciso é suficiente. Ah, e com suporte a parar/reiniciar a qualquer momento 😀

Manipulando imagens com PIL – básico

Bem, com uma lista já enviada agora tenho um pouco mais de tempo, embora ainda faltem mais duas: uma (escrita, já atrasada) e outra dentro de 2 semanas. 🙂

Segue abaixo uma visão básica do que precisei usar da PIL nesses trabalhos (basicamente abrir, pegar pixels, colocar pixels, salvar)

Abrindo uma imagem

img = Image.open(filename)

Nesse trabalho eu tive que usar apenas imagens monocromáticas no modo ‘L’ ao invés de RGB (ou seja, 1 valor por pixel ao invés de 3), e para ‘forçar’ isso, o comando poderia ter sido o seguinte:

img = Image.open(filename).convert(‘L’)

Pegando os dados

Como eu estava usando imagens pequenas, de 512×512, o método que usei foi o ‘getdata()’ no objeto imagem criado anteriormente que retorna um objeto com suporte a iteração com os dados dos pixels.

Escrevendo os dados

Para escrever, basta usar o ‘putdata’ que escreve no objeto a partir da posição 0 (ele enxerga a imagem como um vetor unidimensional no caso do [get|put]data, sendo linha após linha sequencialmente). Opcionalmente argumentos scale; que multiplica todos os pixels; e offset; a partir de onde começa a copiar; podem ser usados.

pixel = value*scale + offset

Salvando

Assumindo que você tem um objeto imagem e que salvá-lo, ele possui um método save (D’oh!) que recebe como argumento o nome do arquivo de saída.

img.save(‘foobar.png’)

Conclusão

Bem, esse foi praticamente um ‘hello, world!’ do PIL, mostrando que pelo menos para essa manipulação básica de imagens é uma biblioteca bem simples e direta de usar. Para mais informações: API do módulo Image.

Nos próximos posts, numpy, filtros, etc…