Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Generación De Modelos Usando Blender Scripts

Iniciado por LC0, 03 de Agosto de 2005, 01:45:32 PM

« anterior - próximo »

LC0

 Saludos a todos.
Me ha dado por empezar a investigar un poco  en el asunto de los scripts en Python de Blender.
Así que he decidido crear uno de prueba, donde se coge una malla de la escena y se guarda en un formato muy muy muy simple: un fichero de texto con las coordenadas de los vértices de cada cara.

De este modo, he creado también un pequeñísimo programa que, con la ayuda de sdl y opengl, visualiza los objetos generados en este formato.

El problema es que parece que los vértices de las caras no son los adecuados, con lo que se observa que la forma del objeto es la adecuada, pero, internamente, el cúmulo de vértices es extrañísimo:

(El objeto que se observa en la imagen es la cabeza de Mono "estándar" de Blender :) ).

Os posteo aquí el script y el visualizador:


from Blender import *
import sys

def grabar():
obj = NMesh.GetRaw("Suzanne")
f=open("bicho2.3dt","w")
for i in obj.faces:
 print len(i.v)
 for j in range(len(i.v)):
  f.write(str(i.v[j].no[0]) + '\n')
  f.write(str(i.v[j].no[1]) + '\n')
  f.write(str(i.v[j].no[2]) + '\n')      
  f.write(str(i.v[j].co[0]) + '\n')
  f.write(str(i.v[j].co[1]) + '\n')
  f.write(str(i.v[j].co[2]) + '\n')
     
       

f.close()


grabar()




int main(int argc, char *argv[])
{
cout <<"Initializing SDL." << endl;

if(SDL_Init(SDL_INIT_EVERYTHING)< 0)
{
 cerr <<"Could not initialize SDL:" << SDL_GetError() << endl;
 SDL_Quit();
}

SDL_GL_SetAttribute(SDL_GL_RED_SIZE,8);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE,8);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE,8);
SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE,8);

SDL_Surface* Video=SDL_SetVideoMode(800,600,32,SDL_OPENGL |SDL_HWSURFACE| SDL_HWPALETTE/*|SDL_GL_DOUBLEBUFFER*/);
if(Video==NULL)
{
 cerr << "Error en modo de video:" << SDL_GetError() << endl;
}

double x=0, y=0;

glEnable(GL_SMOOTH);
glClearColor(0.0,0.0,0.0,0.0);
glMatrixMode(GL_PROJECTION);
   gluPerspective( 45.0f, 640.0f / 480.0f, 0.1f, 100.0f);

int e=0;
bool fin=false;
SDL_Event evento;
double d=1;

ifstream fich("bicho2.3dt");
vector<Coord> objeto;
double coordx, coordy,coordz;
while(fich >> coordx >> coordy >> coordz) //Colorear cada cara con un tono grisáceo: MUY LENTO, pero, como esto es solo una prueba...
{
 objeto.push_back(Coord(coordx,coordy,coordz,rand()%255));
 srand(SDL_GetTicks());
 SDL_Delay(1);
}

while(!fin)
{
 
 SDL_PollEvent(&evento);
 if(evento.type==SDL_KEYDOWN)
  if(evento.key.keysym.sym==SDLK_LEFT) x-=1.5;
  else if(evento.key.keysym.sym==SDLK_RIGHT) x+=1.5;
  else if(evento.key.keysym.sym==SDLK_UP) y+=1.5;    
  else if(evento.key.keysym.sym==SDLK_DOWN) y-=1.5;    
  else if(evento.key.keysym.sym==SDLK_ESCAPE) fin=true;
 
 
 if(SDL_MUSTLOCK(Video)) SDL_LockSurface(Video);

 Uint32 color_pixel=SDL_MapRGB(Video->format,255,0,255);
 
 glClear(GL_COLOR_BUFFER_BIT);
 glMatrixMode(GL_MODELVIEW);
 glLoadIdentity();
 glPushMatrix();
 glTranslatef(0.5,0.5,y);
 glRotatef(x,0.0,1.0,0.0);
 vector<Coord>::iterator i=objeto.begin();


 while(i<objeto.end())
 {
  glDisable(GL_CULL_FACE);
  glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);  
  glBegin(GL_TRIANGLES);  
   glColor3ub(i->color,i->color,i->color);
   glNormal3f(i->x,i->y,i->z);
   i++;
   glVertex3f(i->x,i->y,i->z);
   i++;
   glNormal3f(i->x,i->y,i->z);
   i++;
   glVertex3f(i->x,i->y,i->z);
   i++;
   glNormal3f(i->x,i->y,i->z);
   i++;
   glVertex3f(i->x,i->y,i->z);
   i++;
  glEnd();  
 }

 glPopMatrix();
 
 SDL_GL_SwapBuffers();  
 if(SDL_MUSTLOCK(Video)) SDL_UnlockSurface(Video);

 
}

