Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Diseño sistema materiales

Iniciado por KneDa, 16 de Diciembre de 2011, 01:26:04 AM

« anterior - próximo »

KneDa

Saludos chicos, supongo que este tema no será nada nuevo, pero bueno, ahí va.

El caso es que estaba pensando en empezar a diseñar un sistema/arquitectura para definir materiales de manera flexible y rápida.

Pero la verdad, ando bastante perdido de como enfocarlo. Si alguien me pudiese mandar algún paper/link, o todavía mejor, darme algunas ideas de como orientar dicho sistema se lo agradecería.

En principio, lo que estaba pensando era algo así como un sistema de digamos meta-materiales. Es decir, por una parte tu definirás el meta-material (no se todavía como) , el cual contendrá todos los datos necesarios para poder procesarse y luego, un material concreto no será otra cosa que una instancia de dicho metamaterial. Basicamente, algo así como metamaterial(código) y material(datos).

Lo dicho, esas personas que trabajen a menudo con este tipo de sistemas o aquellos que se hayan peleado para su analisis/construcción... una ayudita, please ;)

Gracias por adelantado.

Gallo

Te recomiendo el capitulo 7.4 del libro Grame Programming Gems 7 (http://www.amazon.com/Game-Programming-Gems/dp/1584505273) , explica como crear un sistema de materiales basado en datos, osea en un XML con los parámetros del shader y tal. Es un sistema similar al de Unreal Engine, no por el Shader Tree que es otro tema, si no por el resultado generado que seria a parte de los shaders, un XML con la descripción del Material y otro XML que seria un Material Instance, que viene siendo una referencia a un material al que ya le das una serie de valores a los parámetros de entrada.

KneDa

Guau... ya van por la edición 7... si que ha triunfado este libro :D

Ok gallo, muchas gracias, es un comienzo ;)


KneDa

Jajaja, ya veo... yo me quedé en la 1 ;)

Oye, una cosilla, estás seguro que es en el gems 7 donde hablan de sistema de materiales? Lo pregunto porque viendo el índice acá http://introgamedev.com/resource_gpg7.html , parece ser que la sección 7 es sobre newtwork y multiplayer O_o

De todas formas, me parece carillo comprarme el libro solo por un capitulo ... no conoces algún paper free o buen artículo por internet q hablen sobre el tema? gracias, again :D

Vicente

Puede que se refiera al capitulo 4, a este articulo:

Support Your Local Artist - Adding Shaders to Your Engine

KneDa

Ah, si, seguramente... me he confudido al mirar ;)

Gallo

Juas, pues si, en eso ke me has pasado es la sección 4, en el que yo tengo sobre mi mesa ahora mismo es la 7 :S que raro, quizá sea otra edición.

KneDa

Jeje, pues seguramente sean ediciones distintas :) . De todas formas, lo que he comentado antes, aunque suena muy interesante ese capítulo y de echo que seguramente que lo explican genial esto, no voy a comprar el libro exclusivamente por leer el cap :)

Sin embargo, déjame pensar que en este foro hay más de una persona que ya se ha enfretado o se está enfrentando con la construcción de dichos sistemas. Así que, un breve resumen de como han enfocado la arquitectura no vendría mal. En principio tampoco estoy buscando nada muy avanzado, quiero decir, esos motores que dependiendo de las capacidades de la gráfica utilizarán unas técnicas soportadas u otras... Está pensado para que el motor corra con unas especificaciones gráficas mínimas.

De nuevo, gracias.

KneDa

Me han recomendado este, "3d Game engine Architecture", el cual está en google books http://books.google.es/books/about/3D_game_engine_architecture.html?hl=es&id=HmBZa9-7mewC .

Alguien que lo haya leído qué opinión le merece?

Es genial el google books para consultar alguna referencia/capítulo de algún libro. Aunque claro está, si te interesa lo mejor es adquirir una copia impresa

TrOnTxU

Voy a "reabrir" esto, para hacer una pregunta.

