[SOLVED] Looking for some help with MOGRE and ray queries

krinberry

22-12-2006 15:16:43

Hey there folks. I posted this in the main Help originally which was the wrong place, apologies to anyone this annoyed! Won't happen again. Anyways, here's the info as I posted it previously:

I've been playing around with Ogre (specifically, the Mogre SDK) and while I've found almost everything incredibly well designed and easy to use, I've run into a bit of trouble with ray queries, mainly due to my own unfamiliarity with how rays work in general. There's no tutorial on the subject for Mogre, and while there are plenty of C++ etc examples that I thought I had more-or-less converted properly for use in C#, I'm getting no love in response when I try to use them. Does anyone have any examples of ray queries in Mogre that I could perhaps take a look at? It doesn't have to be anything fancy, just something to show me the basics.

Any help at all, or even just pointing me to a good resource, would be very much appreciated. Thanks in advance!

Here's the code info from what I've been working with:

void MouseDownHandler(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
float mX = (float)e.X / camX; // camX contains the width of the viewport
float mY = (float)e.Y / camY; // camY contains the height of the viewport

RaySceneQuery raySceneQuery = mgr.CreateRayQuery(new Ray());
raySceneQuery.Ray = cam.GetCameraToViewportRay(mX,mY);
raySceneQuery.SetSortByDistance(true);
raySceneQuery.Execute();
RaySceneQueryResult r = raySceneQuery.GetLastResults();
RaySceneQueryResult.Iterator iRay;
for (iRay = r.Begin(); iRay != r.End(); iRay++)
{
MessageBox.Show("Found Something");
}
raySceneQuery.Dispose();
}
}


Based on posts I've read here in the forums I've tried a few different ways of handling the X and Y values from the event handler; the following are a few of the different ways I've tried (unsuccessfully):

float mX = (((float)e.X) / camX) - 0.5f;
float mY = 1f - ((((float)e.Y) / camY) + 0.5f);


also:

float mx = (float)e.X;
float my = (float)e.Y;


I'm not certain precisely what's wrong, to be honest; the code I used as the primary basis for most of this is from the tutorial here http://www.ogre3d.org/wiki/index.php/In ... Tutorial_3 on the site, specifically:

virtual void onLeftPressed( MouseEvent *e )
{
// Setup the ray scene query
Ray mouseRay = mCamera->getCameraToViewportRay( e->getX(), e->getY() );
mRaySceneQuery->setRay( mouseRay );

// Execute query
RaySceneQueryResult &result = mRaySceneQuery->execute();
RaySceneQueryResult::iterator itr = result.begin( );

// Get results, create a node/entity on the position
if ( itr != result.end() && itr->worldFragment )
{
char name[16];
sprintf( name, "Robot%d", mCount++ );

Entity *ent = mSceneMgr->createEntity( name, "robot.mesh" );
mCurrentObject = mSceneMgr->getRootSceneNode( )->createChildSceneNode( String(name) + "Node", itr->worldFragment->singleIntersection );
mCurrentObject->attachObject( ent );
mCurrentObject->setScale( 0.1f, 0.1f, 0.1f );
} // if
}


At any rate the loop through the iRay contents never fires, and as far as I can tell the ray always seems to original from the initial camera position regardless of any changes to its position or orientation, and doesn't seem to even act as if it was pointing towards where I'd expect it to if the camera was at its initial position.

Sorry if there's anything obviously wrong about my attempts here; the loop right now is just set to give me a messagebox, as I wanted to see a positive result before I got any further into it.

Bekas

24-12-2006 00:23:18

Here's a sample:
The MogreForm.cs file:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Mogre;

