Blender é um software de modelagem 3D de código aberto, capaz de gerar animações e também funciona como Game Engine (infraestrutura especializada para criação de jogos para computador). Além disso, o software possui um renderizador interno e pode ser integrado a renderizadores externos, como os projetos, também de código aberto, Yafaray e LuxRender.
No Blender, uma cena é composta por objetos, que precisam ser fixados em posições e conectados a cena. Se o objeto não estiver conectado a cena, ele será eliminado ao fim do processamento. Para cada sólido, é possível configurar vários materiais, que podem ter zero ou mais texturas.
A cena padrão do Blender é composta por três objetos: uma câmera, uma lâmpada e um cubo (representado como mesh). A escala no Blender é medida em BUs (Blender Units).
Com Python é possível acessar todas essas estruturas do Blender através de módulos, incluindo:
A API do Blender oferece várias texturas procedurais e uma coleção de sólidos primitivos prontos, que podem ser criados e alterados através de código.
Exemplo de código para a criação de uma cena:
import math
import Blender
# Pega a cena atual
cena = Blender.Scene.GetCurrent()
# Elementos da cena "default"
camera = Blender.Object.Get()[0]
cubo = Blender.Object.Get()[1]
lamp = Blender.Object.Get()[2]
# Move a câmera
camera.setLocation(8., -8., 4.)
camera.setEuler(math.radians(70), 0.,
math.radians(45))
# Muda a lente
camera.data.lens = 30
# Remove da cena o objeto "default"
cena.objects.unlink(cubo)
# Altera a intensidade da luz
lamp.data.energy = 1.2
# Muda o tipo para "Sun"
lamp.data.type = 1
# Aumenta o número de samples
lamp.data.raySamplesX = 16
lamp.data.raySamplesY = 16
# E a cor
lamp.data.col = 1., .9, .8
# Cria outra fonte de luz
lamp1 = Blender.Lamp.New('Lamp')
lamp1.energy = 0.5
lamp1.col = .9, 1., 1.
_lamp1 = Blender.Object.New('Lamp')
# Muda o lugar da fonte (default = 0.0, 0.0, 0.0)
_lamp1.setLocation(6., -6., 6.)
# "Prende" a fonte de luz na cena
_lamp1.link(lamp1)
cena.objects.link(_lamp1)
# Cria um material
material1 = Blender.Material.New('newMat1')
material1.rgbCol = [.38, .33, .28]
material1.setAlpha(1.)
# Cria uma textura
textura1 = Blender.Texture.Get()[0]
textura1.setType('Clouds')
textura1.noiseType = 'soft'
textura1.noiseBasis = Blender.Texture.Noise['VORONOICRACKLE']
# Coloca no material
material1.setTexture(0, textura1)
mtex1 = material1.getTextures()[0]
mtex1.col = .26, .22, .18
mtex1.mtNor = 1
mtex1.neg = True
mtex1.texco = Blender.Texture.TexCo['GLOB']
material1.mode += Blender.Material.Modes['RAYMIRROR']
material1.rayMirr = 0.2
material1.glossMir = 0.8
# Cria o piso
mesh = Blender.Mesh.Primitives.Plane(40.)
piso = cena.objects.new(mesh,'Mesh')
piso.setLocation(0., 0., .05)
# Rotaciona o piso
piso.setEuler(0., 0., math.radians(45))
# Coloca o material no piso
piso.setMaterials([material1])
piso.colbits = 1
# Cria outro material
material2 = Blender.Material.New('newMat2')
material2.rgbCol = [.77, .78, .79]
material2.setAlpha(1.)
material2.mode += Blender.Material.Modes['RAYMIRROR']
material2.rayMirr = 0.6
material2.glossMir = 0.4
# Coloca textura no outro material
material2.setTexture(0, textura1)
mtex2 = material2.getTextures()[0]
mtex2.col = .3, .3, .4
mtex2.mtNor = 1
mtex2.neg = True
mtex2.texco = Blender.Texture.TexCo['GLOB']
mat = [material2]
# Cria objetos na cena
def objeto(local, tam, mat, prim=Blender.Mesh.Primitives.Cube):
mesh = prim()
obj = cena.objects.new(mesh, 'Mesh')
obj.setLocation(*local)
obj.size = tam
obj.setMaterials(mat)
obj.colbits = 1
return obj
def coluna(x=0., y=0., z=0., mat=mat):
# Cilindro
prim = Blender.Mesh.Primitives.Cylinder
# Topo
local = x, y, 2.5 + z
tam = .25, .25, .1
objeto(local, tam, mat)
# Base
local = x, y, 0. + z
objeto(local, tam, mat)
# Corpo
for k in xrange(10):
local = x, y, .25 * k + z
tam = .2 - k / 200., .2 - k / 200., .25
objeto(local, tam, mat, prim)
# Cria colunas no fundo
for i in xrange(16):
# Primeira fileira
coluna(i - 8., 8)
# Segunda fileira
coluna(-8., i - 8.)
# Aqueduto
local = -8., i - 8., 3.
tam = .5, .5, .5
objeto(local, tam, mat)
local = i - 8., 8., 3.
objeto(local, tam, mat)
z = .25
# Cria colunas em cima do piso
for i in (-3, 3):
for j in range(-2, 3):
# Fileiras X
coluna(i, j, z)
# Fileiras Y
coluna(j, i, z)
# Cantos
for j in (-3, 3):
coluna(i, j, z)
# Cria escada
for i in xrange(8):
local = 0., 0., i / 32. - .25
tam = 3.3 + (8. - i) / 8., 3.3 + (8. - i) / 8., .25
objeto(local, tam, mat)
# Cria teto
for i in xrange(35):
local = 0., 0., 2.9 + i / 60.
tam = 3.5 - i / 200., 3.5 * ( 1. - i / 35.), .1
objeto(local, tam, mat)
# Pega o "mundo"
world = Blender.World.Get()[0]
# Modo "blend" no fundo
world.skytype = 1
# Atualiza a cena
cena.update()
Saída renderizada:
Exemplo com interface:
from math import *
from Blender.Draw import *
from Blender import BGL, Window, Mesh, Scene
class Buttons:
"""
Classe com para armazenar os botões para que
os valores possam ser usados por outras rotinas
sem usar variáveis globais
"""
# Equação
formula = Create('cos(x) - sin(3*x)')
# Variação
delta = Create(.1)
def interface():
"""
Função que desenha a interface
"""
# Pega o tamanho da janela
x, y = Window.GetAreaSize()
# Desenha caixa de texto
# Parâmetros: rótulo, evento, x, y, largura, altura, valor inicial,
# tamanho máximo do texto, tooltip
Buttons.formula = String('Fórmula: ', 0, 10, y - 30, 300, 20,
Buttons.formula.val, 300, 'Entre com uma expressão Python')
# Desenha caixa de número
# Parâmetros: rótulo, evento, x, y, largura, altura, valor inicial,
# mínimo, máximo, tooltip
Buttons.delta = Number('Delta: ', 0, 10, y - 60, 300, 20,
Buttons.delta.val, .01, 1., 'Entre com a variação')
# Desenha os botões
# Parâmetros: texto do botão, evento, x, y, largura, altura, tooltip
PushButton('Ok', 1, 10, y - 90, 100, 20, 'Aplica as mudanças')
PushButton('Fim', 2, 10, y - 120, 100, 20, 'Termina o programa')
# Comandos OpenGL através da BGL
BGL.glClearColor(.7, .7, .6, 1)
BGL.glClear(BGL.GL_COLOR_BUFFER_BIT)
def events(evt, val):
"""
Função que responde a eventos diversos,
menos os gerados por botões
"""
# Os eventos das teclas estão definidas em Draw
if evt == ESCKEY:
# Termina o programa
Exit()
def buttons(evt):
"""
Função que responde a eventos dos botões
"""
if evt == 2:
Exit()
elif evt == 1:
gen3d()
def gen3d():
# Cena 3D
cena = Scene.GetCurrent()
x = y = z = 0
while x < 2 * pi:
# Calcula os valores de z
z = eval(Buttons.formula.val)
# Cria uma esfera de 16 segmentos, 16 anéis e 0.1 BU de raio
s = Mesh.Primitives.UVsphere(16, 16, .1)
esfera = cena.objects.new(s, 'Mesh')
# Transfere a esfera para o local calculado
esfera.setLocation(x, y, z)
# Próximo x
x += Buttons.delta.val
# Atualiza a cena
cena.update()
if __name__ == '__main__':
# Registra as funções callback
Register(interface, events, buttons)
Interface:
Saída:
Exemplo de criação de malha:
from Blender import NMesh, Redraw
# Cria uma nova malha
mesh = NMesh.New()
# Um dicionário para armazenar os vértices
# conforme a posição
vertices = {}
for X in xrange(3):
for Y in range(3):
# Uma face é determinada pelos vértices que fazem parte dela
face = []
coords = [(X + 0, Y + 0), (X + 0, Y + 1),
(X + 1, Y+ 1), (X + 1, Y + 0)]
# Vértices da face
for x, y in coords:
vertices[(x, y)] = vertices.get((x, y), NMesh.Vert(x, y, 0))
face.append(vertices[(x, y)])
# Adiciona um objeto "face" na lista de faces da malha
mesh.faces.append(NMesh.Face(face))
# Adiciona os vértices na malha
for vertice in vertices.values():
mesh.verts.append(vertice)
# Carrega a malha na cena
NMesh.PutRaw(mesh, 'chess', True)
Redraw()
Saída:
Para executar código em Python no ambiente do Blender, basta carregar o programa na janela de editor de texto do Blender e usar a opção de execução no menu.
Game engine é um software que facilita a criação de jogos, simulando determinados aspectos da realidade, de forma a possibilitar a interação com objetos em tempo real. Para isso, ele deve implementar várias funcionalidades que são comuns em jogos, como por exemplo a capacidade de simulação física. O objetivo principal do uso de game engines é centrar o foco da criação do jogo no conteúdo, ou seja, mapas (níveis), personagens, objetos, diálogos, trilha sonora e cenas. É comum que vários jogos usem o mesmo engine, reduzindo assim, o esforço de desenvolvimento.
Um dos principais recursos fornecidos por game engines é a capacidade de renderizar cenas em 2D ou 3D em tempo real, geralmente usando uma biblioteca gráfica, como o OpenGL, permitindo animações e efeitos especiais. O componente especializado para esta função é conhecido como render engine.
Além disso, a simulação física também é essencial para um jogo, para representar de forma adequada os movimentos dos personagens sendo influenciados pela gravidade, inércia, atrito, detecção de colisões e outros. O componente que realiza esses cálculos é chamado Physics Engine.
Outra funcionalidade importante é a lógica, que é como o jogo determina o comportamento do ambiente e dos personagens. Em muitos casos, o game engine suporta uma ou mais linguagens para descrevê-la.
Os game engines podem incluir outros recursos importantes para determinados tipos de jogos, como conectividade. No caso de MMOG (Massively Multiplayer Online Games), que são muito complexos, a infraestrutura de software é mais conhecida como middleware.
A popularização dos game engines aconteceu durante a década de 90, graças a Id Software, que desenvolveu os jogos que definiram o gênero chamado FPS (First Person Shooter), jogos de ação em primeira pessoa. Esses títulos tiveram seus engines licenciados para outras empresas, que criaram outros jogos desenvolvendo o conteúdo do jogo. Em paralelo, os processadores de vídeo foram incorporando suporte as funções gráficas cada vez mais sofisticadas, o que facilitou a evolução dos engines. A Id também liberou os game engines das séries DOOM e Quake em GPL.
Além de entretenimento, outras áreas podem se beneficiar desses engines. Chamadas genericamente de serious games, aplicações nas áreas de treinamento, arquitetura, engenharia, medicina e marketing estão se popularizando aos poucos.
O Blender inclui um game engine genérico, que permite a criação de jogos 3D, usando o próprio aplicativo para criação de conteúdo e Python para as partes com lógica mais complexa.
O Blender Game Engine (BGE) usa como physics engine o projeto, também Open Source, chamado Bullet. Com ele, é possível simular o comportamento de corpos rígidos (como peças de maquinaria), macios (como tecidos), estáticos (fixos) e intangíveis (que não são afetados por colisões).
O render engine do Blender suporta GLSL (OpenGL Shading Language), o que permite que ele utilize recursos avançados disponíveis nos processadores de vídeo mais recentes.
Já a lógica é definida no BGE através de Logic Bricks, que segue um modelo baseado em eventos. Eventos são associados a um objeto da cena e podem ser gerados por periféricos de entrada (como teclado e mouse), pelo sistema (tempo), pelo próprio BGE (colisões, por exemplo) ou por mensagens enviadas por outros objetos. Quando um ou mais eventos são detectados, o BGE toma uma decisão e reage de acordo.
Existem três tipos de bricks:
No painel Logic, as associações entre os bricks pode ser definida de forma interativa. O BGE tem diversos ativadores prontos, para realizar tarefas como encerrar a execução ou mudar a velocidade do objeto.
O BGE pode evocar código em Python para responder aos eventos, através do controlador “Python”. Quando uma função em Python é executada, ela recebe como argumento o controlador que realizou a chamada, com isso é possível identificar e modificar o objeto (owner) que possui o controlador.
Exemplo (módulo com função para teleporte):
# Módulo de interface com o Game Engine
import GameLogic
def teleport(cont):
# obtêm o dono do controller
own = cont.owner
# obtêm a cena
scene = GameLogic.getCurrentScene()
# obtêm o destino
dest = scene.getObjectList()['OBr_portal']
# obtêm as coordenadas do destino
x, y, z = dest.getPosition()
# move a câmera para 1 BU acima do destino
own.setPosition([x, y, z + 1])
Essa função muda a posição do objeto, para um BU a cima do objeto chamado “r_portal”, independente do lugar na cena em que estiver localizado.