Estoy rehaciendo el sistema que tengo de materiales y surfaces shaders (que supongo que es algo parecido a lo que comentaba Gallo del GP7), y me preguntaba a que solución habias llegado tú al final, KneDa, que habias decidido, o si habias encontrado algun link más sobre el tema.

La verdad es que estoy un poco confuso también con algunas cosas, y no me gustaria tener que volver a reprogramar todo el subsistema otra vez porque algo no me" cuadre" luego, como me ha pasado ahora.

Un saludo y gracias.
Vicent: Linked-In  ***  ¡¡Ya tengo blog!!

KneDa

Pues mira, la verdad, la solución a la que he llegado es bastante sencilla de implementar y bastante versatil, pues te permite jugar con los materiales a tu antojo.

Me explico, cada modelo en mi engine tendrá diferentes partes (modelos jerárquicos) y cada parte del modelo tendrá una lista de materiales (punteros a materiales creados en el engine) , hay algunos engines por ahí que lo implementan a nivel de polígono pero para lo que estoy haciendo es suficiente tenerlo a nivel de parte.

Luego tu tienes que el engine es el encargado de hacer caché con los diferentes materiales, será el encargado de crear los materiales de la forma más óptima, importante esto en la web para no estar descargando datos todo el tiempo. Luego tienes que un material es una colección de datos necesarios para renderizar una parte, esto es, colección de shaders (vertex, fragment, geometry) , datos de entrada (uniforms y attributes) con valores por defecto, es decir, tu defines la interfaz del material que será útil si quieres mostrarlo en algún tipo de tool y modificar parámetros.

Al final, la cosa es bastante sencilla de usar, pues imagínate, tu tienes tu escena con todos los modelos cargados con 3 pasadas.

1º Pasada: El primer material de cada modelo será el material por defecto de cada modelo, material piedra, vidrio, madera... lo que sea...
2º Pasada: El segundo material de cada modelo será pues por ejemplo renderizar el depth buffer para hacer SSAO
3º Pasada: SSAO

Luego el engine proporciona funciones auxiliares para todo el tema de FBOs, Rtt y lo que sea... A mi me va bien, es muy sencilla la approach y bastante versatil... Suerte :)

TrOnTxU

Gracias por tu explicación :)

Verás, tengo algunas dudas sobre lo que has planteado, voy a explicar mi interpretación, bastante parecida a la tuya, pero posiblemente con algunas modificaciones.

En primer lugar, supongo que lo de "materiales por partes o por poligonos", te refieres a tener un mesh con varios sub-materiales (sub-meshes). Esto en mi engine es "indispensable", y asi lo tengo implementado.

En mi aproximacion un "surface shader" es lo que podriamos decir un material, y un Material Instance, una instancia de ese material.

Cada "surface shader" define los shaders que renderizan (estos shaders no están "acabados", ya que se combina su resultado para dar diferentes tipo: normal, skinned, multi-pass light, single-pass light, etc), los tipos de "uniforms" que acepta: diffuse, emissive, etc.., la "Render Layer" o "Layers" sobre la que trabaja (Default, Shadows, etc). Además para evitar la "explosion combinatoria" de los shaders, define que tipo de combinaciones de shaders puede tener.

Un material, en un principio, tiene una referencia a su "surface shader", una lista de uniforms, y estados de render (Alpha, Cull, Depth, etc). Los materiales se crean a partir de la funcion " MaterialManager::create_material( SurfaceShader::Handle shaderHandle )" con lo que se crea un "Material Instance" con los uniforms especificos del surface shader, además se copian los estados por defecto (Alpha, Cull, ...).


Y ahora mis preguntas:

1) ¿Vale la pena tener los estados de render (Alpha, Cull, etc) en cada "Material Instance" o los quito y dejo solo los de los "Surface Shader"? (De entrada pienso que me ahorraria cambios de estado al construir las "Display List" para el "render back-end")

2) La selección del tipo de shader (Skinned, Rigid, Lights , etc) me queda un poco "branchy code". ¿Alguien ha encontrado una buena solución para esto?

