Hi guys I´ve sucessfully solved the decal align problem with a SceneQuery them some vector math to calculate the 3d position intersection...
The result (We still se that there is some error offset but I think this is enough... at least I think it is cheaper than using a physic ray cast)
Still have some decal problems...
Hope that sharing the code with others can help something...
Code: Select all
// Header do Ogre
#include <Ogre.h>
#include <ExampleApplication.h>
#include <Tubes.h>
#include <OgreRenderQueueListener.h>
// render queues
#define RENDER_QUEUE_OUTLINE_GLOW_OBJECTS RENDER_QUEUE_MAIN + 1
#define RENDER_QUEUE_OUTLINE_GLOW_GLOWS RENDER_QUEUE_MAIN + 2
#define RENDER_QUEUE_FULL_GLOW_ALPHA_GLOW RENDER_QUEUE_MAIN + 3
#define RENDER_QUEUE_FULL_GLOW_GLOW RENDER_QUEUE_MAIN + 4
#define LAST_STENCIL_OP_RENDER_QUEUE RENDER_QUEUE_FULL_GLOW_GLOW
// stencil values
#define STENCIL_VALUE_FOR_OUTLINE_GLOW 1
#define STENCIL_VALUE_FOR_FULL_GLOW 2
#define STENCIL_FULL_MASK 0xFFFFFFFF
// Mascaras
enum QueryFlags
{
FRUSTUM_FLAG = 1<<0,
NAVES = 1<<1,
OBJETOS_ESTACIONARIOS = 1<<2,
SHIELDS = 1<<3
};
// A FrameListener that gets passed our projector node and decal frustum so they can be animated
class ProjectiveDecalListener : public ExampleFrameListener
{
public:
ProjectiveDecalListener(RenderWindow* win, Camera* cam, SceneNode *proj, Frustum *decal, SceneManager *mgrscr)
: ExampleFrameListener(win, cam), mProjectorNode(proj), mDecalFrustum(decal), mAnim(0), mSceneMgr(mgrscr)
{
}
bool frameStarted(const FrameEvent& evt)
{
RaySceneQuery *mRaySceneQuery;
// Animacoes de 2 segundos
mAnim += evt.timeSinceLastFrame / 2;
if (mAnim >= 1)
mAnim -= 1;
// Seta o FOV do frustrum do decal para 4 graus
if (mDecalFrustum)
{
mDecalFrustum->setFOVy((Ogre::Degree)4);
}
// Cria RaySceneQuery para ver onde pegou no escudo
mRaySceneQuery = mSceneMgr->createRayQuery(Ray());
Vector3 PosGalaxy = mSceneMgr->getSceneNode("Node_Nave_Galaxy")->getPosition();
Vector3 PosBOP = mSceneMgr->getSceneNode("Node_Nave_K")->getPosition();
Vector3 vDirecao = PosBOP - PosGalaxy;
vDirecao.normalise();
Ray RaioPhaser(PosGalaxy, vDirecao);
mRaySceneQuery->setRay(RaioPhaser);
// Procura somente escudo (Mascara da query)
mRaySceneQuery->setQueryMask(SHIELDS | FRUSTUM_FLAG);
RaySceneQueryResult &result = mRaySceneQuery->execute();
RaySceneQueryResult::iterator itr=result.begin();
// Get the results & do something
if (itr!=result.end()&&itr->movable)
{
for( ; itr != result.end() ; itr++ )
{
static Vector3 pos_impacto;
if (itr->movable->getName() == "Esfera")
{
LogManager::getSingletonPtr()->logMessage("Pegou Escudo");
// Agora vamos calcular o ponto de impacto...
Vector3 origem = RaioPhaser.getOrigin();
Vector3 direcao = RaioPhaser.getDirection();
Real tam_direcao = direcao.length();
Real distancia= itr->distance;
direcao = direcao / tam_direcao;
pos_impacto = origem + (direcao * distancia);
LogManager::getSingletonPtr()->logMessage("Pegou coordenada escudo");
}
if (itr->movable->getMovableType() == "Frustum")
{
// Agora vamos calcular o ponto de impacto...
if (itr->movable->getParentNode()->getName() == "DecalProjectorNode")
{
LogManager::getSingletonPtr()->logMessage("Pegou Frustum decal");
itr->movable->getParentNode()->setPosition(pos_impacto);
}
}
}
}
else
{
LogManager::getSingletonPtr()->logMessage("NAO ACHOU NADA");
}
return ExampleFrameListener::frameStarted(evt);
}
protected:
SceneNode *mProjectorNode;
Frustum *mDecalFrustum;
SceneManager *mSceneMgr;
float mAnim;
};
class StencilOpQueueListener : public Ogre::RenderQueueListener
{
public:
virtual void renderQueueStarted(Ogre::uint8 queueGroupId, const Ogre::String& invocation, bool& skipThisInvocation)
{
if (queueGroupId == RENDER_QUEUE_OUTLINE_GLOW_OBJECTS) // outline glow object
{
Ogre::RenderSystem * rendersys = Ogre::Root::getSingleton().getRenderSystem();
rendersys->clearFrameBuffer(Ogre::FBT_STENCIL);
rendersys->setStencilCheckEnabled(true);
rendersys->setStencilBufferParams(Ogre::CMPF_ALWAYS_PASS,
STENCIL_VALUE_FOR_OUTLINE_GLOW, STENCIL_FULL_MASK,
Ogre::SOP_KEEP,Ogre::SOP_KEEP,Ogre::SOP_REPLACE,false);
}
if (queueGroupId == RENDER_QUEUE_OUTLINE_GLOW_GLOWS) // outline glow
{
Ogre::RenderSystem * rendersys = Ogre::Root::getSingleton().getRenderSystem();
rendersys->setStencilCheckEnabled(true);
rendersys->setStencilBufferParams(Ogre::CMPF_NOT_EQUAL,
STENCIL_VALUE_FOR_OUTLINE_GLOW, STENCIL_FULL_MASK,
Ogre::SOP_KEEP,Ogre::SOP_KEEP,Ogre::SOP_REPLACE,false);
}
if (queueGroupId == RENDER_QUEUE_FULL_GLOW_ALPHA_GLOW) // full glow - alpha glow
{
Ogre::RenderSystem * rendersys = Ogre::Root::getSingleton().getRenderSystem();
rendersys->setStencilCheckEnabled(true);
rendersys->setStencilBufferParams(Ogre::CMPF_ALWAYS_PASS,
STENCIL_VALUE_FOR_FULL_GLOW,STENCIL_FULL_MASK,
Ogre::SOP_KEEP,Ogre::SOP_KEEP,Ogre::SOP_REPLACE,false);
}
if (queueGroupId == RENDER_QUEUE_FULL_GLOW_GLOW) // full glow - glow
{
Ogre::RenderSystem * rendersys = Ogre::Root::getSingleton().getRenderSystem();
rendersys->setStencilCheckEnabled(true);
rendersys->setStencilBufferParams(Ogre::CMPF_EQUAL,
STENCIL_VALUE_FOR_FULL_GLOW,STENCIL_FULL_MASK,
Ogre::SOP_KEEP,Ogre::SOP_KEEP,Ogre::SOP_ZERO,false);
}
}
virtual void renderQueueEnded(Ogre::uint8 queueGroupId, const Ogre::String& invocation, bool& repeatThisInvocation)
{
if (( queueGroupId == LAST_STENCIL_OP_RENDER_QUEUE ))
{
Ogre::RenderSystem * rendersys = Ogre::Root::getSingleton().getRenderSystem();
rendersys->setStencilCheckEnabled(false);
rendersys->setStencilBufferParams();
}
}
};
/*
Exemplo que usa ManualObjects para criar um efeito mais bonito e menos custoso para placa de video
implementar estrelas
*/
// Classe que Implementa Randomicos
class Random{
public:
Random()
{
}
double randomUniform(double min, double max)
{
double r;
r=(double)rand()/RAND_MAX;
r=min+r*(max-min);
return r;
}
double randomNormal(double mean, double std)
{
double x1, x2, w, y1;
do {
x1 = 2.0 * randomUniform(0,1) - 1.0;
x2 = 2.0 * randomUniform(0,1) - 1.0;
w = x1 * x1 + x2 * x2;
} while ( w >= 1.0);
w = sqrt( (-2.0 * log( w ) ) / w );
y1 = x1 * w;
y1 = (y1 * std) + mean;
return y1;
}
void randomSphere(double radius=80)
{
double l=0;
for(int j=0;j<3; j++){
Tabela[j] = randomNormal(0,1);
l += Tabela[j]*Tabela[j];
}
l = sqrt(l);
double r = randomUniform(0,1);
r = pow( r, 1/3);
for(int j=0;j<3; j++){
Tabela[j] = radius*(r * Tabela[j] / l);
}
}
double PegaTabela(int i = 0) { return Tabela[i]; }
private:
double Tabela [3];
};
class Starfield{
public:
Starfield()
{
}
void CreateStarfield(Ogre::SceneManager* mSceneMgr, int NumberOfStars = 10000)
{
// Cria uma mesh manualmente
ManualObject* manual = mSceneMgr->createManualObject("manual");
manual->begin("BaseWhiteNoLighting", RenderOperation::OT_POINT_LIST);
float brillance=0.0;
Random p;
for (int i=0; i<NumberOfStars; i++)
{
// Tamanho da esfera
p.randomSphere(10000);
brillance = (int)((float)rand()/32767*99);
brillance = brillance/100;
manual->position(p.PegaTabela(0), p.PegaTabela(1), p.PegaTabela(2));
manual->colour(ColourValue(brillance, brillance, brillance, 1));
}
manual->end();
// Agora cria um node e anexa a mesh manual criada
mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(manual);
}
};
class SampleApp : public ExampleApplication
{
public:
SampleApp()
{}
protected:
SceneNode *mProjectorNode;
Frustum *mDecalFrustum;
Frustum *mFilterFrustum;
// Funcao para criar o decal
void createProjector()
{
// set up the main decal projection frustum
mDecalFrustum = new Frustum();
mDecalFrustum->setQueryFlags(FRUSTUM_FLAG);
mProjectorNode = mSceneMgr->getRootSceneNode()->createChildSceneNode("DecalProjectorNode");
mProjectorNode->attachObject(mDecalFrustum);
//mProjectorNode->setPosition(4.6122017,1.8448830,9.2244034); //0,1.4,0
// include these two lines if you don't want perspective projection
mDecalFrustum->setProjectionType(PT_ORTHOGRAPHIC);
mDecalFrustum->setNearClipDistance(120);//25
// Seta um frustum perpendicular
mFilterFrustum = new Frustum();
mFilterFrustum->setProjectionType(PT_ORTHOGRAPHIC);
mFilterFrustum->setQueryFlags(FRUSTUM_FLAG);
SceneNode *filterNode = mProjectorNode->createChildSceneNode("DecalFilterNode");
filterNode->attachObject(mFilterFrustum);
filterNode->setOrientation(Quaternion(Degree(90),Vector3::UNIT_Y));
}
// Poe um pass extra no material que renderiza o decal no topo da textura
void makeMaterialReceiveDecal(const String &matName)
{
// Pega o material
MaterialPtr mat = (MaterialPtr)MaterialManager::getSingleton().getByName(matName);
// Cria um novo pass na textura do material
Pass *pass = mat->getTechnique(0)->createPass();
// Seta o passe para se mesclar com a textura anterior
pass->setSceneBlending(SBT_TRANSPARENT_ALPHA);
pass->setDepthBias(1);
// Poe o decal com iluminacao propia
pass->setLightingEnabled(false);
// Seta primeira textura
TextureUnitState *texState = pass->createTextureUnitState("Nebula_tr.png");
texState->setProjectiveTexturing(true, mDecalFrustum);
texState->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
texState->setTextureFiltering(FO_POINT, FO_LINEAR, FO_NONE);
// Seta textura de filtro (Mesmo tirando funciona)
texState = pass->createTextureUnitState("decal_filter.png");
texState->setProjectiveTexturing(true, mFilterFrustum);
texState->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
texState->setTextureFiltering(TFO_NONE);
}
// Sobrecarrega do CreateScene
void createScene(void)
{
/// Cria o campo estelar
//Starfield *p_Starfield = new Starfield();
//p_Starfield->CreateStarfield(mSceneMgr);
mSceneMgr->setSkyBox(true, "StarTrek/NebulaTeste");
// Luz
mSceneMgr->setAmbientLight( ColourValue( 1, 1, 1 ) );
Light *light = mSceneMgr->createLight("Light_BOP");
light->setType(Light::LT_POINT);
light->setPosition(Vector3(0, 20, 0));
light->setDiffuseColour(1.0, 1.0, 1.0);
light->setSpecularColour(1.0, 1.0, 1.0);
light = mSceneMgr->createLight("LightGalaxy");
light->setType(Light::LT_POINT);
light->setPosition(Vector3(0, 20, 100));
light->setDiffuseColour(1.0, 1.0, 1.0);
light->setSpecularColour(1.0, 1.0, 1.0);
light = mSceneMgr->createLight("Light3");
light->setType(Light::LT_DIRECTIONAL);
light->setDiffuseColour(ColourValue(.25, .25, 0));
light->setSpecularColour(ColourValue(.25, .25, 0));
light->setDirection(Vector3( 0, -1, 1 ));
// Nave Klingon
Entity *ent2 = mSceneMgr->createEntity( "Nave_Klingon", "BirdOfPrey.mesh" );
SceneNode *node2 = mSceneMgr->getRootSceneNode()->createChildSceneNode( "Node_Nave_K" );
ent2->setQueryFlags(NAVES);
node2->attachObject( ent2 );
// Esfera
Entity *esfera_teste = mSceneMgr->createEntity("Esfera", "esfera_teste.mesh");
esfera_teste->setMaterialName("StarTrek/ForceShield");
esfera_teste->setQueryFlags(SHIELDS);
SceneNode *node_esfera = mSceneMgr->getRootSceneNode()->createChildSceneNode( "Node_Escudo_BOP" );
node_esfera->attachObject(esfera_teste);
// Pega o tamanho atual da esfera e divide por 4
node_esfera->setScale(node_esfera->getScale() / 9);
// Cria o decal
createProjector();
// Poe o material em todas as subentities da entidade do escudo
for (unsigned int i = 0; i < esfera_teste->getNumSubEntities(); i++)
makeMaterialReceiveDecal(esfera_teste->getSubEntity(i)->getMaterialName());
// Nave Enterprise Galaxy
Entity *ent3 = mSceneMgr->createEntity( "Nave_Galaxy", "Nave_Enterrpise.mesh" );
SceneNode *node3 = mSceneMgr->getRootSceneNode()->createChildSceneNode( "Node_Nave_Galaxy",Vector3( 0, 20, 100 ) );
ent3->setQueryFlags(NAVES);
node3->attachObject( ent3 );
// Tubos.. (Para o glow serao 3 tubos)*********************
SceneNode* pNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
SeriesOfTubes* mTubes = new SeriesOfTubes(mSceneMgr,16,0.25);
// Ponto da Galaxy até a BOP
mTubes->addPoint(Vector3(0,20,100));
mTubes->addPoint(Vector3(0,0,0));
mTubes->setSceneNode(pNode);
mTubes->createTubes("Tubo_Phaser1","StarTrek/PhaserBeam");
//*******************************
SceneNode* pNode1 = mSceneMgr->getRootSceneNode()->createChildSceneNode();
SeriesOfTubes* mTubes1 = new SeriesOfTubes(mSceneMgr,16,0.25);
// Ponto da Galaxy até a BOP
mTubes1->addPoint(Vector3(0,20,100));
mTubes1->addPoint(Vector3(0,0,0));
mTubes1->setSceneNode(pNode1);
mTubes1->createTubes("Tubo_Phaser2","cg/alpha_glow");
mTubes1->setRenderQueueGroup(RENDER_QUEUE_FULL_GLOW_ALPHA_GLOW);
//******************************
SceneNode* pNode2 = mSceneMgr->getRootSceneNode()->createChildSceneNode();
SeriesOfTubes* mTubes2 = new SeriesOfTubes(mSceneMgr,16,0.25);
// Ponto da Galaxy até a BOP
mTubes2->addPoint(Vector3(0,20,100));
mTubes2->addPoint(Vector3(0,0,0));
mTubes2->setSceneNode(pNode2);
mTubes2->createTubes("Tubo_Phaser3","cg/no_depth_check_glow");
mTubes2->setRenderQueueGroup(RENDER_QUEUE_FULL_GLOW_GLOW);
}
StencilOpQueueListener * mStencilOpFrameListener;
virtual void createFrameListener(void)
{
mStencilOpFrameListener = new StencilOpQueueListener();
mSceneMgr->addRenderQueueListener(mStencilOpFrameListener);
mFrameListener= new ProjectiveDecalListener(mWindow, mCamera, mProjectorNode, mDecalFrustum, mSceneMgr);
mRoot->addFrameListener(mFrameListener);
}
};
// ----------------------------------------------------------------------------
// Main function, just boots the application object
// ----------------------------------------------------------------------------
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
#else
int main(int argc, char **argv)
#endif
{
// Create application object
SampleApp app;
try
{
app.go();
}
catch( Exception& e )
{
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
MessageBox( NULL, e.getFullDescription().c_str(), "An exception has occured!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
#else
std::cerr << "An exception has occured: " << e.getFullDescription();
#endif
}
return 0;
}