Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Sandra Engine 0.4 Y San Wrapper

Iniciado por DraKKaR, 22 de Septiembre de 2005, 02:20:04 PM

« anterior - próximo »

DraKKaR

 Buenas, acabo de subir la nueva versión de Sandra Engine. Como mayor novedad, a parte de incluir un renderer basado en iluminación por píxel y nurvas posibilidades con lso comandos de consola, es la inclusión de lo que he llamado San Wrapper.

Esto viene a raiz de un post que ya comentamos anteriormente (Teoria de Motores) en el que discutíamos la mejor manera de presentar el API del motor al usuario.

De esta manera hay 2 formas de usar el motor:

1- Usando el API del motor con todas sus clases y con la responsabilidad compartida con el motor sobre la liberación de recursos y gestión de memoria.

2- Usando San Wrapper (San viene de Sandra Simplified). Este wrapper oculta por completo todo el motor que tiene detrás y presenta al usuario un API en C llana. Además se encarga de la gestión completa de los recursos, de forma que se liberan limpiamente cuando no se necesitan. Con San Wrapper el usuario ya no trabajo con punteros que contienen objetos, sino que trabaja con identificadores opacos que apuntan indirectamente a objetos que están bien protejidos dentro del wrapper. Esto hace que la programación sea más simple, segura y productiva. A costa de perder algo de flexibilidad que normalmente no es necesaria en aplicaciones estándar.

He añadido un primer tutorial a la web del motor sobre San Wrapper, para que os hagais una idea de lo sencillo de usar que es (desde mi punto de vista). El tutorial es bastante simple, pero sirve de introducción. Más adelante pondré tutoriales más complejos para manejar mejor objetos. También podeis echarle una ojeadaal fichero san.h (desde el SDK o desde el CVS) para ver un poco todas las funciones que proporciona el wrapper.

Actualmente, el wrapper no expone toda la funcionalidad del motor, esto es algo que se irá mejorando con el tiempo (y con las propuestas de los usuarios).


Nada más, os agradecería que probarais el SDK o que echarais una ojeada al tutorial, ya que me sería de gran ayuda para obtener ideas, sugerencias y recoger fallos.


Trabajo futuro necesario:
- Mejorar el renderer de iluminación por píxel
- Mejorar las herramientas de exportación e importación de datos al motor

Como siempre, cualquier que quiera echar una mano en lo que sea tiene las puertas (y el código) totalmente abiertas.

Hasta luego!


AgeR

 Me parece muy interesante lo del San Mig... digoooo San Wrapper  :P

No lo he bajado todavía, pero viendo el primer tutorial, veo algo que puede mejorarse para hacer el wrapper mucho más fácil para cualquiera. A ver...
En vez de hacer que el usuario cargue una malla, y luego le asigne un material.... por que no creas una clase Actor y que el usuario, al crear el actor, le indique qué malla y materiales usa? De este modo puedes reusar más fácilmente las mallas y evitas al usuario tener que cambiarle un material a una malla.
Para esto, al renderizar, deberías añadir al mundo los Actores, y no las mallas. Así de primeras es lo que se me ocurre, pero facilitaría mucho el uso  :huh:

Otra cosa... tienes pensado crear un renderer DX8? Seguramente no, pero si lo haces podrías ganar algún que otro usuario. Por ejemplo muchos desarrolladores indie buscan motores potentes pero sencillos, y que sean versátiles a la hora de renderizar (DX8 es el máximo que se suele usar para juegos share). Si además haces rular el motor en Mac, seguro que haces que Zaelsius se ponga cariñoso contigo  :lol:

Venga, saludos megacrack!

DraKKaR

 Hola AgeR! Gracias por contestar!

Ummm... realmente al mundo no se añaden las mallas, sino Actores que usan esas mallas. Es decir:

Lo que hace sanWorldAddMesh es:

1- Crear un Actor (en el motor se llaman SpaceObject)
2- Agregar el actor al mundo
3- Hacer que el actor use la malla pasada como parametro

He querido meter todo esto dentro de la misma función por el afán de simplicidad que busco en San Wrapper. Aunque ahora que lo pienso puede inducir confusiones. Es decir, si llamas 100 veces a la función sanWorldAddMesh con la misma malla como parámetro no se repiten 100 mallas, sino que se crean 100 SpaceObject que apuntan a la misma malla.

Y con lo de los materiales no le veo el problema. También se pueden reutilizar las texturas:

SAN_TEXTURE2D tex = sanLoadTexture2D("tex.jpg");
sanMaterialTex2D(malla1, SAN_DIFFUSE_MAP, tex);
sanMaterialTex2D(malla2, SAN_DIFFUSE_MAP, tex);
sanMaterialTex2D(malla3, SAN_DIFFUSE_MAP, tex);
sanMaterialTex2D(malla4, SAN_DIFFUSE_MAP, tex);
sanMaterialTex2D(malla5, SAN_DIFFUSE_MAP, tex);


¿Es esto el problema que le veias?



Sobre le renderer de DirectX8: antaño tenía un renderer de OpenGL y otro en DirectX que implementaban la misma funcionalidad (Mars lo puede corroborar cuando trabajabamos en Blast (de hecho supongo que todavia podrias bajarlo y ver que están ahi los 2 renderers (Blast!))).
Sin embargo acabé trabajando más en el de OpenGL y el de DirectX ya no está actualizado a la última versión del motor.

De todos modos no veo porqué usar un renderer de DirectX gustaría más al usuario: se supone que el motor te abstrae del API y no sabes (ni necesitas saber) si trabajas en OpenGL, DirectX o por software. Aunque si alguien se anima a hacer un renderer de DirectX que soporte iluminación por pixel puedo ayudar en todo lo que pueda con la interfaz.

PD: No tengo MAC para probarlo O_O, además está a medias el port para linux que un día tuve y con el tiempo perdí.


Gracias por tus críticas, ¿más comentarios al respecto?


Pensamiento: Al igual que un motor 3D te abstrae del API gráfico... ¿sería posible crear un API que te abstrayera del motor gráfico (como lo hace San Wrapper), de forma que pudieras elegir usar un motor u otro? Es decir, ¿alguien podría compilar San Wrapper para que hiciera llamadas a OGre (por ejemplo) en vez de a Sandra Engine? Yo lo veo factible (hasta cierto punto).

Pogacha

 Eso del San Wrapper esta por demas interesante ... no te molesta que te robe la idea?

AgeR

 Vale, si es como dices, entonces es un problema de nomenclatura simplemente. En vez de sanWorldAddMesh debería ser algo como sanWorldAddActor (Actor queda más intuitivo que SpaceObject  ;) ).
Lo de las texturas.... cuando haces:
sanMaterialTex2D(malla1, SAN_DIFFUSE_MAP, tex);
sanWorldAddMesh(malla1);
sanWorldAddMesh(malla1);

Ahí se crean 2 "actores" que usan la misma malla, pero... también usan la misma textura?
Para mí, lo ideal sería que un objeto no tuviera asignada ninguna textura, que la tuviera directamente el "actor", y en el renderizado se activara su textura y se usara la malla que tuviera asignada.
No sé si me explico. Igual es lo que haces y no me he enterado (acabo de levantarme XD).

Lo del renderer DX8 te lo decía porque algunos de los posibles usuarios del motor pueden ser desarrolladores indie por ejemplo. En el mercado share, es mucho más habitual trabajar con dx8 que con opengl, por temas de drivers. Si les das dx8 y opengl, y además tú o alguien (zaelsius?  :rolleyes: ) lo porta a mac, yo creo que puedes conseguir una buena base de usuarios.

Miki

 En realidad esta es la forma "buena" de trabajar en cualquier motor decente. Tener 2 niveles de acceso/programación en el engine es vital, ya que unos usuarios (los más novatos) se limatarán a usar el de alto/sencillo nivel, y los programadores pro intentarán pelearse más con la parte de bajo nivel (más difícil pero más flexible y kizás te permita optimizar más algunos aspectos del juego).
Si el motor es muy sencillo (un motor solo 2D por ejemplo) es muy posible k no necesite de esta caracteristica, más cuando esté bien estructurado desde el principio.

DraKKaR

 
CitarEso del San Wrapper esta por demas interesante ... no te molesta que te robe la idea?

Trankilo pogacha, para algo el proyecto es Open Source.... haz lo que la LGPL te permita ;)
De todos modos, ¿que tienes en mente?Quizá podamos unir fuerzas.


AgeR, en mi motor hay varios tipos de objetos "añadibles" al mundo:


  • SpaceObject: Son objetos que se mueven en el espacio 3D, con todo lo que ello conlleva.
  • PhysiqueObject: Son una especialización de lso SpaceObject pero que ofrecen cálculo de físicas.
  • ScreenObject: objetos que se mueven por la pantalla.
  • WorldObject: Objetos añadibles al mundo que pueden ofrecer una funcinoalidad pero que no tienen porque representarse.