SDL_Quit();
return 0;
}


A ver si podeis ayudarme, porque esto, que es tan sencillo, me trae de cabeza. De antemano, muchas gracias.

PD: Perdón por la identación: Los ficheros originales están bien identados, pero al pasarlo aquí, he hecho (y me ha hecho :D) cosas raras, y no tengo demasiadas ganas de retocarlo todo ahora.

vincent

 no tengo idea de python con blender, pero no puede ser que té dé primero la ristra de vértices y después te venga la lista de caras?
Desarrollo en .Net y metodologías http://devnettips.blogspot.com

LC0

 En teoría, a los vértices de una malla se puede acceder desde las caras, que contienen una lista con los vértices que la forman (que pueden ser 3 o 4, pero a la hora de generar la malla he tenido cuidado de que esta wsté formada por triángulos).
te paso el link donde viene la referencia de los objetos y los miembros del API.

ajmendoza

 No será error de la normal de las caras? cada una mira para donde le parece.

Saludos

zupervaca

 puede que algunos triangulos esten en sentido horario y otros no, aunque algunos triangulos parece que estan demasiado estirados

LC0

 
Citar
No será error de la normal de las caras? cada una mira para donde le parece.

Eso pensé en un principio, pero,como dice zupervaca, mira algunos vértices: salen demasiado estirados, y otros parecen que no encajan en el "puzzle".
Y no te creas que no activé la capacidad de renderizar las caras por los dos lados, pero... nada de nada.

vincent

 Quizá debes tener en cuenta el siguiente parametro de los vertices


index
The vertex index, if owned by a mesh.

   Type:
       int



Saludos,
Desarrollo en .Net y metodologías http://devnettips.blogspot.com

LC0

 Sí, me he percatado de la propiedad index, pero eso solo indica la posición del vértice en la lista de vértices de la malla, y no de la cara en cuestión.
Aunque parezca confuso, pero a los vértices de una malla se pueden acceder de dos formas: A través de ella misma, o a través de las caras.
Obtenerla directamente desde la malla no asegura la pertenencia a una cara en concreto.

Por cierto, gracias a todos por las respuestas.

_Grey

 El problema esta en que guardas los datos de los vértices sin tener en cuenta los datos de las caras, los vértices están en su sitio pero las caras están de cualquier manera.

A long long time ago, a far galaxy..... digo ..... hace tiempo estuve trasteando con blender y los scripts en python, me hice un par que prácticamente no recuerdo como funcionan, es mas, supe como "programar" en python por ver los scripts y la api de blender igual, y en el fondo son adaptaciones propias de otros scripts que había por Internet, la cuestión es que los e probado y parecen funcionar bien.
El primero guarda los valores de los objetos haciendo 3 vértices por cada polígono, con lo que te saldrá una lista larga, el segundo guarda un vértice por cada vértice del objeto y procura que la lista de indices este bien, eso si, al final, el interprete python de blender da error, pero el archivo parece salvarse bien.
El archivo es de tipo .ASC, lo podrás leer con el bloc de notas si quieres, tiene modificado el campo de material, pondrá el nombre de la textura si se usa.
Te tendría que ser fácil modificar para que salve a otro tipo de formato, apenas cambiando el contenido de los write(), y por lo menos veras como recorría los objetos de Blender para que te hagas tu propio script.

Eso si, de esto hace mucho y no te podre ayudar mucho mas allá, te dejo el código de ambos.