3) Los atributos dependen del tipo de mesh (por ejemplo pueden tener color en los vertices o no), lo que me lleva a una nueva selección del "shader program". ¿Alguna otra solución?

4) Yo guardo los "uniforms" como arrays estaticos. Divido en dos tipos de parametros en "escalares" (floats simples), y "vectoriales" (Vector4, aunque puedes coger los dos primeros floats, por ejemplo, para un vector2), ya que gasto no matrices (estos uniforms, como worldViewProj por ejemplo, los cambio desde el renderer-back-end, no desde el material), con lo que tengo que almacenar tambien las keys para obtener el parametros por nombre (U32 con el Crc32 de un string), y los indices de uniform del parametro en cuestion en el shader.
¿Alguna otra aproximacion?


5) Para utilizar varios "passes" los defines como varios materiales para el mismo modelo. Yo habia pensado en cambio de que el "surface shader" tuviera "la lista de pasos" especifica, luego hay unos "pass" especiales para acumulacion de depth, etc. que se realizan en otras "layers" del renderer.
¿Es mejor realizar los "todos los passes especificos del material del tiron", o dibujar todos los objetos por cada pass por separado como hago con los "passes especiales"?
En un principio, a mi me parece que puede depender de la arquitectura, pero no estoy seguro ¿Que pensais vosotros?


La verdad es que es un poco "trallada de olla" el sistema, pero no he encontrado demasiadas referencias, y esto me parece suficientemente flexible, aunque tengo alguna duda sobre la eficiencia de algunas cosas.


Un saludo, y gracias de nuevo
Vicent: Linked-In  ***  ¡¡Ya tengo blog!!

KneDa

Si, cuando digo partes me refiero a submeshes, en mi caso trabajo con simples meshes estáticas ya que para los casos de uso no se está contemplando nada como fracturas de meshes y no hace falta tener referencias a nivel de polígono.

En cuanto a las preguntas, evitando el tema de estados, que es algo que no me ha hecho falta en mi engine, te puedo aportar algunas ideas que te pueden ir bien.

3) Con respecto a los atributos, yo los defino en mi formato de modelo3d, por decirlo de otro modo, son los datos de salida que ofrece una malla. Ya después, será el engine el que se encargue de preprocesar y analizar la coherencia entre datos del modelos y requisitos de los materiales. En mi opinión, analizar los materiales y comprobar las coherencias con la malla debería hacerse en una etapa de preprocesado, ya que la funciones de query a la gpu son costosas y debería de evitarse en el loop rendering. A modo de ejemplo, en un determinado modelo, la malla tendría algo como esto (formato json):

Ej:    "attributes" : [
          { "datatype":"SHORT", "datasize":3, "offset":0, "normalized":true, "bind":"position"},
          { "datatype":"SHORT", "datasize":3, "offset":6, "normalized":true, "bind":"normal"},
          { "datatype":"SHORT", "datasize":2, "offset":12, "normalized":true, "bind":"diffuse_texture"}

4) Los uniforms, yo los divido de la siguiente forma, calculados o no calculados, si son calculados será el engine el encargado de proporcionar el resultado al shader, y si no, será el modelo que use la instancia de un material, todo ello, siempre manejando datos por defecto, ya que un modelo puede pasar o no datos de la instancia del material. Es bastante flexible tener este tipo de datos precalculados, si te fijas en rendermonkey hay bastantes datos precalculados y son muy útiles :)

Ej:     "uniforms" : {
        "mvp_transform": { "type":"float_mat4", "computed":{"source":"MODEL_VIEW_PROJECTION"}},
        "normal_transform": { "type":"float_mat3", "computed":{"source":"MODEL", "inverse":true, "transpose":true}},
        "ambient":  { "type":"float_vec4", "default": [0,0,0,1]},
        "diffuse":  { "type":"float_vec4", "default": [1,1,1,1]},
        "specular": { "type":"float_vec4", "default": [0,0,0,1]},
        "shiny":    { "type":"float", "default": 0 },
    }

