me encuentro ante una situacion algo complicada y queria saber como lo solucionasteis vosotros, tengo unos indices y unos vertices, algunos vertices se deben de duplicar por las coordenas de textura, pero ahora resulta que me he puesto a meterle las normales y ningun vertice tiene una normal igual, antiguamente tenia buffers separados y no era ningun problema, pero con el tema de querer aprovechar los shaders toda la info tiene que estar en el vertice, ¿como hago para no tener que duplicar todos los vertices? es que me encuentro en que los indices no valdrian para nada :huh:
saludos
Yo tambien me encontre con ese problema, y lo "solucione" dibujando los modelos como listas de triangulos sin indices, es decir, duplicando vertices. Ocupa un poco mas pero es mucho mas simple y sencillo :huh:
yo también opté por la solución a lo bruto... :rolleyes:
por ahora podre un indexbuffer de 0 a X por si acaso luego encuentro una solucion al problema tocho, pero no hay duda que por ahora duplicar todo es la unica solucion :(
gracias
Lo que tienes que hacer hacer es que esos vertices duplicados tengan la misma normal, si los calcula tu programa, podrias calcular las normales antes de duplicarlos y mantener esa misma normal para los duplicados.
Lo normal seria que al cargar la malla los vertices ya esten duplicados y con su normal correcta, pero claro, eso dependera de los formatos y editores graficos que uses.
Saludos.
Hasta donde yo se un buen formato de mallas deberia tener una lista de vectores 3d como vertices una lista de vectores 2d como texcoords y una lista de de poligonos/triangulos ( dependiendo del caso: separados como islas de stips o fans ), cada uno indicando sus pares de indices de posicion/texcoords correspondientes a cada vertice como así otras propiedades unicas del vertice como la normal, color, lista de pesos, etc ...
Saludos
PD: Dado el cruce con haddd, un buen formato debe ser independiente del API, cosa que uno construlla para su API la información que este necesite de la manera mas apropiada.
Bueno, estás metiendote de lleno en los problemas de base de DX B)
El problema es que el hardware necesita esa información por vértice. Así que en lugar de una estructura lógica de indices de vértices, índices de texturas, índices de normales, pues tenemos esta "horrorosa" forma de definir los vértices.
Tienes que tener en cuenta una cosa llamada smoothing groups. Si en el programa de dibujo quieres que te aparezca por ejemplo una esfera facetada, tienes que duplicar las normales en cada cara, si por el contrario quieres una esfera soft, las normales se tienen que promediar entre las caras y no necesitarás duplicarlas. Así que a veces depende del grafista si tienes o no que duplicar las normales. :blink:
Nosotros exportamos desde MAX la estructura lógica y después construimos un mesh de triángulos. Finalmente convertimos estos triángulos a indexado.
Por cierto, a ver si tienes una forma elegante de resolver el FVF, porque nosotros no lo hemos resuelto todavía ;)
¿entonces un smothing group seria una media de las normales de los tres posibles triangulos adyacentes al vertice? no se si formulo bien la pregunta
el tema del fvf no se exactamente a que te refieres, yo por ahora estoy utilizando los vertexelement para definir su estructura, si es como acceder a el sin realizar comprobaciones y sin tener su estructura ya definida la cosa esta chunga ... muuu chunga :lol:, no obstante puedes hacer pequeñas chapucillas con el CustomVertex, pero esta claro que este es el gran fallo que tenemos con c-sharp y que no sucedia con c++ ;)
saludos
Un smothing group es un conjunto de triangulos/faces/caras que tienen lados difumados ... o sea ... vertices en los cuales su normal se calcula interpolando las normales de los triangulos que lo usan, de esta manera se define la normal al vertice mediante un conjunto de caras que lo usan, esto es mas util para la etapa de edición.
Saludos.
pues ya que estamos, ¿alguien puede poner la formula para calcular la normal interpolada de un vertice compartido por un numero indeterminado de triangulos?
gracias y saludos.
teoricamente es sumar las dos normales y dividir el resultado entre 2, luego sumas al resultado otra normal y divides entre 2 y asi sucesivamente
(nooo) si ya me decia mi madre que estudiase
Citarteoricamente es sumar las dos normales y dividir el resultado entre 2, luego sumas al resultado otra normal y divides entre 2 y asi sucesivamente
Yo sumaria las normales de todos los poligonos adyacentes, y dividiria por la cantidad de normales calculadas, y luego mas vale que normalices la normal resultante :P
Hay un truco para que los poligonos de mas area "arrastren" la normal hacia ellos, haciendo la misma operacion, pero las normales de los poligonos que sumaras no deben estar normalizadas, pero recuerda otra vez normalizar la normal resultante :P
Saludos.
yo no te recomiendo hacer esto ya que cuando te metas en temas de colisiones tendras problemas, normalmente hacemos ese calculo durante la lectura de un archivo y no sabemos todas las normales que tiene con lo que por eso se lo dije asi
Me parece interesante lo de calcular las colisiones a partir de las normales, no estoy muy puesto en eso y algun dia tendre que meterme de lleno, ¿se supone que entonces las comprobaciones son hechas a partir de los vertices de cada plano en lugar de el plano en si?.
En ese caso seria bienvenido el que la colision tenga en cuenta tambien el arrastre de cada poligono, seria ideal para juegos tipo pinball u otros que requieran de colisiones muy precisas sobre todo tipo de superficies, supongo, no se.
es que eso ya depende del motor y como se quiera hacer, si quieres que cualquier modelo tenga colisiones, el tener definirle mas estructuras para comprobar las colisiones puede ser un problema (mas que nada de memoria), si quieres algo muy especifico como por ejemplo colisiones contra un decorado estatico, bsps, etc pues es mejor tener estructuras ya generadas con muchos calculos precalculados, es que ya te digo todo depende de lo que se quiera hacer
saludos
Cita de: "_Grey"Yo sumaria las normales de todos los poligonos adyacentes, y dividiria por la cantidad de normales calculadas, y luego mas vale que normalices la normal resultante :P
No sirve de nada dividir por la cantidad si luego normalizas ... y no hay regla para esto (encontrar la normal del vertice compartido), en realidad deberias parametrizar las curvas de las caras y así calcular la normal, pero como entonces se deberian especificar mas parametros por cara ... en definitiva sumas todas las normales y luego normalizas suponiendo una curva suave y homogenea ...
Saludos
Holaps,
Yo lo que hago es sumar la normal de todas las faces adyacentes al vertice del cual keremos sacar la normal, luego divido entre el nº de faces, y finalmente normalizo la normal resultante. Este algoritmo es muy útil cuando NO TENEMOS la normal de ningún vertice de la malla. De hecho, para k no kepa ninguna duda, akí teneis el código del método en cuestión:
NOTE: No os hagais la picha un lio con las llamadas al Device. No es Direct3D ni OpenGL, es una capa abstracta.
[SIZE=1]//--------------------------------------------------------------------------------------------
// Name: ComputeNormals()
// Desc: Compute vertex-based normals
//--------------------------------------------------------------------------------------------
/*BOOL8 cResMesh::ComputeNormals()
{
// Esta función hay k mirarla bien antes de activarla.
// Todo debería correr perfectamente, pero no está preparada para la posibilidad de usar un
// solo stream buffer: cStreamBuffers::IsUniqueStream().
return false;
if( !m_pBuffers || !m_pBuffers->m_tVB.m_pBuffer || !m_pBuffers->m_tIB.m_pBuffer )
return false;
if( !m_pBuffers->IsUniqueStream() && !m_pBuffers->m_tNB.m_pBuffer )
return false;
LPRETVECTOR3 pVB = 0;
LPRETVECTOR3 pNB = 0;
LPUNSIG16 pIB16 = 0;
LPUNSIG32 pIB32 = 0;
// Lock buffers
if( !RASTER->LockVertexBuffer( &(m_pBuffers->m_tVB), (LPVOID*)&pVB ) ) return false;
if( !RASTER->LockVertexBuffer( &(m_pBuffers->m_tNB), (LPVOID*)&pNB ) ) return false;
if( m_pBuffers->Is32BitIndexed() )
{
if( !RASTER->LockIndexBuffer( &(m_pBuffers->m_tIB), (LPVOID*)&pIB32 ) ) return false;
}
else
{
if( !RASTER->LockIndexBuffer( &(m_pBuffers->m_tIB), (LPVOID*)&pIB16 ) ) return false;
}
RETVECTOR3 vSum, vNormal;
FLOAT32 fShared = 0;
UNSIG32 i, j;
for( i = 0; i < m_pBuffers->m_dwNumVerts; i++ )
{
for( j = 0; j < m_pBuffers->m_dwNumFaces; j++ )
{
// Check if the vertex is shared by another face. All to do is add
// the un-normalized normal of the shared face and them increase "shared"
if( pIB16 )
{
if( pIB16[j+0] == i || pIB16[j+1] == i || pIB16[j+2] == i )
{
// Calculate the cross product to obtain the normal
vNormal = ( pVB[pIB16[j*3+0]] - pVB[pIB16[j*3+2]] ) ^ ( pVB[pIB16[j*3+0]] - pVB[pIB16[j*3+1]] );
vSum += vNormal;
fShared += 1.f;
}
}
else
{
if( pIB32[j+0] == i || pIB32[j+1] == i || pIB32[j+2] == i )
{
// Calculate the cross product to obtain the normal
vNormal = ( pVB[pIB32[j*3+0]] - pVB[pIB32[j*3+2]] ) ^ ( pVB[pIB32[j*3+0]] - pVB[pIB32[j*3+1]] );
vSum += vNormal;
fShared += 1.f;
}
}
}
// Get the normal by dividing the sum by the shared counter
// We must negate the shared for OpenGL, but not for D3D, so it has the normals pointing out
if( RASTER->IsD3D() )
pNB[i] = vSum / fShared;
else
pNB[i] = vSum / -fShared;
// Normalize it to get final vertex normal
pNB[i].SetNormalized();
vSum.SetZero(); // Reset the sum
fShared = 0.f; // Reset the shared
}
// Unlock buffers
RASTER->UnlockIndexBuffer ( &(m_pBuffers->m_tIB) );
RASTER->UnlockVertexBuffer( &(m_pBuffers->m_tVB) );
RASTER->UnlockVertexBuffer( &(m_pBuffers->m_tNB) );
return true;
}[/SIZE]
Sobre lo que decía Haddd de los smoothing groups..... Esto es realmente un problema GORDO, sobretodo a la hora de hacer un importador/exportador para MAX o cualkier otro programa de diseño 3D. Al final (después de 1 mes de trabajo) conseguí hacer un exportador en max script k te sacara posición de vertice, normal, color de vertice, coord de textura (hasta 3 sets de coordenadas), indices...cada elemento en un stream independiente. Así, para cargar luego la malla en el motor, el algoritmo es muy sencillo y extremadamente rápido (solo hay k crear los buffers y rellenarlos con la info). El problema de dicho exportador es que si la malla k se keire exportar sobrepasa X vértices, es posible k tarde unas cuantas....horas....en realizar la exportación. Y aún así, haciendo pruebas con los smoothing groups, notifiké un par de fallos k aún tengo k arreglar (nooo) Todavía me fata por exportar bones, pero eso lo dejaré para la otra vida (uoh)
Salud2
No se quien hizo ese algoritmo, pero lo unico que hace con dividir por fshared es invertir la normal en caso que no se use D3D y dar error de división si haces una malla de un solo vertice.
Matematicamente:
CitarV : Vector arbitrario;
Nv : vector normalizado -> |Nv| = 1;
a : escalar modulo arbitrario <> 0
tal que
V = aNv;
|V| = a;
Nv = V / |V|
lo que implica que
Nv = (aNv) / (a)
y por propiedad del producto y division:
J = bV;
Nj = J / |J|
|J| = b|V| = ba
Nj = (bV) / (ba) = (ba Nv) / (ba)
Nj = Nv
Lo cual demuestra indefectiblemente que para normalizar no hay que multiplicar o dividir un vector por nada, cuando normalizas le estas sacando el modulo!!!.
Saludos.
puedes hacer una optimizacion que notaras bastante, este codigo es mortal
for( i = 0; i < m_pBuffers->m_dwNumVerts; i++ )
{
for( j = 0; j < m_pBuffers->m_dwNumFaces; j++ )
{
recorre solo las caras, calculas la normal de esa cara y se la metes a los tres vertices sumandola contra la anterior que habia y la divides entre dos, al final recorres una vez mas los vertices y normalizas ya si quieres, de una pasada por las caras haces todo el calculo, si quieres saber como calcular la normal correctamente pasate por mi web y descarga el codigo de c++ clase vector
saludos
Cita de: "zupervaca"puedes hacer una optimizacion que notaras bastante, este codigo es mortal
for( i = 0; i < m_pBuffers->m_dwNumVerts; i++ )
{
for( j = 0; j < m_pBuffers->m_dwNumFaces; j++ )
{
recorre solo las caras, calculas la normal de esa cara y se la metes a los tres vertices sumandola contra la anterior que habia y la divides entre dos, al final recorres una vez mas los vertices y normalizas ya si quieres, de una pasada por las caras haces todo el calculo, si quieres saber como calcular la normal correctamente pasate por mi web y descarga el codigo de c++ clase vector
saludos
Hay un detalle con ese algoritmo colega, ¿qué pasa si un vertice pertenece a más de una cara?, entonces el vertice quedará con la normal de la última cara a la que pertenezca mostrando datos de iluminación erroneos cuando se referencie en caras anteriores, la única solución para eliminar ese problema es con smooth de normales, sacar una normal promedio de todas las normales que tiene el vértice, lo que no es muy simple.
Si esto no se hace se van a ver efectos de iluminación bastante extraños sobre el modelo.
Saludos.
Cita de: "visualcubb"Cita de: "zupervaca"puedes hacer una optimizacion que notaras bastante, este codigo es mortal
for( i = 0; i < m_pBuffers->m_dwNumVerts; i++ )
{
for( j = 0; j < m_pBuffers->m_dwNumFaces; j++ )
{
recorre solo las caras, calculas la normal de esa cara y se la metes a los tres vertices sumandola contra la anterior que habia y la divides entre dos, al final recorres una vez mas los vertices y normalizas ya si quieres, de una pasada por las caras haces todo el calculo, si quieres saber como calcular la normal correctamente pasate por mi web y descarga el codigo de c++ clase vector
saludos
Hay un detalle con ese algoritmo colega, ¿qué pasa si un vertice pertenece a más de una cara?, entonces el vertice quedará con la normal de la última cara a la que pertenezca mostrando datos de iluminación erroneos cuando se referencie en caras anteriores, la única solución para eliminar ese problema es con smooth de normales, sacar una normal promedio de todas las normales que tiene el vértice, lo que no es muy simple.
Si esto no se hace se van a ver efectos de iluminación bastante extraños sobre el modelo.
Saludos.
veamos si pertenece a mas de una cara, los indices de las caras ya resuelven este problema, para algo hay indices de las caras digo yo, lo correcto es usar un solo for
for( j = 0; j < m_pBuffers->m_dwNumFaces; j++ )
tampoco quedaria la ultima ya que se hace esto como dije anteriormente, no se si no lo leiste
Citarse la metes a los tres vertices sumandola contra la anterior que habia y la divides entre dos
saludos