Este es el primero, Blender2Asc.py:

import Blender

from Blender import NMesh
from Blender import Object
from Blender import Material

# En este Script se cambia
# la x por la y y se invierte el valor de la z
# tambien se cambia el orden de los vertices del poligono
# asi se puede cargar tal como se ve en Blender

def printVertex(f,mesh,cara,v,array,number,mat):
   nx = v[array].co[0]*mat[0][0]+v[array].co[1]*mat[1][0]+v[array].co[2]*mat[2][0]+mat[3][0];
   ny = v[array].co[0]*mat[0][1]+v[array].co[1]*mat[1][1]+v[array].co[2]*mat[2][1]+mat[3][1];
   nz = v[array].co[0]*mat[0][2]+v[array].co[1]*mat[1][2]+v[array].co[2]*mat[2][2]+mat[3][2];
   auxn = ny;
   ny = nz;
   nz = auxn;
   nz = nz * -1;
   f.write("Vertex %d: X: %f Y: %f Z: %f " % (number,nx,ny,nz))
   if len(cara.uv):
       f.write("U: %f V: %f" % (cara.uv[array][0],cara.uv[array][1]))
   f.write("\n")

def printColors(f,c):
   f.write("\n")
   f.write("    r %f g %f b %f a %f " % (c.r,c.g,c.b,c.a))

def printObject(f,objBase):
   # cuenta cuantas cara ahi cada cara de 3 vertices cuenta como uno cada cara de 4 vertices cuento como 2
   obj = Blender.NMesh.GetRaw(objBase.data.name)    
   obj.hasFaceUV()
   cantidadCaras = 0
   totalCaras=0;
   matrix=objBase.matrix
   while cantidadCaras<len(obj.faces):
       cara = obj.faces[cantidadCaras]
       # saca los vertices de la cara
       vertPorCara = len(cara.v)
       if vertPorCara == 4:
           totalCaras = totalCaras +2
       elif vertPorCara == 3:
           totalCaras = totalCaras +1
       cantidadCaras = cantidadCaras +1
   # saca imformacion del objeto en formato .ASC
   f.write("Tri-mesh, Vertices: %d Faces: %d\n" % (totalCaras*3,totalCaras))
   if len(cara.uv):
       f.write("Mapped\n")
   f.write("Vertex list:\n")
#    if obj.has_uvco:
#        print "has_uvco OK"
#    else:
#        print "has_uvco NONE"
#    for uv in cara.uv:
#        print "*" , uv
   # saca lista de vertices
   vert=0
   cantidadCaras = 0
   while cantidadCaras<len(obj.faces):
       cara = obj.faces[cantidadCaras]
       # saca los vertices de la cara
       vertPorCara = len(cara.v)
       if vertPorCara == 4:
#            print "CUATRO CARAS"
           printVertex(f,obj,cara,cara.v,0,vert,matrix)
           vert = vert +1
           printVertex(f,obj,cara,cara.v,1,vert,matrix)
           vert = vert +1
           printVertex(f,obj,cara,cara.v,2,vert,matrix)
           vert = vert +1
           printVertex(f,obj,cara,cara.v,2,vert,matrix)
           vert = vert +1
           printVertex(f,obj,cara,cara.v,3,vert,matrix)
           vert = vert +1
           printVertex(f,obj,cara,cara.v,0,vert,matrix)
           vert = vert +1
       elif vertPorCara == 3:
#            print "TRES CARAS"
           printVertex(f,obj,cara,cara.v,0,vert,matrix)
           vert = vert +1
           printVertex(f,obj,cara,cara.v,1,vert,matrix)
           vert = vert +1
           printVertex(f,obj,cara,cara.v,2,vert,matrix)
           vert = vert +1
#        else:
#            print "valor de vertPorCara %d\n" % vertPorCara
       cantidadCaras =  cantidadCaras+1
   # saca lista de caras
   f.write("Face list:\n")
   cantidadCaras = 0
   caraindex = 0
   indice = 0
   while cantidadCaras<len(obj.faces):
       cara = obj.faces[cantidadCaras]
       # saca los vertices de la cara
       vertPorCara = len(cara.v)
       if vertPorCara==4:
           f.write("Face %d: A:%d B:%d C:%d\n" % (caraindex,indice,indice+2,indice+1))
           indice = indice+3
           f.write("Smoothing: 0\n")
           if len(cara.uv):
               f.write("Material: \"%s\"\n" % (cara.image.getFilename()))                