Realmente no sé que problemas pueden¡ tener esa nomenclatura. La palabra actor me suena más un personaje que a un objeto genérico.



CitarLo de las texturas.... cuando haces:
sanMaterialTex2D(malla1, SAN_DIFFUSE_MAP, tex);
sanWorldAddMesh(malla1);
sanWorldAddMesh(malla1);

Ahí se crean 2 "actores" que usan la misma malla, pero... también usan la misma textura?

Claro, la textura es la misma, la que has cargado con sanLoadTexture2D().

CitarPara mí, lo ideal sería que un objeto no tuviera asignada ninguna textura, que la tuviera directamente el "actor", y en el renderizado se activara su textura y se usara la malla que tuviera asignada.
No sé si me explico. Igual es lo que haces y no me he enterado (acabo de levantarme XD).

Eso es un dilema que tuve un tiempo: la malla representa la forma de un objeto: com se ve en pantalla, por lo que es mas o menos lógico que también guarde qué textura debe utilizar para representarse. Por otra parte, si los parámetros de representación (como la opacidad, la textura,...) se almacenan en el SpaceObject (actor ;) se obtiene más flexibilidad ya que puedes pintar la misma malla con diferentes texturas o propiedades. Sin embargo, puede que se pierda en comodidad, porque si quieres que 100 objetos usen la misma malla y el mismo material, deberías especificar malla y material para cada uno de ellos, en vez de simplemente una malla para cada uno (donde está el material almancenado).

Puede que sea interesante guardar el material tanto en la malla como en el SapceObject (actor). Y que sea decidible cual de las 2 usar, o que uno override a otro. Sin embargo, un SpaceObject no tiene porque usar una malla para representarse (sino que peude usar cualquier DisplayObject ;), y puede que la forma de representarse que tenga no necesite un material.

Es interesante... ¿Que opinais de todo esto?


Ager: puede que recoja el código que tenia de DirectX y lo adapte a la nueva versión, aunque cualquier es libre de hacerlo  :D

Miki: Coincido plenamente contigo. De todos modos, cuando San Wrapper ofreza toda la funcionalidad que debe, debería ser díficil encontrar una razón para usar el API plano de Sandra Engine, que podría limitarse a la creación de plugins y renderers, oa usar el motor de una forma extraña, para lo que el wrapper no esté pensado. Sobre el tema de rendimiento, no debe haber ninguna diferencia de rendimiento respectgo a usar el API del motor directamente.

Haddd

 nosotros utilizamos materiales asociados al MeshObject. La estructura es esta:

MeshObject ( Contenedor de mesh y materiales que almacen la matriz WorldSpace)
|
|-> Material ( texturas y datos del material asociados)
|
|-> Mesh ( conjunto de vértices e índices)

De esta forma podemos reutilizar materiales y meshes.

Lo que vosotros decís implica que dentro de Mesh haya un material por defecto, que si no está asociado a MeshObject, se utilice. Yo creo que es una buena idea, sólo añade funcionalidad... ;)  

AgeR

 Ajá. Decididamente luego me lo bajo y lo escudriño a fondo, porque pinta muy bien.

Sobre la textura, es la única cosa que (para mí) falla. Claro que también tú estás haciendo un motor para todo tipo de aplicaciones, y no exclusivamente juegos. En un juego es muy normal que un objeto pueda representarse con varias texturas diferentes, para, aprovechando una misma malla, tener por ejemplo 10 enemigos distintos, donde distintos implica cambiar la textura, propiedades del material, o lo que sea.
Donde digo enemigo, igual se podría decir árbol, pedrusco, casa fantasticomedievalcontoquesfuturistas, o lo que sea  :lol: .


DraKKaR

 Ager, entiendo lo qie dices, y ahora mismo en el motor se podría resolver de la siguiente forma:

Realmente un Mesh de Sandra Engine NO guarda vértices ni geometría, sino que guarda una referencia a 2 objetos VertexData y VertexIndices. Teniendo esto en cuenta, si queremos que un mismo Mesh tenga diferentes materiales sin repetir geometría se puede hacer lo siguiente:

1- Cargar la geometria de la malla en 2 objetos VertexData y VertexIndices-
2- Crear tantas mallas como diferentes materiales.
3- Asignar a cada una de estas mallas el vertexdata y vertexindices para que usen la misma geometría.
4- Asignar a cada malla un material distinto.

De esta manera cada malla tiene su propio material que indica como representarse, y NO se repite nada en memoria, peusto que solo hay una instancia de objetos VertexData y VertexIndices compartida por todas las mallas.

Haddd: esa es otra manera de hacerlo, supongo que depende del resto de la estructura del motor y de como vea cada uno las cosas.

Sí, los objetos que usan material (como las mallas o los billboards) tienen un material por defecto, que no contiene ningún mapa y define el color diffuse como blanco y la opacidad a 1.

Xam

 
QUOTE (Haddd)

nosotros utilizamos materiales asociados al MeshObject. La estructura es esta:


MeshObject ( Contenedor de mesh y materiales que almacen la matriz WorldSpace)
|
|-> Material ( texturas y datos del material asociados)
|
|-> Mesh ( conjunto de vértices e índices)

De esta forma podemos reutilizar materiales y meshes.
[/quote]

Bajo mi punto de vista. La organización interna que explica Haddd me parece la más lógica.

De todas formas yo utilizaría una especie de "managers" para cada uno de los recursos del motor. A éstos se les podría solicitar elementos por copia o por referencia (evitando mantener en memoria elementos repetidos de manera innecesaria). Estos "managers" se encargarían de inicializar (y más tarde liberar) las referencias necesarias para los distintos objetos que se quieran cargar. Creo que esto solucionaría de una manera elegante la gestión de recursos tanto para el modo San Wrapper como para el modo "normal".

DraKKaR

 En el motor todos los objetos se pasan por referencia y se eliminan automaticamente cuando no se necesitan (gracias a boost::shared_ptr<>). Si quieres una nueva instancia de un objeto puede usar la clase sandra::PrimitiveFactory que te creará una nueva instancia.

Haddd

 Hasta hoy no he podido echarle un vistazo a tu motor. Te felicito, es un trabajo titánico e incluso tiene física, increíble, realmente increíble. Sería una suerte haber contado contigo para Haddd, porque tienes que tener unos conocimientos realmente envidiables. :)

Voy a poner el código de tu ejemplo 2 y el código de cómo sería algo parecido con Haddd, para que compares. Porque creo que a ti te falta utilizar tu propio engine. En eso Haddd tiene mucha experiencia por los vídeos. No sólo sirven para mostrar a la gente lo que puede hacer el motor, también sirven para darte cuenta de lo fácil o lo difícil que es hacer ciertas cosas con el motor. Eso no ha hecho resstructurar el código unas cuantas veces... :(


sanInit();
sanInitVideo("../../plugins/render_ogl_sm1.dll",800,600,32);
sanInitInput();
sanInitWorld();

sanLoadMapTextures("../../samples/media/sponza.sgemap","../../samples/media/");
sanEnable(SAN_LIGHTING);
sanLightMul(50000);

sanCamera(SAN_CAMERA_POS, 0,100,20);
sanCamera(SAN_CAMERA_LOOKAT, 0,105,0);
sanCameraType(SAN_CAMERATYPE_ORBIT);
sanCamera(SAN_PLANES, 0.1, 1000.0, 0.0); // SAN_PLANES x=near y=far z=?
sanCameraOrbit(SAN_CAMERAORBIT_SPEED,100.0f);

sanAddLight(400,10,50, 1,0,0, 10);

while(1){
 if (sanKeyPressed(SAN_KEY_ESCAPE))
  break;
 if (!sanUpdate())
  break;
}
sanFree();


Eso sería con Haddd crear un objeto


HMeshObject MeshObject = Haddd.Scene.MeshObjects.Create("pared");
MeshObject.CastShadows = false;

MeshObject.Mesh.Creation.Rectangle(20, 20, 2, 2, HCreateRectangle.XY, false, 3f, 3f);

MeshObject.Material = new HMaterial[1];
MeshObject.Material[0] = new HMaterial();
HMaterialLayer layer = new HMaterialLayer();
MeshObject.Material[0].AddLayer(layer);
layer.DiffuseMap.Texture = Haddd.Video.Textures.Create2D("rust", true);
layer.NormalMap.Texture = Haddd.Video.Textures.Create2D("rust_normal", true);
layer.NormalMap.Enabled = true;
layer.NormalType = HNormalType.Mapping;
MeshObject.Material[0].Layers[0].LightingFragment = Haddd.EffectFragments.FindFirst("falloff");

MeshObject.Position = new Vector3(0.5f,1.0f,0);

// Creams una luz omni

omni = (HOmniLight)Haddd.Scene.Lights.Create("omni01", HLightType.Omni);
omni.Position = new Vector3(0f, 1.0f, -2.0f);
omni.Color = new HColor(1.0f, 1.0f, 0.0f, 1.0f);
omni.Multiplier = 1.3f;
omni.AffectDiffuse = true;
omni.AttenuationType = HLightAttenuationType.DualRadius;
omni.FarAttenuationStart = 7.0f;
omni.FarAttenuationEnd = 10.0f;
omni.CastShadows = true;
omni.Enabled = true;




La principal ventaja del sistema que nosotros utilizamos es que pulsando el . gracias al intellisense, el programador tiene acceso a todas las propiedades y métodos de la clase, con su descripción. Con el estilo C que tu utilizas, tiene que memorizar los métodos y las definiciones.

Es decir, puedes coger el ejemplo que te he puesto y fácilmente, por ejemplo, serás capaz de activar las sombras ( hay una propiedad para ello) sin haber leido nada. Pero con tu método vas a tener que echar mano de la documentación. Añade a esto la complejidad de un motor y creo que el método C++ es muucho más productivo.

Yo pensaba que San Wrapper era un wrapper pero en C++, para facilitar la vida al desarrollador. Pero así como lo has enfocado, creo más bien que es una vuelta atrás.

Tus motivos tendrás para hacerlo así, yo sólo te doy mi opinión, que se que será bien recibida.

Un saludo.  ;)  

