From BlenderWiki

Jump to: navigation, search
Blender3D FreeTip.gif
IMPORTANT! Do not update this page!
We have moved the Blender User Manual to a new location. Please do not update this page, as it will be locked soon.

Escrevendo um Plugin para Texturas

Nesta seção nós iremos escrever um Plugin de Textura básico e então navegar através dos passos para a utilização de um Plugin de Textura.

O conhecimento básico necessário sobre os Plugins de Textura é que você tem que dar a ele algumas entradas; posição, e valores de normal tanto quanto algumas outras informação. Então você tem como retorno, valores de informação de "intensity, colour and/or normal" (intensidade, cores e/ou normal), dependendo do tipo de Plugin de Textura.

Manter a informação de partes do Manual ”No estado”
Como esta parte do Manual explica procedimentos avançados do Blender através de configuração e programação Interna, decidi manter os Códigos em C sem tradução parcial ou completa, incluindo os seus comentários. É desejável que o leitor que se aventure na área de programação possua um mínimo de conhecimento do Inglês para que possa se guiar através de manuais de programação, e para que possa compreender os comandos de maneira adequada
→ Ivan Paulos Tomé - Greylica


Todos os arquivos necessários para desenvolver Plugins tanto quanto alguns Plugins de exemplo podem ser encontrados dentro do diretório blender/plugins de sua instalação do Blender. Você pode alternativamente baixar um monte de Plugins disponíveis a partir deste repositório de Plugins. Os Plugins são suportados pelo Blender (chamados ou carregados) utilizando a família de chamadas dlopen(). Para os que não estão familiarizados com este sistema, ele permite que um programa ( Blender ) utilize um Objeto compilado como se fosse parte do programa em si, e seu funcionamento é similar ao de DLLs ou "Dynamically Linked Libraries" (Bibliotecas de Vínculo Dinâmico),com a exceção de que os Objetos a serem carregados são determinados durante o "runtime" (tempo de execução).

A vantagem da utilização do sistema de chamadas dlopen para Plugins é que ele é muito rápido para acessar uma função, e não há "overhead" (taxação/perda de desempenho) em fazer a Interface com o Plugin, o que é crítico quando (no caso de Plugins de Textura) a rotina do Plugin pode ser chamada por milhares de vezes em um único render. A desvantagem do Sistema é que o código do Plugin funciona como se fosse parte do Blender em si, caso o Plugin trave, o Blender irá travar também.

Os arquivos tipo include encontrados dentro do subdiretório da instalação do Blender plugin/include/ documentam a funcionalidade provida para os Plugins. Isso inclui as funções da biblioteca Imbuf para o carregamento e trabalho com Imagens e Buffers de Imagens, e funções de "noise" (ruído) e "turbulence" (turbulência) para uma texturização consistente.

Especificação

#include <plugin.h>
Todos os Plugins do Blender devem incluir este arquivo de cabeçalho, que contém todas as estruturas e definições necessárias para que o Plugin funcione adequadamente com o Blender .
char name[]="Tiles";
Uma "string" (variável de amarração) contendo o nome do Plugin, este valor será mostrado para o título da Textura dento da Buttons Window, no sub-contexto Texture .
#define NR_TYPES 2; char stnames[NR_TYPES][16]= {"Square", "Deformed"};
Os Plugins possuem permissão para ter sub-tipos separados para variações menores em algoritmos – por exemplo, a textura padrão tipo "clouds" (nuvens) dentro do Blender possui os subtipos "“Default”" (”Padrão”) e "“Color”" (”Cor”). NR_TYPES deverá ser definido para o número de sub-tipos requerido para o Plugin, e um nome para cada sub-tipo deverá ser fornecido (stnames[NR_TYPES]). Cada Plugin deverá ter pelo menos 1 sub-tipo e um nome para o sub-tipo.
VarStruct varstr[]= {...};
A estrutura varstr contém toda a informação da qual o Blender necessita para mostrar botões para um Plugin. Os Botões para Plugins podem ser numéricos para a entradad de dados, ou de textos para comentários e outras informações. Os Plugins são limitados para um máximo de 32 variáveis. Cada entrada VarStruct consiste de um tipo, nome, informação de campo de atuação, e uma "tooltip" (dica de ferramenta).
O "”type”" (”tipo”) define o tipo de dados para cada entrada de botão, e a maneira que esse botão será mostrado. Para botões numéricos, este valor deverá ser uma combinação ( através dos binários OR, “|”) de “INT” ou “FLO” para o formato numérico (inteiro ou flutuante), e “NUM”, “NUMSLI”, ou “TOG”, para o tipo de botão (numérico, numérico com deslizador, ou de alternância). Botões de Texto deverão ter um tipo de código para definir seu rótulo, através de “LABEL”.
O "“name”" (”nome”) é o que será mostrado no botão (ou ao lado dele). Isto é limitado a 15 caracteres.
A informação de "“range”" (”campo de atuação”) consiste de três variáveis de ponto flutuante que definem os valores de "default, minimum, and maximum" (padrão, mínimo e máximo) para o botão. Para os botões de alternância utilizando o código TOG, o mínimo é configurado para o seu estado pressionado, e o máximo é configurado dentro de seu estado não pressionado.
A "”tooltip”" (”dica de ferramenta”) é uma "string" (variável de amarração) que será mostrada quando o Mouse estiver sobre este botão (caso o usuário possua a opção "Tool Tips" (Dicas de Ferramenta) habilitada). Isto possui um limite de 80 caracteres, e deverá ser configurado para a "string" (variável de amarração) NULL ("") caso não seja utilizado.
typedef struct Cast {...};
A estrutura de Código Cast é utilizada durante a chamada da função doit, e serve como uma maneira de simplificar o acesso para os dados de valores de cada Plugin. A estrutura Cast deverá conter, em ordem, um valor "integer" (inteiro) ou de "float" (ponto flutuante) para cada botão definido dentro de varstr, incluindo botões de texto. Tipicamente, estes deverão possuir o mesmo nome que o botão para simples referência.
float result[8];
A matriz de códigos resultante (array) é utilizada para passar informação de/para e para receber informação a partir do Plugin. Os valores resultantes são mapeados da seguinte maneira:
 result Index  Significance  Range 
 result[0]  Intensity value  0.0 to 1.0 
 result[1]  Red color value  0.0 to 1.0 
 result[2]  Green color value  0.0 to 1.0 
 result[3]  Blue color value  0.0 to 1.0 
 result[4]  Alpha color value  0.0 to 1.0 
 result[5]  X normal displacement  -1.0 to 1.0 
 result[6]  Y normal displacement  -1.0 to 1.0 
 result[7]  Z normal displacement  -1.0 to 1.0 