#                f.write("Material: \"pisos.tga\"\n")
#                f.write("Material: \"%s\"\n" % (obj.mats[cara.mat]))
           caraindex = caraindex+1
           f.write("Face %d: A:%d B:%d C:%d\n" % (caraindex,indice,indice+2,indice+1))
           indice = indice+3
           f.write("Smoothing: 0\n")
           if len(cara.uv):
               f.write("Material: \"%s\"\n" % (cara.image.getFilename()))                
#                f.write("Material: \"pisos.tga\"\n")
#                f.write("Material: \"%s\"\n" % (obj.mats[cara.mat]))
           caraindex = caraindex+1
       elif vertPorCara == 3:            
           f.write("Face %d: A:%d B:%d C:%d\n" % (caraindex,indice,indice+2,indice+1))
           indice = indice+3
           f.write("Smoothing: 0\n")
           if len(cara.uv):
               f.write("Material: \"%s\"\n" % (cara.image.getFilename()))                
#                f.write("Material: \"pisos.tga\"\n")
#                f.write("Material: \"%s\"\n" % (obj.mats[cara.mat]))
           caraindex = caraindex+1
       cantidadCaras =  cantidadCaras+1

print "INICIO SCRIPT"

fp = open("C:/blender.txt","w")
fp2 = open("C:/debug.txt","w")

objectslist = Object.Get()
objectslistcount=0
objectsaved=0
print "Objetos totales:",len(objectslist)
fp2.write("Objetos totales:%d\n" % (len(objectslist)))
while objectslistcount<len(objectslist):
   object3d = NMesh.GetRaw(objectslist[objectslistcount].name)
   print "Objeto:",objectslist[objectslistcount].name
   fp2.write("Objeto:%s\n" % (objectslist[objectslistcount].name))
   if object3d!=None:
       fp.write("Named object: \"")
       fp.write(objectslist[objectslistcount].name)
       fp.write("\"\n")
       printObject(fp,objectslist[objectslistcount])
       fp.write("\n")
       objectsaved = objectsaved +1
   else:
       print "No es un mesh y no se guarda"
       fp2.write("No es un mesh y no se guarda\n")
   objectslistcount = objectslistcount+1

fp2.close()
fp.close()

print "FIN SCRIPT"


Y este el segundo del que hablaba, Blender2AscPRO.py: (PRO?? ni que fuera un counter de esos XD)
import Blender
from Blender import NMesh
from Blender import Object
from Blender import Material

print "INICIO SCRIPT"

# clase para guardar un vertice
class MyVertexClass:
   co=[]   # coordenadas del vertice
   no=[]   # normal
   uv=[]   # coordenadas de textura

# clase para guardar un poligono
class MyFaceClass:
   index=[]
   file=0

# UV 1 textura activas 0 no
# VertexArray tendra el array con los vertices
# FacesArray tendra el array con los poligonos
UV = 0
VertexArray=[]
FacesArray=[]

fp = open("C:/blender.txt","w")

objectslist = Object.Get()              # Coge lista de objetos

for inobjectlist in objectslist:        # Pasa por todos los objetos
   objraw = NMesh.GetRaw(inobjectlist.name)
   if objraw==None:                        # No es una malla
       print inobjectlist.name+" - "+"NO ES UNA MALLA"
   else:                                   # Es una malla
       print inobjectlist.name+" - "+"ES UNA MALLA"
       for f in objraw.faces:                  # Pasa por todas las caras del objeto
