Jump to content
The Dark Mod Forums

Speaker radius


Recommended Posts

I need to check for the soundShader (to retrieve the SoundRadii class) and the s_min/max Distance keys so I can call the appropriate render.

I guess I could either check for the values in render(), which would cause a lot of overhead, or I could add some sort of key observer. I guess the key observer is the way to go.

The genericEntity class (which I copied) already contains some sort of observer, but I don't understand how it works. Any clues or other classes from which I could copy would be appreciated...

 

 

btw. the Radiant shows five keys which could be of relevance for this: s_shader, s_mindistance, s_maxdistance, s_minDistance, s_maxDistance.

I'm not sure which of those are relevant for the render. The original plan was to only retrieve the values from s_shader, but s_min/max Distance seem to allow to override those and perhaps s_min/max distance do something similar. Some clarification would also be helpful.

Link to comment
Share on other sites

  • Replies 123
  • Created
  • Last Reply

Top Posters In This Topic

The GenericEntity contains the Doom3Entity, which holds the actual spawnargs. The SoundRadii class could act as KeyObserver, which gets notified as soon as the relevant keyvalues change.

 

At the moment, the way the observer mechanism is setup on the Doom3Entity is unneccessary complicated and should be refactored to some simpler system. Anyhow, you can have a look at Doom3Group::KeyObserverMap m_keyObservers;. This is some sort of keyobserver relay class which does all the (complicated) organisational stuff for you. Look at Doom3Group::construct() to see how it's setup. Be sure to attach the KeyObserverMap to the Doom3Entity. The callbacks you need to pass to the KeyObserverMap have to be defined on your SoundRadii class.

typedef MemberCaller1<
			  SoundRadii, 
			  const std::string&, 
			  &SoundRadii::soundShaderChanged> SoundShaderChangedCaller;

Then pass this SoundShaderChangedCaller to the KeyObserverMap, like this:

_keyObservers.insert("s_shader", SoundRadii::SoundShaderChangedCaller(_soundRadii));

You can also let the SoundRadii class register itself using its own KeyObserverMap, that's up to you:

_keyObservers.insert("s_shader", SoundShaderChangedCaller(*this));

 

(Let me add that I personally hate callbacks, but changing the Doom3Entity interface is too much hassle for the moment being.)

 

The relevant spawnargs are s_minDistance, s_maxDistance and s_shader. Compare the file misc.def, that's where the speaker entity is defined. The minDistance/maxDistance are the inner and outer radii, the soundshader can be used to lookup these values (if not overridden, like you correctly noticed).

 

Confusing? :)

Link to comment
Share on other sites

  • 2 weeks later...

I did an svn up and now radiant doesn't compile anymore :-(

I get

g++ -o build/release/plugins/archivezip/plugin.os -c -pipe -DPOSIX -DXWINDOWS -W -Wall -Wcast-align -Wcast-qual -Wno-unused-parameter -Wno-non-virtual-dtor -Wreorder -fPIC -O2 `xml2-config --cflags` -fPIC -Ibuild/release/radiant -Iradiant -Ibuild/release/include -Iinclude -Ibuild/release/libs -Ilibs -Ibuild/release/include -Iinclude plugins/archivezip/plugin.cpp
include/itextstream.h: In member function 'virtual int TextInputStream::underflow()':
include/itextstream.h:58: error: 'assert' was not declared in this scope
scons: *** [build/release/plugins/archivezip/plugin.os] Error 1
scons: building terminated because of errors.

Link to comment
Share on other sites

Okay, finally got back to this.

 

But still the observers are sort of a riddle to me...

an example:

in the .h file there is:

OriginKey m_originKey;


void originChanged();
typedef MemberCaller<Speaker, &Speaker::originChanged> OriginChangedCaller;

and in the .cpp file:

m_originKey(OriginChangedCaller(*this))


m_keyObservers.insert("origin", OriginKey::OriginChangedCaller(m_originKey));


void Speaker::originChanged() {
 m_origin = m_originKey.m_origin;
 updateTransform();
}

It seems I need to write both, a class: OriginKey and a function: originChanged().

Then I have to create a MemberCaller with my new function, the OriginChangedCaller. Then instanciate the OriginKey class with my OriginChangedCaller and finally parse another OriginChangedCaller that is member of the OriginKey class to the keyObserver.

 

Seeing that I just want to observe three values and get notified when they change, does that really mean I have to write three classes (those that are already there all are in an extra file...) and three functions? Or do I miss the wood for the trees?

Link to comment
Share on other sites

I think I have it done basicly. I simply copied the entire OpenGL code over from GTK-Radiant :-P.