O Plugin deverá sempre retornar um valor de intensidade. O retorno de Cores em RGB ou valores de Normal são opcionais, e deverão ser indicados pela "flag" (bandeira) doit() de retorno com os valores “1” (RGB) ou “2” (Normal).
Antes do Plugin ser chamado, o Blender inclui o seguinte dentro da renderização-normal result[5], result[6] and result[7].
float cfra
O valor cfra, é um valor configurado pelo Blender para o "frame" (quadro) corrente antes de cada passo de renderização. Este valor é o número do "frame" (quadro) (± 0.5 dependendo das configurações de campo de entrelaçamento).
plugin_tex_doit prototype
A função plugin_tex_doit deverá ser prototipada para ser utilizada pela função getinfo . Você não necessita fazer alterações nesta linha.
plugin_tex_getversion
Esta função deverá estar em cada Plugin para que ele seja carregado corretamente. Você não deve alterar esta função.
plugin_but_changed
Esta função é utilizada para passar informação sobre quais botões o usuário modou dentro da Interface. A maioria dos Plugins não necessita utilizar esta função, somente quando a Interface permite o usuário que altere algumas variáveis que forçam o Plugin a fazer um recálculo (uma tabela randômica picada, por exemplo (random hash table)).
plugin_init
Caso necessário, os Plugins podem utilizar esta função para inicializar os dados Internos.
Nota: Esta função de inicialização pode ser chamada múltiplas vezes caso o mesmo Plugin de textura seja copiado. Não inicie "global data" (dados Globais) específicos de uma instância única de um Plugin nesta função.
plugin_getinfo
Esta função é utilizada para comunicar informação para o Blender. Você nunca precisará alterá-la.
plugin_tex_doit
A função doit é responsável pelo retorno da informação sobre o Pixel requisitado para o Blender.
"The Arguments" (Os Argumentos)
int stype
Este é o número do sub-tipo selecionado, veja as entradas acima sobre NR_TYPES e char stnames[NR_TYPES][16].
Cast *cast
A estrutura Cast é a que contém os dados do Plugin, veja as entradas acima sobre typedef struct Cast.
float *texvec
Este é um ponteiro para três posições flutuantes, que são as coordenadas das texturas para qual o valor da textura será retornado.
float *dxt, float *dyt
Caso este ponteiros sejam não nulos, (non-NULL) eles apontam para dis vetores ( duas matrizes de três pontos flutuantes) que definem o valor de tamanho da textura requisitada em espaço de Pixels. Eles são somente não nulos (non-NULL) quando o Oversamplig está ligado (OSA) e são utilizados para realizar apropriadamente os cálculos de Anti-Aliasing.
A função doit deverá preencher dentro da matriz resultante (ela deverá sempre preencher um valor de intensidade), e retorna 0, 1, 2 ou 3 dependendo de quais valores foram preenchidos :
  • 0 para intensidade somente,
  • 1 para intensidade + Cor RGBA,
  • 2 para intensidade + Normal, e
  • 3 para intensidade + Cor RGBA + Normal.