namespace Mogre.Demo.MogreForm
{
public partial class MogreForm : Form
{
protected OgreWindow mogreWin;

public MogreForm()
{
InitializeComponent();
this.Disposed += new EventHandler(MogreForm_Disposed);

mogreWin = new OgreWindow(new Point(100, 30), mogrePanel.Handle);
mogreWin.InitMogre();
}

private void MogreForm_Paint(object sender, PaintEventArgs e)
{
mogreWin.Paint();
}

void MogreForm_Disposed(object sender, EventArgs e)
{
mogreWin.Dispose();
}

private void mogrePanel_MouseClick(object sender, MouseEventArgs e)
{
if (mogreWin.ClickedOnHead(e.X, e.Y))
MessageBox.Show("You hit the head");
else
MessageBox.Show("Missed");
}
}

public class OgreWindow
{
public bool ClickedOnHead(int mx, int my)
{
//normalise mouse coordinates to [0,1]
//we could have used the panel's width/height in pixels instead of viewport's width/height
float scrx = (float)mx / viewport.ActualWidth;
float scry = (float)my / viewport.ActualHeight;

Ray ray = camera.GetCameraToViewportRay(scrx, scry);
RaySceneQuery query = sceneMgr.CreateRayQuery(ray);
RaySceneQueryResult results = query.Execute();

// This just shows a better way to enumerate the results than using RaySceneQueryResult.Iterator
foreach (RaySceneQueryResultEntry entry in results)
{
// Do stuff
}

//if we hit the head then there is 1 result
return results.Count > 0;
}

public Root root;
public SceneManager sceneMgr;

protected Camera camera;
protected Viewport viewport;
protected RenderWindow window;
protected Point position;
protected IntPtr hWnd;

public OgreWindow(Point origin, IntPtr hWnd)
{
position = origin;
this.hWnd = hWnd;
}

public void InitMogre()
{

//-----------------------------------------------------
// 1 enter ogre
//-----------------------------------------------------
root = new Root();

//-----------------------------------------------------
// 2 configure resource paths
//-----------------------------------------------------
ConfigFile cf = new ConfigFile();
cf.Load("resources.cfg", "\t:=", true);

// Go through all sections & settings in the file
ConfigFile.SectionIterator seci = cf.GetSectionIterator();

String secName, typeName, archName;

// Normally we would use the foreach syntax, which enumerates the values, but in this case we need CurrentKey too;
while (seci.MoveNext())
{
secName = seci.CurrentKey;
ConfigFile.SettingsMultiMap settings = seci.Current;
foreach (KeyValuePair<string, string> pair in settings)
{
typeName = pair.Key;
archName = pair.Value;
ResourceGroupManager.Singleton.AddResourceLocation(archName, typeName, secName);
}
}

//-----------------------------------------------------
// 3 Configures the application and creates the window
//-----------------------------------------------------
bool foundit = false;
foreach (RenderSystem rs in root.GetAvailableRenderers())
{
root.RenderSystem = rs;
String rname = root.RenderSystem.Name;
if (rname == "Direct3D9 Rendering Subsystem")
{
foundit = true;
break;
}
}

if (!foundit)
return; //we didn't find it... Raise exception?

//we found it, we might as well use it!
root.RenderSystem.SetConfigOption("Full Screen", "No");
root.RenderSystem.SetConfigOption("Video Mode", "640 x 480 @ 32-bit colour");

root.Initialise(false);
NameValuePairList misc = new NameValuePairList();
misc["externalWindowHandle"] = hWnd.ToString();
window = root.CreateRenderWindow("Simple Mogre Form Window", 0, 0, false, misc);
ResourceGroupManager.Singleton.InitialiseAllResourceGroups();

//-----------------------------------------------------
// 4 Create the SceneManager
//
// ST_GENERIC = octree
// ST_EXTERIOR_CLOSE = simple terrain
// ST_EXTERIOR_FAR = nature terrain (depreciated)
// ST_EXTERIOR_REAL_FAR = paging landscape
// ST_INTERIOR = Quake3 BSP
//-----------------------------------------------------
sceneMgr = root.CreateSceneManager(SceneType.ST_GENERIC, "SceneMgr");
sceneMgr.AmbientLight = new ColourValue(0.5f, 0.5f, 0.5f);

//-----------------------------------------------------
// 5 Create the camera
//-----------------------------------------------------
camera = sceneMgr.CreateCamera("SimpleCamera");
camera.Position = new Vector3(0f,0f,100f);
// Look back along -Z
camera.LookAt(new Vector3(0f,0f,-300f));
camera.NearClipDistance = 5;

viewport = window.AddViewport(camera);
viewport.BackgroundColour = new ColourValue(0.0f, 0.0f, 0.0f, 1.0f);


Entity ent = sceneMgr.CreateEntity("ogre", "ogrehead.mesh");
SceneNode node = sceneMgr.RootSceneNode.CreateChildSceneNode("ogreNode");
node.AttachObject(ent);
}

public void Paint()
{
root.RenderOneFrame();
}

public void Dispose()
{
if (root != null)
{
root.Dispose();
root = null;
}
}
}

}


And the MogreForm.Designer.cs:


namespace Mogre.Demo.MogreForm
{
partial class MogreForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;

/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}

#region Windows Form Designer generated code

/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.mogrePanel = new System.Windows.Forms.Panel();
this.SuspendLayout();
//
// mogrePanel
//
this.mogrePanel.Location = new System.Drawing.Point(150, 68);
this.mogrePanel.Name = "mogrePanel";
this.mogrePanel.Size = new System.Drawing.Size(483, 375);
this.mogrePanel.TabIndex = 0;
this.mogrePanel.MouseClick += new System.Windows.Forms.MouseEventHandler(this.mogrePanel_MouseClick);
//
// MogreForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(810, 544);
this.Controls.Add(this.mogrePanel);
this.Name = "MogreForm";
this.Text = "Simple Mogre Form";
this.Paint += new System.Windows.Forms.PaintEventHandler(this.MogreForm_Paint);
this.ResumeLayout(false);

}

#endregion

private System.Windows.Forms.Panel mogrePanel;

}
}

krinberry

24-12-2006 03:29:28

Bekas, thank you! That code works perfectly, and I think I see what my problem was initially... it wasn't even a problem with the ray query but my initial setup I think (still looking through to be more certain, but that's what it looks like now).

I've been puzzling over this for days now, I can't tell you how happy this makes me. :)

Also thank you for pointing out a better method than using RaySceneQueryResult.Iterator for enumeration. :)

Whee! This has made my day. Thank you very much again! (Sorry, I'm just excited :))