One small problem is left, I need three Vector3 functions that were obviously removed from DarkRadiant (vector3_scaled, vector3_added, vector3_to_array). Should I copy them too or rewrite the thing to work without them (probably more work)?

Link to comment
Share on other sites

Those functions already exist but they are named differently, I think vector3_scaled and vector3_added are implemented as overloaded operators (so you can just write myVector * 2.0 or myVector1 + myVector2), while vector3_to_array is not needed since there is an operator cast to const double* which will be invoked if you pass a Vector3 to a function expecting an array.

Link to comment
Share on other sites

Yes, that is the only difference. Many OpenGL functions provide the option of working with floats or doubles. In the case of DarkRadiant everything should be using double if possible, but GtkRadiant has not made this change so their code will be stuck with floats.

Link to comment
Share on other sites

Two more:

Atm I have

if (m_useSpeakerRadii)
	renderer.addRenderable(m_speakerRadii, localToWorld);

Which works, but renders the spheres only around the sound entity when it is located in global {0,0,0}, otherwise the spheres are located somewhere different than the entity. I guess the reason is localToWorld. But I have no idea what else could go in there since I basicaly just copied it.

 

Should I add a switch that turns the spheres on/off? Or use the turn lightVolumes on/off switch?

Link to comment
Share on other sites

if (m_useSpeakerRadii)
	renderer.addRenderable(m_speakerRadii, localToWorld);

Which works, but renders the spheres only around the sound entity when it is located in global {0,0,0}, otherwise the spheres are located somewhere different than the entity. I guess the reason is localToWorld. But I have no idea what else could go in there since I basicaly just copied it.

 

Yes, the localToWorld transform needs to be set correctly from the Node/Instance/Entity (one of those -- I would guess the Instance, but unfortunately I know very little about this area). Looking at how the light volume classes do it is probably your best bet.

 

Should I add a switch that turns the spheres on/off? Or use the turn lightVolumes on/off switch?

 

It definitely needs to be separate from the light volumes, and should be connected up as a registry setting (just like the light volumes). Adding a toolbar icon will be necessary in the long run but if you don't want to mess around with GTK then just using a registry setting for now will be fine.

Link to comment
Share on other sites

With some trial-and-error I already fixed the first thing, I used m_aabb_local.origin, no idea what it does, but it works ;-P hehe.

 

I think a button isn't that hard to do, so, I guess I'll try.

 

Yet another question, I think angua already mentioned it, the spheres all seem a lot to small. Angua said the values have to be converted from metres to doom3 units. Any clue what the ratio metres/doom units is?

Link to comment
Share on other sites

More questions: The sphere/circles disappear once the speaker itself is out of the view, I guess this is not a desired effect. I probably have to set the AABB of the speaker to the outer radius or let them have their own AABB, but those are just guesses.

 

The 3d view shows the lines of the 2d views which looks quite bad. I did some sort of separation with:

if((state & RENDER_FILL) != 0) {
	speakerDrawRadiiFill(m_origin, m_radii);
}
else {
	speakerDrawRadiiWire(m_origin, m_radii);
}

but it obviously doesn't work.

 

Atm the code draws three circles (one for each viewport), so the 2d viewports show all three circles, which doesn't look good (two of the three always look like lines, in 3d view all three circles are visible). Is there a way to draw things specific to a viewport? - Or even better, don't draw the circles directly as circles, but as a surrounding line of the 3d sphere, since that would look good in both, the 3d view port and the 2d views... I guess that will be a bit more complicate and involve the viewport vector or so, but it would really look better.

 

Should I give this thing some nicer textures? - How?

 

 

That's probably it for today. If things work out bad, that's even it until next weedend, but we'll see.

Link to comment
Share on other sites

ai/ai.cpp in the SDK source says:

 

const float s_DOOM_TO_METERS = 0.0254f;

 

The idea being you multiply a measurement in doom units by 0.0254 to get metres. Why 0.0254? Because 0.0254 metres = 1 inch, so 1 Doom unit is approximately 1 inch.

 

This isn't accurate though; IIRC we're using 1 Doom unit = 1.1 inches to make things look right. But, AFAIK the sound system in D3 works on the basis that 1 Doom unit = 1 inch, so that's probably what you should use.

My games | Public Service Announcement: TDM is not set in the Thief universe. The city in which it takes place is not the City from Thief. The player character is not called Garrett. Any person who contradicts these facts will be subjected to disapproving stares.
Link to comment
Share on other sites

More questions: The sphere/circles disappear once the speaker itself is out of the view, I guess this is not a desired effect. I probably have to set the AABB of the speaker to the outer radius or let them have their own AABB, but those are just guesses.

 