Interação Textura/Material

O Blender é um pouco diferente da maioria dos pacotes de 3D dentro da separação lógica entre Texturas e Materiais. Dentro do Blender, as Texturas são Objetos que retornam certos valores, são de fato geradores de sinal (como geradores de onda em um sintetizador, por exemplo). Os Materiais controlam o Mapeamento das Texturas nos Objetos, o que é afetado, quanto, em que sentido, etc.

Plugins apropriadamente desenhados deverão somente incluir variáveis para afetar o sinal retornado, não o seu mapeamento. Os botões para controlar a escala, campo de abrangência, eixos, etc, são melhor incluídos quando eles fazem com que a Textura seja fácil de utilizar (no caso do botão "Size" (Tamanho) dentro do Plugin "Tiles" (Encaixes/recortes)), ou quando eles aceleram a calculação (os sub-tipos "Intensity" (Intensidade)/"Color" (Cor)/"Bump" (Ressalto) dentro do Plugin Clouds2). Caso contrário, o sub-contexto Material fará com que esses botões se tornem redundantes, e a interface se tornará complexa sem necessidade.

Plugin de Textura Genérica

#include "plugin.h"
 
/* Texture name */
char name[24]= "";
 
#define NR_TYPES 3
char stnames[NR_TYPES][16]= {"Intens", "Color", "Bump"};
 
/* Structure for buttons,
 * {butcode, name, default, min, max, tooltip}
 */
VarStruct varstr[]= {
	{NUM|FLO, "Const 1", 1.7,    -1.0, 1.0, ""},
};
 
typedef struct Cast {
	float a;
} Cast;
 
float result[8];
float cfra;
 
int plugin_tex_doit(int, Cast*, float*, float*, float*);
 
/* Fixed Functions */
int plugin_tex_getversion(void) {
	return B_PLUGIN_VERSION;
}
 
void plugin_but_changed(int but) { }
void plugin_init(void) { }
 
void plugin_getinfo(PluginInfo *info) {
	info->name= name;
	info->stypes= NR_TYPES;
	info->nvars= sizeof(varstr)/sizeof(VarStruct);
	info->snames= stnames[0];
	info->result= result;
	info->cfra= &cfra;
	info->varstr= varstr;
	info->init= plugin_init;
	info->tex_doit= (TexDoit) plugin_tex_doit;
	info->callback= plugin_but_changed;
}
 
int plugin_tex_doit(int stype, Cast *cast, float *texvec, float *dxt, float *dyt) {
	if (stype == 1) {
		return 1;
	}
	if (stype == 2) {
		return 2;
	}
	return 0;
}


Nossas Modificações

O Primeiro passo é ter um diagrama ou um plano de ação. O que este Plugin irá fazer, como os usuários irão interagir com ele. Para este exemplo, nós vamos criar uma simples Textura que cria um simples padrão de blocos de "brick" (tijolos). Agora nós vamos copiar nosso Plugin Genérico cube.c e iremos preencher as lacunas. É sempre uma (muito boa) ideia adicionar alguns comentários. Primeiro de tudo dizer aos usuários o que o Plugin faz, aonde eles podem obter uma cópia, quem eles devem contatar para correções de bugs/melhorias, e quaisquer restrições de licenças que o Plugin possa ter nos seus códigos.

Quando estiver utilizando comentários, tenha certeza de utilizar com comentários em estilo de linguagem C, tipicamente “/* */”. Os Plugins são escritos em C e alguns compiladores não aceitam comentários no estilo C++, portanto, use “//” para seus comentários. Exemplo abaixo (em inglês):

/*
Description: This plugin is a sample texture plugin that creates a simple
brick/block pattern with it.
It takes two values a brick size, and a mortar size.
The brick size is the size of each brick.
The mortar size is the mortar size in between bricks.
Author: Kent Mein (mein@cs.umn.edu)
Website: http://www.cs.umn.edu/~mein/blender/plugins
Licensing: Public Domain
Last Modified: Tue Oct 21 05:57:13 CDT 2003
*/

O próximo passo é preencher o código para o nome name, você realmente deverá manter este como sendo o mesmo que o seu nome de arquivo .c , preferivelmente descritivo, com menos de 23 caracteres, sem espaços, e todos em "lowercase" (Minúsculo).

char name[24]= "cube.c";

Nós iremos tentar manter este Plugin o mais simples possível, e somente possuir um tipo de controle que lida com a intensidade. Então necessitamos do seguinte:

#define NR_TYPES 1
char stnames[NR_TYPES][16]= {"Default"};

