(http://juegaencasa.com/haddd/fotos/6.Jpg)
#region Using directives
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using Microsoft.DirectX;
using Microsoft.DirectX.DirectSound;
using Microsoft.DirectX.Direct3D;
using Microsoft.DirectX.DirectInput;
using HadddEngine;
using HadddEngine.Video;
using HadddEngine.Core;
using HadddEngine.Maths;
using HadddEngine.Scene;
using HadddEngine.Scene.MD5;
using HadddEngine.Physics;
using HadddEngine.Particles;
using HadddEngine.Sound;
using HadddEngine.Tools;
#endregion
namespace Tutorial
{
/// <summary>
/// Este ejemplo nos enseñará a crear objetos y asignarle propiedades
/// físicas
/// Al no indicar cámara, el motor utiliza una cámara de primera persona por defecto
/// que se maneja con las teclas WASD y el ratón.
/// </summary>
public class HTutorial : HMain
{
#region Campos
/// <summary>Rigid body referido a la esfera</summary>
HRigidBody sphereBody;
#endregion
#region Constructores
public HTutorial()
{
}
#endregion
#region Init
/// <summary>
/// Este método se llama por el motor una vez que se ha creado el device
/// </summary>
/// <param name="form">Formulario que se utiliza como ventana</param>
/// <returns>true si todo ha ido bien</returns>
public override bool InitGame(Form form)
{
// Creamos los objetos de fuentes y texturas...
Haddd.AfterCreateDevice();
// Cargamos texturas, escenas, shaders...por defecto
Haddd.LoadCreateInHouse();
#region Objetos
// Activamos el sistema de físicas de Newton
Haddd.Physics.Create();
CreateGround();
CreateCubes();
CreateSphere();
#endregion
#region Luz
// Creo una luz omnidireccional
HOmniLight light = (HOmniLight)Haddd.Scene.Lights.Create("light", HLightType.Omni);
// Asigno su posición
light.Position = new Vector3(0, 0, -2f);
// La intensidad
light.Multiplier = 1f;
// La atenuación
light.AttenuationType = HLightAttenuationType.DualRadius;
// La distancia a la que empieza a atenuarse
light.FarAttenuationStart = 1f;
// La distancia a la que se atenua completamente
light.FarAttenuationEnd = 2f;
// El color
light.Color = HColor.Yellow;
// Si afecta al diffuse del material
light.AffectDiffuse = true;
// Si afecta al specular del material
light.AffectSpecular = true;
// Por ahora, que no genere sombras
light.CastShadows = false;
// Ponemos la luz ambiente
Haddd.Scene.Lights.Ambient = new HColor(0.4f, 0.4f, 0.4f);
#endregion
Haddd.Scene.Camera.Position = new Vector3(0, 1f, -6f);
// Una vez que todo está preparado, iniciamos el motor
Haddd.Begin();
// Creamos la clase input para gestionar el teclado y el ratón
Haddd.CreateInput();
return true;
}
#endregion
#region Creation
void CreateGround()
{
// Ahora crearé un cubo que nos hará de suelo
Vector3 size = new Vector3(10f, 1f, 10f);
HMesh groundMesh = HMesh.CreateCube24Vertices(size);
HMeshObject ground = Haddd.Scene.MeshObjects.Create("ground", false);
// Ahora asociamos el mesh con el meshobject
ground.Mesh = groundMesh;
// Creamos un array de materiales de 1 elemento.
HMaterial[] material = new HMaterial[1];
material[0] = new HMaterial();
// Creamos la capa
HMaterialLayer layer = new HMaterialLayer();
// Lo añadimos al material
material[0].AddLayer(layer);
layer.DiffuseMap.Texture = Haddd.Video.Textures.Create2D("Pared_Difusse", true);
// Asignamos a nuestros HMeshObject el materal que acabamos de crear
ground.Material = material;
// En Newton, primero debemos definir un objeto "colisionable" dando la
// forma de este objeto.
HCollision collision=new HCollision();
// Tendrá el mismo tamaño que el utilizado al crear el mesh
// PUESTO QUE EN NEWTON, LA UNIDAD ES EL METRO, IGUAL QUE EN HADDD
collision.CreateBox(ref size);
// Ahora creamos un Rigibd body que son los objetos que tienen
// asociado el tipo de colision y todas las propiedades físicas
// Asociamos el objeto collision creado y el HMeshObject
HRigidBody body = Haddd.Physics.RigidBodies.Create(collision, ground);
// Indicamos la masa
// En Newton un objeto de masa 0 se considera un objeto estático
// Es decir, se puede colisionar con él, pero este no reacciona a nada
body.Mass=0f;
// Necesitamos indicar una matriz. No utilizamos la misma que en
// el meshobject porque podemos tener rigidbodies NO asociados a una
// malla y por eso tenemos que asignar la matriz en lugar de utilizar
// la del propio HMeshObject
// En nuestro caso, queremos que la parte superior del suelo esté
// en la y=0, por ello indicamos el centro y del objeto=-size.Y/2
Matrix matrix = Matrix.Translation(new Vector3(0,-size.Y/2, 0));
body.SetMatrix(ref matrix);
// Ya no utilizamos más la colision así que la liberamos
collision.Release();
}
void CreateCubes()
{
HMesh cubeMesh = HMesh.CreateCube24Vertices(0.5f, 0.5f, 0.5f);
// En Newton, primero debemos definir un objeto "colisionable" dando la
// forma de este objeto.
// Como el objeto collision es el mismo para todos los cubos
// basta crearlo aquí y reutilizarlo
HCollision collision = new HCollision();
// Tendrá el mismo tamaño que el utilizado al crear el mesh
// PUESTO QUE EN NEWTON, LA UNIDAD ES EL METRO, IGUAL QUE EN HADDD
collision.CreateBox(0.5f, 0.5f, 0.5f);
float x, y;
// Vamos a crear cubos apilados...
for (int px = 0; px < 2; px++)
{
for (int py = 0; py < 6; py++)
{
x = (float)px;
y = (float)py;
// Colocamos los cubos de forma que estén centrados
// y uno encima del otro
Vector3 pos = new Vector3(-0.25f + (x * 0.5f), 0.25f + (y * 0.5f), 0);
HMeshObject cube = Haddd.Scene.MeshObjects.Create("cube"+px.ToString()+py.ToString(), false);
// Ahora asociamos el mesh con el meshobject
cube.Mesh = cubeMesh;
HMaterial[] material = new HMaterial[1];
material[0] = new HMaterial();
// Creamos la capa
HMaterialLayer layer = new HMaterialLayer();
// Lo añadimos al material
material[0].AddLayer(layer);
layer.DiffuseMap.Texture = Haddd.Video.Textures.Create2D("brick_d", true);
// Asignamos a nuestros HMeshObject el materal que acabamos de crear
cube.Material = material;
// Ahora creamos un Rigibd body que son los objetos que tienen
// asociado el tipo de colision y todas las propiedades físicas
// Asociamos el objeto collision creado y el HMeshObject
HRigidBody body = Haddd.Physics.RigidBodies.Create(collision, cube);
// Indicamos la masa
body.Mass = 4f;
// Necesitamos indicar una matriz. No utilizamos la misma que en
// el meshobject porque podemos tener rigidbodies NO asociados a una
// malla y por eso tenemos que asignar la matriz en lugar de utilizar
// la del propio HMeshObject
Matrix matrix = Matrix.Translation(pos);
body.SetMatrix(ref matrix);
}
}
collision.Release();
}
void CreateSphere()
{
// Ahora crearé una esfera
float radius=0.3f;
HMesh sphereMesh = HMesh.CreateSphere(radius, 20, 20);
HMeshObject sphere = Haddd.Scene.MeshObjects.Create("sphere", false);
// Ahora asociamos el mesh con el meshobject
sphere.Mesh = sphereMesh;
// Creamos un array de materiales de 1 elemento.
HMaterial[] material = new HMaterial[1];
material[0] = new HMaterial();
// Creamos la capa
HMaterialLayer layer = new HMaterialLayer();
// Lo añadimos al material
material[0].AddLayer(layer);
layer.DiffuseMap.Texture = Haddd.Video.Textures.Create2D("mancha", true);
// Asignamos a nuestros HMeshObject el materal que acabamos de crear
sphere.Material = material;
// En Newton, primero debemos definir un objeto "colisionable" dando la
// forma de este objeto.
HCollision collision = new HCollision();
collision.CreateSphere(radius, radius, radius);
// Ahora creamos un Rigibd body que son los objetos que tienen
// asociado el tipo de colision y todas las propiedades físicas
// Asociamos el objeto collision creado y el HMeshObject
HRigidBody body = Haddd.Physics.RigidBodies.Create(collision, sphere);
// Indicamos la masa
body.Mass = 40f;
// Indicamos poca resistencia al aire
body.LinearDamping = 0.01f;
// Especificamos la matriz
Matrix matrix = Matrix.Translation(new Vector3(0,radius,-3.5f));
body.SetMatrix(ref matrix);
// Ya no utilizamos más la colision así que la liberamos
collision.Release();
// indicamos a la variable global que este es el body que utilizaremos
sphereBody = body;
}
#endregion
#region Action
/// <summary>
/// Este método se llama en cada fotograma y es donde debemos
/// indicar los eventos de teclado y la acción del juego
/// </summary>
/// <returns>true=continuamos; false=salir de la aplicación</returns>
public override bool Action()
{
// ¿Salimos de la aplicación?
if (Haddd.Input.Keyboard.KeyPressed(Key.Escape)) return false;
// Si pulsa la G activamos / desactivamos los gizmos
// La diferencia entre KeyTouch y KeyPressed es que KeyTouch sólo devuelve
// true cuando la tecla se presiona por primera vez, y no siempre que está presionada
// como es el caso de KeyPressed
// KeyTouch actuaría como un teclado normal, devolviendo true sólo 1 vez por
// cada pulsación de tecla
if (Haddd.Input.Keyboard.KeyTouch(Key.G))
Haddd.Scene.ShowGizmos = !Haddd.Scene.ShowGizmos;
// Si pulsa la P puede ver los objetos de colision de Newton
if (Haddd.Input.Keyboard.KeyTouch(Key.P))
Haddd.Physics.Debug = !Haddd.Physics.Debug;
// Si pulsa la I añadimos impulso a la esfera
if (Haddd.Input.Keyboard.KeyTouch(Key.I))
sphereBody.AddImpulse(new Vector3(0, 0, 3f));
// Todo correcto, continuamos
return true;
}
#endregion
#region Render
/// <summary>
/// Este es el método de renderización
/// </summary>
public override void Render()
{
// Preparamos la escena para que empiece el render
Haddd.Scene.Begin();
{
// Renderizamos todos los elementos de la escena
Haddd.Scene.Render();
// Realizamos la postproducción
Haddd.Scene.ProcessPostProduction();
// Renderizamos diversas cosas de la escena (gizmos, Axes, Names...)
Haddd.Scene.RenderMiscellaneous();
// Obtenemos acceso a la 1ª fuente. El motor por defecto crea una fuente
HFont fuente = Haddd.Video.Fonts[0];
// Iniciamos la renderización de las fuentes
Haddd.Video.Fonts.Begin();
// Escribimos texto en la primera línea, posición x=0, color amarillo
fuente.RenderLine(Haddd.Version + ". Press ESC to exit. Press G to Show/Hide Gizmos.", 0, HColor.Yellow);
// Escribimos texto en la segunda línea, posición x=0, color amarillo
fuente.RenderLine(Haddd.Video.Render.Stats.Fps + " FPS", 0, HColor.White);
fuente.RenderLine("Press P to show Physic collisions", 0, HColor.Yellow);
fuente.RenderLine("Press I to add impulse", 0, HColor.Yellow);
// Finalizamos la renderización de las fuentes
Haddd.Video.Fonts.End();
}
// Terminamos la escena
Haddd.Scene.End();
}
#endregion
}
}
Pensaba que era un poco largo, pero lo lei detenidamente y tal vez soy yo que no me acostumbro a la sintaxys del C# ...
Supongo que el IDE automaticamente resalta la region que se quiere ver, así en texto plano cuesta un poco darse cuenta de cuando se esta hablando de fisica y cuando de otra cosa.
Saludos.
Muy bueno.
Por curiosidad, cuáles son las especificaciones del ordenador del cual surgió el snapshot con 70 FPS?
AMD 1800+ Radeon 9500.
El motor hace muchas pasadas para conseguir el resultado final. Evidentemente los fps bajan, sin embargo, no variaría mucho más si pusieras más luces y más polígonos. Es por la arquitectura que utilizamos ;)
Viendo estos tutoriales siento electricidad acumulada en las puntas de mis dedos, tengo ganas de empezar a utilizar vuestro motor para implementar unas cuantas ideas que tengo en mi mente saturada (genial) (por ejemplo un modelador de personajes bipedos a base de parámetros, un entorno para programar bots "inteligentes" aplicando diferentes técnicas de IA (p.e. NEAT - Evolving Neural Networks Through Augmenting Topologies)
Enhorabuena!
Esa es la idea de Haddd. Que tu puedas programar de una forma sencilla, simplemente activando / desactivando flags. Aunque eso es a costa de FPS, yo creo que permite en muy poco tiempo tener resultados espectaculares. Espero también que la gente colabore a detectar los errores y a mejorar el motor, como pasó con Irrlitch y OGRE.
(ole)
Pues acabo de adquirir una gf6200 (ya sé que no es gran cosa) así que por fin podré disfrutar de vuestro motor cuando lo saquéis, y podré trastear con él, que ya hay ganas (uoh)
El tutorial, visto por encima parece sencillo y sobre todo corto. Me ha sorprendido que no haya que hacer muchas virguerías para aplicar las físicas (ole)
Vaya pues si que era verdad que lo hicisteis facil para usar (ole) . Si teneis algo de tiempò :ph34r: estaria cojonudo que explicaseis un poco como hicisteis lo de la lampara del video 3 (musseum), a mi personalmanete me gusto mucho
Claro, haré un tutorial avanzado sobre ello ... :P
Ya lo tienes, me falta pulirlo y documentarlo un poco mejor... :P
(http://juegaencasa.com/haddd/fotos/7.Jpg)
#region Creation
void CreateScene()
{
// Cargamos el eslabón. Necesitamos escalarlo al cargar
float scale = 1f / 50f;
HImport.Haddd.Load("link",scale);
// Accedemos al 1er elemento de los objetos que se acaban de cargar
linkMeshObject = HImport.Haddd.MeshObjects[0];
// Construimos la cadena de la izquierda
BuildChain(new Vector3(0,4,0),ref leftChain,"l");
// Construimos la cadena de la derecha
BuildChain(new Vector3(1, 4, 0), ref rightChain, "r");
// El eslabon que se carga, lo ocultamos puesto que ya tenemos
// las cadenas creadas y este nos sobra
linkMeshObject.Hide = true;
// Creamos la lámpara
CreateLamp();
}
void BuildChain(Vector3 pos,ref chain chain,string prefix)
{
HRigidBody parent = null;
float linkHeight = linkMeshObject.BoundingBox.Height;
HCollision colision = new HCollision();
// Creamos un objeto de colision del mismo tamaño que el eslabon
colision.CreateSphere(linkMeshObject.BoundingBox.Width / 2f, linkHeight / 2f, linkMeshObject.BoundingBox.Depth / 2f);
float rotacionY = 0;
for (int i = 0; i < 10; i++)
{
// Clonamos el eslabón original, dándole un nuevo nombre
HMeshObject mesh = linkMeshObject.Clone("link" + prefix + i.ToString());
// asignamos la posición al nuevo meshobject
mesh.Position = pos;
// Creamos un RigidBody
HRigidBody body = Haddd.Physics.RigidBodies.Create(colision, mesh);
// Le damos una masa y la inercia
body.SetMassMatrix(5f, 1f, 3f, 0.5f);
// Creamos la matriz del body
Matrix m = Matrix.RotationY(rotacionY) * Matrix.Translation(pos);
body.SetMatrix(ref m);
// Ahora crearemos un joint de tipo Ball and Socket
HBallJoint joint;
joint = new HBallJoint(
pos + new Vector3(0, linkHeight / 2, 0), // Indicamos la posición donde se establece el punto de contacto EN COORDS MUNDO
new Vector3(0, 1f, 0), // El eje de rotación
Geometry.DegreeToRadian(0), // Permitimos la rotación absoluta
0, // Permitimos la rotación absoluta
body, // El rigidBody que se asocia a este joint
parent // el padre del que depende este joint
);
// En el próximo joint, este será el padre
parent = body;
// bajamos un poco el eslabon pero no completamente para que así de la impresión
// de que está unido
pos.Y -= linkHeight * 0.8f;
// Los eslabones van alternando su rotación para que parezca una cadena
if (rotacionY == 0)
rotacionY = Geometry.DegreeToRadian(90f);
else
rotacionY = 0f;
// Guardamos los valores para después poder crear los joints de
// la lámpara
chain.linkBody = body;
chain.finalPos = pos + new Vector3(0, linkHeight / 2, 0);
}
colision.Release();
}
void CreateLamp()
{
// Ahora crearé un cubo que nos hará de lámpara
Vector3 size = new Vector3(2f, 0.4f, 1f);
HMesh mesh = HMesh.CreateCube24Vertices(size);
HMeshObject lamp = Haddd.Scene.MeshObjects.Create("lamp", false);
// Ahora asociamos el mesh con el meshobject
lamp.Mesh = mesh;
// Creamos un array de materiales de 1 elemento.
HMaterial[] material = new HMaterial[1];
material[0] = new HMaterial();
// Creamos la capa
HMaterialLayer layer = new HMaterialLayer();
// Lo añadimos al material
material[0].AddLayer(layer);
layer.DiffuseMap.Texture = Haddd.Video.Textures.Create2D("Pared_Difusse", true);
// Asignamos a nuestros HMeshObject el materal que acabamos de crear
lamp.Material = material;
// En Newton, primero debemos definir un objeto "colisionable" dando la
// forma de este objeto.
HCollision collision=new HCollision();
// Tendrá el mismo tamaño que el utilizado al crear el mesh
// PUESTO QUE EN NEWTON, LA UNIDAD ES EL METRO, IGUAL QUE EN HADDD
collision.CreateBox(ref size);
// Ahora creamos un Rigibd body que son los objetos que tienen
// asociado el tipo de colision y todas las propiedades físicas
// Asociamos el objeto collision creado y el HMeshObject
HRigidBody body = Haddd.Physics.RigidBodies.Create(collision, lamp);
// Indicamos la masa
body.Mass=50f;
// Necesitamos indicar una matriz. No utilizamos la misma que en
// el meshobject porque podemos tener rigidbodies NO asociados a una
// malla y por eso tenemos que asignar la matriz en lugar de utilizar
// la del propio HMeshObject
Vector3 pos = leftChain.finalPos;
pos.X=(rightChain.finalPos.X+leftChain.finalPos.X)/2f;
pos.Y -= linkMeshObject.BoundingBox.Height / 2f;
Matrix matrix = Matrix.Translation(pos);
body.SetMatrix(ref matrix);
// Ya no utilizamos más la colision así que la liberamos
collision.Release();
lampBody = body;
// añadimos los joints
HBallJoint joint = new HBallJoint(leftChain.finalPos, new Vector3(0, 1f, 0), 0, 0, body, leftChain.linkBody);
HBallJoint joint2 = new HBallJoint(rightChain.finalPos, new Vector3(0, 1f, 0), 0, 0, body, rightChain.linkBody);
}
#endregion
pregunta tonta: ¿donde actualizais los objetos segun los datos que os da newton?
En la clase Physics. De eso se encarga el motor, para que no tengas que hacerlo tu ;)
pregunta tonta 2: ¿hay la posibilidad de evitar que la clase Physics lo haga y lo hagamos nosotros? me refiero a obtener los valores de newton y adaptar el objeto segun queramos nosotros
claro...simplemente no uses la física de Haddd y hz tu tus propias clases de físcia en el motor.
Tiene, muy buena pinta. Como han dicho los demas, yo tambien quiero probar vuestro motor...
(ole)
yo tengo ganas mas que del motor de ver los .fx, que por mi parte es donde mas fallo ya que son matematicas bastante avanzadas y hay mucho truco ;)
CitarAMD 1800+ Radeon 9500.
El motor hace muchas pasadas para conseguir el resultado final. Evidentemente los fps bajan, sin embargo, no variaría mucho más si pusieras más luces y más polígonos. Es por la arquitectura que utilizamos
No está nada mal. La verdad que vuestro motor promete mucho ...
¿Hay alguna fecha tentativa de "release"?
Noviembre ;) Ahora mismo tamos hasta arriba (pulir, tutos, traducciones, etc etc). A ver si pueden responder Haddd o Ber que tendrá las cosas más claras que yo (a nivel global). Un saludo!
Vicente
oye, y los doc del plugin del 3d max y el md5 y eso, ¿ eso va a parte de los tutos o son el 8 , 9 , etc?
Por cierto, en el video 3 (musseum) iluminais a "imp" con una luz muy bonita, es como un foco de un escenario y le da un aspecto muy real ¿ como se llama esa luz? ¿Se utilizara de modo especial o sera un tipo de luz mas?
(uoh) (uoh)
Cita de: "Kaneda"oye, y los doc del plugin del 3d max y el md5 y eso, ¿ eso va a parte de los tutos o son el 8 , 9 , etc?
Eso serán unos tutoriales aparte ya que no tienen que ver con la programación del motor.
Cita de: "Kaneda"Por cierto, en el video 3 (musseum) iluminais a "imp" con una luz muy bonita, es como un foco de un escenario y le da un aspecto muy real ¿ como se llama esa luz? ¿Se utilizara de modo especial o sera un tipo de luz mas?
Creo que no tenía nada especial aquella luz. Era una luz de tipo omnidireccional. Tal vez el color y el hecho de que el imp tenía aplicado una pequeña reflexión del entorno le daba ese toque especial. La verdad es que la mayor parte del tiempo no prestamos atención a la mezcla de los colores, con lo importante que es para conseguir una imagen agradable.
Saludos.
PD: hmmm tal vez me estoy confundiendo...¿Te refieres a los light shafts?.
creo que si.. :huh: .. lo primero veo que hay una luz omni , pero justo despues se enciende una luz de estas que parecen que tienen particulas tipo foco de escenario, no se si si sera shaft light, o luz .... :( x , pero esta muy conseguido, ademas me estoy fijando en el video y parece ademas que en el escenario se proyecta un LOGO o algo asi que pone HAD3 , yo creo que mucha gente no se dio cuenta de eso MOLA!!!!! (uoh)
Sí, eso es una luz spot con un proyector asignado y light shafts. De todos modos los light shafts no quedan bien cuando se mira perpendicularmente a la luz. Eso es algo que hay que arreglar.
Saludos.
esto... y un tuto sobre vuestro maginifico editor de particulas?? (a lo mejor viene a parte , es que he visto el video y hay muchisimos botones y opciones :lol: )