Organikus térhálókat élethűbbé tehetünk apró, periodikus mozgásokkal. Ilyen
volt például az Aeronautism című demónkban a repülő szörny, aminek a csápjai
és a farokúszója ritmikusan lengett.
A vertex shaderek elsősorban a térhálók csúcsponti koordinátáit és a normál
vektorokat kapják bemenetnek, de a programozó bizonyos számú saját attribútumot
is megadhat. Ezt fogjuk mi is használni, hogy kijelöljük azokat a csúcspontokat,
amelyeket mozgatni akarunk.
A csúcspontok kijelöléséhez kezdetben azt a trükköt használtam, hogy a betöltöttem a modellt egy szerkesztő programba és azokat a csúcsokat, amelyeket nem kívántam mozgatni, kitöröltem. Exportáltam OBJ formátumba a csonka modellt, majd a Linux parancssor és Perl scriptek segítségével összehasonlítottam az eredeti modellel. Végül a különbségükből készítettem egy fájlt, ami minden egyes csúcspontra tartalmazott egy 0 vagy 1 értéket, attól függően, hogy akartam-e mozgatni az adott csúcsot vagy nem. Az Aeronautism-ban volt egy 0.5 is, mert a csápokat máshogy mozgattam, mint a farokúszót.
Szerencsére Blender segítségével egyszerűsíthető a folyamat. Ezt fogom részletezni.
Indítsuk el a Blendert, töltsük be a modellünket. Váltsunk Vertex Paint módba, majd fessük be a kívánt színűre a csúcspontokat. A be nem festett részek fehérek lesznek. Ha többféle mozgást akarunk, akkor használjunk különböző színeket. Ebben a példában pirosat használtam. A mozgások finomhangolására használhatjuk a színek intenzitását is, amit a Paint fülön állíthatunk be.
Ha elküszültünk, akkor egy Python script segítségével könnyedén exportálhatjuk a csúcspontok színeit. A szkript forráskódja a következő:
#!BPY
A szkriptet másoljuk a .blender/scripts könyvtárba. Ha már fut a Blender, a Script -> Update Menu menüponttal frissítsünk. Ez a szkript egy nyers adatot ad vissza egy előre definiált fájlba. Minden egyes poligon csúcspontjának a színét és a csúcspont sorszámát adja vissza. Mivel a poligonok közös csúcspontot adnak vissza, ezért az eredmény fájl redundáns. Még mindig nem értek eléggé a Python nyelvhez, ezért az ismétlődő szakaszokat a parancssor segítségével távolítom el:
"""
Name: 'Vertex Color Extract'
Blender: 243
Group: 'Export'
"""
import bpy
import Blender
from Blender import *
scene = bpy.data.scenes.active
for o in scene.objects:
if o.type == 'Mesh':
mesh = o
bf = open("vertexcolor.txt", "w")
for face in mesh.data.faces:
for i, vert in enumerate(face):
bf.write("%f %f %f %d\n" % (face.col[i].r, face.col[i].g, face.col[i].b, vert.index))
bf.close()sort -nk 4 vertexcolor.txt | uniq >eredmeny.txt
Minden egyes csúcspont színe megvan. A demónkba töltsük be ezt a fájlt és tároljuk le egy tömbbe. A példában ez a tömb az attrib nevet kapja. GLfloat attrib[4432]; /* Tudom, mennyi csúcspontom van a térhálóban */
A példaprogram elég egyszerű. Mivel egy demóban a programozó tudja, hogy az adott modell mennyi csúcspontból áll, ezért bocsánatos bűn, ha ezt beégetem a kódba. Ha újra akarjuk használni a kódot, akkor természetesen át kell tervezni azt.
file = fopen("vertexcolor.txt", "r");
while(fgets(line, 200, file) != NULL){
r = atof(strtok(line, " "));
g = atof(strtok(NULL, " "));
b = atof(strtok(NULL, " "));
index = atoi(strtok(NULL, " \n"));
if(g == 0.0 && b == 0.0){
attrib[index] = 1.0;
}
else{
attrib[index] = 0.0;
}
}
fclose(file);
Miután beolvastuk a fájlból az adatokat, készítünk egy vertex buffert a tárolására: glGenBuffers(1, &vbo);
Majd a shader megfelelő változójához kötjük a vertex buffert. Ez a lépés nagyban hasonlít a korábban bemutatott csúcspont és normál vektornál használt módszerhez.
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * vertexcount, attrib, GL_STATIC_DRAW); glBindVertexArray(vao);
Az OpenGL kirajzoló rutin a következő képpen fest:
uni = glGetAttribLocation(shader, "sniff");
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(uni, 1, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(uni);
glUseProgram(shaderprg);
Végezetül lássuk a shader kódot:
time = getTimeInterval();
uni = glGetUniformLocation(snooze, "time");
glUniform1f(uni, time);
#version 410
Amely csúcspontnál az attribútum 1.0, ott a pozíció egy kis színusz függvény segítségével oszcillál, amitől élőbbnek tűnik a háló. Még élethűbb lehet a modell, ha zaj segítségével kiszámíthatatlanabbá tesszük a mozgást. A példafájlban a modellt Grass készítette. A Function-os demónkban is látható lesz. (A program teljes forráskódját hamarosan elérhetővé teszem)
in vec3 vertex;
in vec3 normal;
in float sniff;
uniform mat4 pmatrix;
uniform mat4 modelmatrix;
uniform float time;
out vec3 color;
void main(void){
vec3 pos = vertex;
if(sniff == 1.0) pos.y = pos.y + sin(time * 40.0) / 300.0;
gl_Position = pmatrix * modelmatrix * vec4(pos, 1.0);
color = normal * vec3(1.0);
}