The speaker's AABB will indeed need to enclose the rendered radius, yes. The AABB is used for culling, so if the AABB is off-screen the speaker object will not get rendered.

 

Atm the code draws three circles (one for each viewport), so the 2d viewports show all three circles, which doesn't look good (two of the three always look like lines, in 3d view all three circles are visible). Is there a way to draw things specific to a viewport? - Or even better, don't draw the circles directly as circles, but as a surrounding line of the 3d sphere, since that would look good in both, the 3d view port and the 2d views... I guess that will be a bit more complicate and involve the viewport vector or so, but it would really look better.

 

Good point -- conceptually the speaker radius is a sphere, so it might be best to model it as a sphere for now. We can then look into reducing the rendered lines in the 2D views later. Greebo might have some useful input on this since he implemented that background image rendering, which similarly requires 2D drawing in a 3D viewport.

 

Should I give this thing some nicer textures? - How?

 

No, flat colour is perfectly acceptable, the intention is purely to give an indication of how far the speaker's sound will reach.

Link to comment
Share on other sites

Crispy, OrbWeaver, thanks.

So here is a small todo what is left:

On/Off switch

Better lines in 2d/3d view

bigger AABB

correct inch -> metres conversion

 

Since all of those are small tasks I can perhaps find the time for single ones of them in the evening during the week, but no promises.

Link to comment
Share on other sites

Good point -- conceptually the speaker radius is a sphere, so it might be best to model it as a sphere for now. We can then look into reducing the rendered lines in the 2D views later. Greebo might have some useful input on this since he implemented that background image rendering, which similarly requires 2D drawing in a 3D viewport.

The background image rendering takes place before all the renderables are traversed and drawn. I hooked this into the XYView::draw() method, where GL_TEXTURE_2D is temporarily enabled by the Overlay class.

 

There is currently no way to check for a Renderable which XY viewtype (i.e. which projection matrix) is active at the moment, so I can quickly think of two solutions:

 

- Implement a query which allows the GenericEntity::renderWireFrame() method to check for the currently drawn XY view type. This will be a small hack, like this:

1) XYView::draw() >> calls GlobalXYWnd::setRenderedViewType(EViewTy

pe);

2) Traverse the Renderables, call renderWireFrame()

3) GenericEntity::renderWireFrame queries GlobalXYWnd::getRenderedViewType() and submits the correct renderable

 

The second solution will require a new type of Renderable, say Renderable2D. During traversal of the OpenGLRenderables, the Renderable2D objects are submitted to and gathered by the Renderer. In XYView::draw(), these 2D renderables are traversed and called with the correct viewtype as argument (within an enabled GL_TEXTURE_2D state). This is more work, but it could also allow for the rendering of textured light and speaker radii, similar to the background image.

 

Both solutions are not terribly elegant, as in principle all the OpenGLRenderables should not know nor care about the actual projection type while being drawn. Though, I don't think this problem is solveable without the Renderables knowing about the projection type.

 

OrbWeaver, can you think of a more elegant way to solve this?

Link to comment
Share on other sites

Both solutions are not terribly elegant, as in principle all the OpenGLRenderables should not know nor care about the actual projection type while being drawn. Though, I don't think this problem is solveable without the Renderables knowing about the projection type.

 

I agree -- the problem is that the "2D" view is not actually a 2D view but a 3D view with an orthographic projection type, and the expectation is that renderables submit 3D geometry which gets projected to 2D by the view itself.

 

OrbWeaver, can you think of a more elegant way to solve this?

 

I would be tempted to say that if the speaker radius is supposed to be a sphere, then it should be rendered as a 3D sphere rather than 2D circles. A simple UV sphere could be used, and wouldn't need that many latitude or longitude lines to give an effective idea of how far the sound will reach.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Recent Status Updates

    • Petike the Taffer

      I've finally managed to log in to The Dark Mod Wiki. I'm back in the saddle and before the holidays start in full, I'll be adding a few new FM articles and doing other updates. Written in Stone is already done.
      · 4 replies
    • nbohr1more

      TDM 15th Anniversary Contest is now active! Please declare your participation: https://forums.thedarkmod.com/index.php?/topic/22413-the-dark-mod-15th-anniversary-contest-entry-thread/
       
      · 0 replies
    • JackFarmer

      @TheUnbeholden
      You cannot receive PMs. Could you please be so kind and check your mailbox if it is full (or maybe you switched off the function)?
      · 1 reply
    • OrbWeaver

      I like the new frob highlight but it would nice if it was less "flickery" while moving over objects (especially barred metal doors).
      · 4 replies
    • nbohr1more

      Please vote in the 15th Anniversary Contest Theme Poll
       
      · 0 replies
×
×
  • Create New...