DraKKaR

 
CitarHasta hoy no he podido echarle un vistazo a tu motor. Te felicito, es un trabajo titánico e incluso tiene física, increíble, realmente increíble. Sería una suerte haber contado contigo para Haddd, porque tienes que tener unos conocimientos realmente envidiables.

Gracias Haddd, viniendo de tí me halaga. Aunque la física no la implementé yo, sino que uso ODE  :D. Y como ya hace tiempo que no la uso, se ha quedado un poco desactualizada y ya no va tan fina como antes  :(

Realmente, al principio también me hice la pregunta sobre como debía ser el wrapper: C++? C? Queriendo hacerlo muy simple de usar me inspiré en el API de OpenGL y del propio ODE (que tiene una interfaz C pero está programado internamente en C++). Además, me gusta mucho que el usuario no trabaje con punteros a nada, sino con identificadores opacos que maneja internamente el Wrapper. Creo que esto da mucha estabilidad al sistema.

Sin embargo, como bien dices, usar el motor con funciones llanas puede que lo haga a veces un poco enrevesado. Puede que fuera mejor hacerlo en C++, teniendo clases que encapsulen al identificador que representa al objeto y que ofrezca una serie de funciones que le afecten. Pero todo esto sin utilizar punteros. De esta manera se conseguiría algo un poco mas organizado y seguramente más sencilo de utilizar.

Realmente no se como enfocarlo, puede que todo dependa de gustos... ¿que opina el resto de stratosfericos?

PD: Puede que la solución sea hacer una tercera API que sería San Wrapper ++  :D  

Xam

 Como ya he comentado, la organización interna que expuso anteriormente Haddd si me parece la correta. Ahora, la forma de llevarla a cabo no me parece, ni mucho menos, la más idónea. El motivo de utilizar "intellisense" no me parece una razón de peso como para apoyarse en ella para diseñar la interfaz con el motor.

De todas formas, ninguna de las formas me parece la más acertada.

QUOTE (DraKKaR)

Sin embargo, como bien dices, usar el motor con funciones llanas puede que lo haga a veces un poco enrevesado. Puede que fuera mejor hacerlo en C++, teniendo clases que encapsulen al identificador que representa al objeto y que ofrezca una serie de funciones que le afecten. Pero todo esto sin utilizar punteros. De esta manera se conseguiría algo un poco mas organizado y seguramente más sencilo de utilizar.
[/quote]

Creo que con esto estás dando en el clavo. Y si además, esas clases las gestionas con los "managers" que he comentado anteriormente ya te quedaría redondo. Todo esto sería para organización interna. Luego, sobre esto ya se podría utilizar algo parecido al San Wrapper (en combinación con algún lenguaje script) para facilitar, de verdad, el uso del motor por gente ajena al mismo.






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.