#            print "cara!"
           index=[]
           vertcount=0
           for fv in f.v:                          # Pasa por todos los vertices de la cara
               VertexSearch = MyVertexClass()          # Crea vertice
               VertexSearch.co = fv.co
               VertexSearch.no = fv.no
               VertexSearch.uv = []                
               if objraw.hasFaceUV():
                   UV = 1
                   VertexSearch.uv.append(f.uv[vertcount][0])
                   VertexSearch.uv.append(f.uv[vertcount][1])
               pos=0
               for searchv in VertexArray:             # Busca el VertexSearch dentro de VertexArray
                   if searchv.co[0]==VertexSearch.co[0]:   # Compara searchv con VertexSearch
                       if searchv.co[1]==VertexSearch.co[1]:
                           if searchv.co[2]==VertexSearch.co[2]:
                               if searchv.no[0]==VertexSearch.no[0]:
                                   if searchv.no[1]==VertexSearch.no[1]:
                                       if searchv.no[2]==VertexSearch.no[2]:
                                           if len(searchv.uv):
                                               if searchv.uv[0]==VertexSearch.uv[0]:
                                                   if searchv.uv[1]==VertexSearch.uv[1]:
                                                       break
                                           else:
                                               break
                   pos=pos+1                               # incrementa marcador de posicion del vertice que se busca
               if pos==len(VertexArray):               # No esta el vertice y se introducira
                   VertexArray.append(VertexSearch)
               index.append(pos)                       # Introduce indice en estructura de la cara
               vertcount = vertcount + 1
           newFace = MyFaceClass()                 # Crea la cara
           newFace.index=[]
           newFace.index.append(index[0])          # Pasa los indices a la cara ...
           newFace.index.append(index[1])
           newFace.index.append(index[2])
           if f.image:
               newFace.file=f.image[0].name
           FacesArray.append(newFace)              # Introduce cara al array FacesArray                
           if len(index)==4:                       # Crea una cara extra por que la original era de 4 vertices
               newFace = MyFaceClass()                 # Crea la cara
               newFace.index=[]                
               newFace.index.append(index[2])          # Pasa los indices a la cara ...
               newFace.index.append(index[3])
               newFace.index.append(index[0])
               if f.image:                
                   newFace.file=f.image[0].name
               FacesArray.append(newFace)              # Introduce cara al array FacesArray

fp.write("Named object: \"%s\"\n" % ("ostras"))
fp.write("Tri-mesh, Vertices: %i Faces: %i\n" % (len(VertexArray),len(FacesArray)))
if UV==1:   # Tiene coordenadas de textura
   fp.write("Mapped\n")
fp.write("Vertex list:\n")
print "VertexArray(",str(len(VertexArray)),")"
count = 0
for va in VertexArray:
   fp.write("Vertex %i: X: %f Y: %f Z: %f " % (count,va.co[0],va.co[1],va.co[2]))
#    if len(va.no):
#        fp.write("norm %f %f %f " % (va.no[0],va.no[1],va.no[2]))
   if UV==1:   # Tiene coordenadas de textura
       fp.write("U: %f V: %f" % (va.uv[0],va.uv[1]))
   fp.write("\n")
   count = count +1

fp.write("Face list:\n")
print "FacesArray(",str(len(FacesArray)),")"
count = 0
for fa in FacesArray:
   fp.write("Face %i: A:%i B:%i C:%i\n" % (count,fa.index[0],fa.index[1],fa.index[2]))
   fp.write("Smoothing: 0\n");
   if fa.file:
       fp.write("Material: \"%s\"\n" % (fa.file));    
   count = count +1

print FacesArray[0]
fp.close()

print "FIN SCRIPT"


Espero que te ayuden, gracias por los recuerdos, saludos.

LC0

 
Citar
El problema esta en que guardas los datos de los vértices sin tener en cuenta los datos de las caras, los vértices están en su sitio pero las caras están de cualquier manera.
Uhm... pues tiene pinta de ser lo que tú dices, pero no acabo de ver cual puede ser esa información que falta.
Estaba pensando que, probablemente, el problema radique en que no guarde las normales de las caras (aunque, de un principio, tenía el objetivo de que el objeto se viera suavizado y, para eso, bastan las normales de los vértices.
Ahora mismo no puedo, pero mañana o en otro momento lo miraré, a ver que tal...
Venga, gracias :).






Stratos es un servicio gratuito, cuyos costes se cubren en parte con la publicidad.
Por favor, desactiva el bloqueador de anuncios en esta web para ayudar a que siga adelante.
Muchísimas gracias.