5) Mmm, yo en mi engine defino algo así como un objeto pipeline. Una instancia del engine aceptará varios tipos de pipelines, en cada objeto pipeline tu defines como serán las etapas de rendering del engine (multipass rendering). De esta forma añadir y reusar pipelines es superrápido, tu puedes tener el pipeline donde se representen los objetos con los materiales sin filtrado, un pipeline donde añadas ssao, pipeline con deferred rendering, pipeline con non-photorealistic rendering... etc. Además, si quieres hacerte una tool donde defines un pipeline en base a nodos o lo que sea es inmediato.

Luego ya, a como hagas la lista de render final y las optimizaciones que le quieras meter ya depende de tu engine, pero las posibilidades son muy amplias.

De todas formas, esto de tener el sistema supergenérico en todo esto o un nivel de abstracción muy alto, en mi opinión, no siempre compensa. Quiero decir, fíjate en muchos juegos que han triunfado actualmente y no dejan de utilizar sistemas de materiales realmente simples, pero no les ha ido nada mal :D

Suerte y ánimo ;D

TrOnTxU

Gracias por la respuesta, esta muy bien explicado todo :D

Voy con los comentarios:

Primero: me mola mucho que utilices json, ... yo tambien :D ... bueno ... más o menos ... lo mio se llama LSON pero es una "copia barata" del SJSON de BitSquid, que esta basado en json, pero con una "syntaxis" más sencilla y parecida a Lua.
De todas formas, esto lo hago en el "development content", mientras utilizo el motor para desarrollo, luego lo paso por un compiler, y genera packs binarios con tablas de offsets y compresion opcional. Pero "durante el desarrollo" mola mucho utilizar este tipo de formato :D, aunque supongo que será lo típico para webGl, pero en fin ... mola :)


3) Muy buena idea, estoy de acuerdo con lo que has dicho, deberia haberlo decidido asi desde el principio y no rallarme.
Comprobaré el formato de la geometria contra la especificacion de entrada del "surface shader" solo al aplicar el material al objeto, y hago "saltar" un tipo de warning exception o lo que sea, y reemplazo el material "que no se puede bindar" por uno generico que funcione con el formato especificado. ¿Por ejemplo, no?

Aunque hay una cosa que no entiendo de tu descripcion:
{ "datatype":"SHORT", "datasize":3, "offset":0, "normalized":true, "bind":"position"},
¿la posición esta normalizada?


4) Perdón por la cuarta pregunta, creo que la he "liado" un poco, a veces no me sé explicar ^^
Preguntaba por como almacenar los datos de las "propiedades" (uniforms), pero no me he dado cuenta en en js no debe haber ese problema por la naturaleza "dinamica y no tipada" del mismo lenguaje.
En cuanto a los uniforms precalculados estoy de acuerdo, yo también hago eso, por eso decia que para almacenar "propiedades" del material solo gastaba scalares y vectores, pero no matrices porque todas son para "parametros precalculados" como el worldViewProj, la inversa de la vista, etc.
Mola la semantica que le das, es parecida como dices a RenderMonkey, y, en este sentido, bastante más "flexible" que la mia, ya que no "interpreto" diferentes nombres de uniforms para los "parametros precalculados", siempre el mismo.


5) Supongo que los "pipelines" que utilizas, seran algo parecido a los "layers" que utilizo yo.
Siguiendo tu consejo deberia "colectar" los "draw calls/pasos" de cada mesh por separado, y luego ordenarlos segun la especificación plataforma (ordenar por shader, front-back, back-front, etc), para enviarlos de tirón al back-end. ¿No?
Lo cual me parece una idea "fantastica", asi que voy a probar a hacer algo asi, ya tenia algún tipo de ordenación, pero los "multi-passes" se hacian seguidos, y igual no es una buena idea.


Gracias de nuevo por las respuestas.
Un saludo
Vicent: Linked-In  ***  ¡¡Ya tengo blog!!






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.