Para a nossa Interface de Usuário, nós iremos permitir que as pessoas alterem o tamanho dos Blocos de "Brick and Mortar" (Tijolos e da Massa), tanto quanto os valores de intensidade retornados para fabricar os Blocos de "Brick and Mortar" (Tijolos e Massa). Para isso, nós precisamos editar os valores de varstr e Cast. A parte onde estão os códigos para Cast deverão ter uma varável para cada entrada dentro de varstr.

/* Structure for buttons,
 *	{butcode, name,     default, min, max, tooltip]
 */
VarStruct varstr[]= {
	{NUM|FLO, "Brick",      0.8, 0.1, 1.0, "Size of Cell"},
	{NUM|FLO, "Mortar",     0.1, 0.0, 0.4, "Size of boarder in cell"},
	{NUM|FLO, "Brick Int",  1.0, 0.0, 1.0, "Color of Brick"},
	{NUM|FLO, "Mortar Int", 0.0, 0.0, 1.0, "Color of Mortar"},
};
 
typedef struct Cast {
	float brick, mortar, bricki, mortari;
} Cast;

Agora nós precisamos preencher a parte de plugin_tex_doit, nós basicamente queremos quebrar a nossa textura em “Células” que irão consistir de um bloco e a Massa estará na base dos cantos desse “Tijolo”. Então, determinar se estamos na parte do "Brick OR Mortar" (Tijolo OU da Massa). O seguinte código deverá fazer isto:

int plugin_tex_doit(int stype, Cast *cast, float *texvec, float *dxt, float *dyt) {
	int c[3];
	float pos[3], cube;
 
	/* setup the size of our cell */
	cube = cast->brick + cast->mortar;
 
	/* we need to do is determine where we are inside of the current brick. */
	c[0] = (int)(texvec[0] / cube);
	c[1] = (int)(texvec[1] / cube);
	c[2] = (int)(texvec[2] / cube);
	pos[0] = ABS(texvec[0] - (c[0] * cube));
	pos[1] = ABS(texvec[1] - (c[1] * cube));
	pos[2] = ABS(texvec[2] - (c[2] * cube));
 
	/* Figure out if we are in a mortar position within the brick or not. */
	if ((pos[0] <= cast->mortar) ||
	    (pos[1] <= cast->mortar) ||
	    (pos[2] <= cast->mortar)) {
		result[0] = cast->mortari;
	} else {
		result[0] = cast->bricki;
	}
	return 0;
}

Uma coisa a ser notada, a função ABS (que retorna uma variável de valor numérico Absoluto) está definida no cabeçalho ou declaração plugins/include. Existem algumas outras funções comuns também, tenha certeza de dar uma olhada no que está ali.

Compilando

O software “bmake” é um simples utilitário, (que roda através de shell script) para auxiliar com a compilação e desenvolvimento de Plugins. Ele ode ser encontrado dentro do subdiretório plugins/ da Instalação do Blender. Ele é invocado pela linha de comando : bmake (plugin_name.c), e irá tentar ligar corretamente as bibliotecas apropriadas e compilar o arquivo específico em C de maneira adequada para seu Sistema.

Caso você esteja tentando desenvolver Plugins em uma Máquina rodando o Sistema Operacional Microsoft Windows, o software “bmake” poderá não funcionar. Neste caso, você deverá procurar pela utilização do software “lcc”. Você poderá utilizar o seguinte para compilar um Plugin com o “lcc”:

Assumindo que você tenha colocado os seus Plugins dentro de c:\blender\plugins, aqui há uma exemplo de como você deverá compilar o Plugin de Textura sinus.c. Abra uma Janela de Console de comando ou DOS e faça o seguinte (Nota: Você irá querer ter certeza de que o diretório lcc\bin está corretamente registrado na lista de caminhos ou “Path”, consulte os arquivos para fazer os registros adequados de sua variáveis de ambiente para seu Sistema Operacional):

cd c:\blender\plugins\texture\sinus
lcc -Ic:\blender\plugins\include sinus.c
lcclnk -DLL sinus.obj c:\blender\plugins\include\tex.def
implib sinus.dll

A última versão do “lcc” não possui a biblioteca “implib”. Caso realmente não a tenha, faça o seguinte:

cd c:\blender\plugins\texture\sinus
lcc -Ic:\blender\plugins\include sinus.c
lcclnk -dll -nounderscores sinus.obj c:\blender\plugins\include\tex.def

Note que o arquivo tex.def não é distribuído com os fontes do Blender, mas está disponível a partir do Repositório de Plugins do Blender. Alternativamente, crie um arquivo tex.def, copie e cole o seguinte :

EXPORTS
LibMain@12
plugin_but_changed
plugin_getinfo
plugin_init
plugin_tex_doit
plugin_tex_getversion