Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
FlyingDodo
Jan 22, 2005
Not Extinct
I've just finished writing Vector,Quaternion and Matrix classes (c++). I understand vectors and matrices (well I hope I understand enough). I want to make a class which can be used to rotate things through 6dof. I can use the quaternions to make a basic fps camera which works fine but I have no idea how I am supposed to make a 6dof camera.

Adbot
ADBOT LOVES YOU

FlyingDodo
Jan 22, 2005
Not Extinct

HB posted:

By "basic fps camera" do you mean a camera that uses Euler angles? If you can convert the angle and axis from a quaternion to an orientation matrix, you can use it to transform the camera just like any other object.

Then, to spin the camera around a relative axis like in Descent, you transform the target axis with the camera quaternion, convert the result and the magnitude to a quaternion, and multiply it back into the camera orientation.

If that didn't make any sense, I can try to find the book I got this from in the first place. It's been a really long time since I had to work with quaternions.


No didn't make any sense :(. I'm not very good at maths. All I want is to be able to do is rotate things around for a space game. Like rotating spaceships around all possible orientations, based on pitch/roll/yaw.

FlyingDodo
Jan 22, 2005
Not Extinct

HB posted:

code:
void Ship::RotateAroundRelativeVector(double axis[3], float magnitude)
{
     //member: Quaternion q;
     //member: float position[3];
     float tempMatrix[4][4];
     float absoluteDirection[4];
     Quaternion delta;
     RotationMatrixFromQuat(q, tempMatrix);
     MultiplyMatrixAndVector(tempMatrix, axis, absoluteDirection);
     delta = QuaternionFromAxisAndAngle(axis, magnitude);
     q = MultiplyQuats(q, delta);
}

I'm a bit lost here. I'm assuming that MultiplyMatrixAndVector(tempMatrix, axis, absoluteDirection); multiplies axis by tempMatrix and stores the result in absoluteDirection. So why is delta made from axis and magnitude. Shouldn't it be absoluteDirection and magnitude?

FlyingDodo
Jan 22, 2005
Not Extinct

HB posted:

Sorry, you're right. It should be absoluteDirection.

I'm still having problems trying to make this all work. I made a class which is easy to use (well if it worked properly it would be). All you have to do is give it axis/angles and it gives back an opengl matrix. For some reason it only works for rotations around one axis at a time, otherwise it goes all weird. I hate to dump a wall of text but could you take a look at my code? There must be some mistake in it somewhere that I can't find.
http://rafb.net/p/jNVHEl32.html

FlyingDodo
Jan 22, 2005
Not Extinct
It works rotating along any one axis at a time, no matter the axis. But if I have something like:

Transformer t;//stores the current orientation
double lr; //left/right angle change this frame
double ud; //up/down angle change this frame

and then do this:

t.rotateRelative(Vector3(0,1,0),lr);
t.rotateRelative(Vector3(1,0,0),ud);

It goes weird.
If I only have one call to rotateRelative, no matter the axis, it will work fine.

FlyingDodo
Jan 22, 2005
Not Extinct
I think I have finally solved my rotation problems. Wrong order of quaternion multiplication. This whole thing has been very :psyduck: .

FlyingDodo
Jan 22, 2005
Not Extinct
dogmaan if you want to make your own editor based around the quake3 .map format I suggest you read this: http://mattn.ninex.info/files/MAPFiles.pdf

FlyingDodo
Jan 22, 2005
Not Extinct
Are there any good books or other resources on constructing a potentially visible set from a bsp tree? All I can find is one webpage with minimal information. ( http://www.exaflop.org/docs/naifgfx/naifebsp.html ) Google is not really helping, I cant find any books or anything at all.

FlyingDodo
Jan 22, 2005
Not Extinct

OneEightHundred posted:

...portal stuff...

Thank you for your explanation alhough I'm stil a bit confused as to how to find the portals (I understand the idea behind it, but I'm having trouble turning it into code) I am aware that manually placed portals are how it's usually done now. I'm interested in a PVS from a more educational point of view, but I am more interested in automatically placed portals because they can be used for removing invisible surfaces by starting from leaves which have a known point considered 'inside' such as a player start point and then flood filling through portals, and any leaves not reached can have their polygons marked as not visible. Building a PVS from creating those portals is more of a little something extra I can do when I have the portals. If I have them, I might as well use them.

I have found an article with some pseudo code, but it doesn't seem to make much sense to me. The following pseudo code came from http://www.devmaster.net/articles/hidden-surface-removal/

code:

► PLACE-PORTALS
* Indata:
*   PortalPolygon – Polygon to push down the tree
*   Node – The node that we are currently visiting.
* Outdata:
*   None
* Effect:
*   Pushes a portal polygon down through the tree clipping when it
*   needs it. The output of this function will be that each node
*   contains a list of portal polygons where each portal connects
*   exactly two nodes.

PLACE-PORTALS (PortalPolygon, Node)
1  if (IS-LEAF (Node))
       // The portal is checked against every polygon in the node. When the
       // portal polygon is spanning the plane defined by a polygon it will
       // be clipped against that plane. The two resulting parts will be
       // sent down from the top of the tree again.
2      for (each polygon P2 in Node)
3          IsClipped = false
4          if (CALCULATE-SIDE (P2, PortalPolygon) = SPANNING)
5              IsClipped = true
6             (RightPart, LeftPart) = CLIP-POLYGON (P2, PortalPolygon)
7             PLACE-PORTALS (RightPart, RootNode)
8             PLACE-PORTALS (LeftPart, RootNode)
9      if (not IsClipped)
10         Remove the parts of the portal polygon that coincide with
           other polygons in this node.  //see description below
11         Add this node to the set of connected nodes in this portal polygon.
12 else
13     if (the dividing polygon of this node hasn’t been pushed down the tree)
14         Create a polygon P that is larger than the bounding box that
           contains all polygons in the sub trees of this node that
           lies in the same plane as the dividing polygon.
15         PLACE-PORTALS (P, Node.LeftChild)
16         PLACE-PORTALS (P, Node.RightChild)
17     Side = CALCULATE-SIDE (Node.Divider, PortalPolygon)
18     if (Side = POSITIVE)
19         (RightPart, LeftPart) = CLIP-POLYGON(P2, PortalPolygon)
20         PLACE-PORTALS (RightPart, RootNode)
21         PLACE-PORTALS (LeftPart, RootNode)
22     if (Side = POSITIVE or COINCIDING)
23         PLACE-PORTALS (PortalPolygon, Node.RightChild)
24     if (Side = NEGATIVE or COINCIDING)
25         PLACE-PORTALS (PortalPolygon, Node.LeftChild)

Shouldn't the line marked 18 be if(Side = SPANNING) otherwise clipping by a polygon in front of another would just have the front part having the entire original polygon and the back empty. Also in lines 20 and 21 why do the pieces go down from the root of the tree, why not left/right child node? Are these mistakes or am I missing something I havent thought of?

FlyingDodo
Jan 22, 2005
Not Extinct
Ok but what about lines 18-21? They appear nonsensical to me. Surely this has to be a mistake.

code:
18     if (Side = POSITIVE)
19         (RightPart, LeftPart) = CLIP-POLYGON(P2, PortalPolygon)
20         PLACE-PORTALS (RightPart, RootNode)
21         PLACE-PORTALS (LeftPart, RootNode)
Shouldn't it be this:

code:
18     if (Side = SPANNING)
19         (RightPart, LeftPart) = CLIP-POLYGON(Node.Divider, PortalPolygon)
20         PLACE-PORTALS (RightPart, RootNode)
21         PLACE-PORTALS (LeftPart, RootNode)

FlyingDodo fucked around with this message at 19:40 on Jun 8, 2011

FlyingDodo
Jan 22, 2005
Not Extinct
I have a rather puzzling problem relating to constructing an AABB tree and its peformance, it seems to be far too slow. Firstly some information about the tree. It is a binary tree and built by inserting element one at a time. Data is only stored in leaf nodes, all other nodes just bounding boxes.

When inserting an element, if the current node is not a leaf node, the current nodes bounding box is enlarged so it is big enough to contain the element being inserted. Then one of the two child nodes is chosen by checking if the inserted element is inside the bounding box of one of the two child nodes, if it is it gets sent down the respective node. If it is not inside either but it is intersecting then it chooses the one it intersects. If it does not intersect either of the nodes then it calculates the manhattan distance between the centre of the child nodes bounding box and the centre of element to be inserted bounding box. If the distance is greater it chooses the node with the greater manhattan distance. For whatever reason this seems to give better performance than checking if it is less.

The performance does not seem to be very good overall. There is, up until around 14000 elements in the tree, better performance simply by comparing a given AABB against every other AABB. Even then it is only a ~100ms difference of ~700ms vs ~800ms.

I am assuming there is something wrong with how I insert things into the tree. Anything I can find on building AABB trees is either how to build them if you already have all elements in advance (not in this case), or the algorithm given is similar to what I already do, but chooses the child node based on some mysterious unexplained cost function. One suggests manhattan distance but as I have said it strangely gives better performance choosing the further node. Thoughts anyone?


edit: found and fixed a bug to do with the manhattan distance check, which (sort of) explained why at the time choosing the further distance made it faster. Now it is checking which is closer instead of further away, which is obviously correct. The time is now down to ~400ms vs 800ms. I still think it could be faster. It seems that having a good cost function is key to performance.

FlyingDodo fucked around with this message at 18:37 on Jun 27, 2011

FlyingDodo
Jan 22, 2005
Not Extinct

Gerblyn posted:

Have you tried outputting any data on the tree? You want to have a look at how deep it is, and how many entities each leaf node contains. Generally you want to have your entities spread fairly evenly throughout the leaves, since your tree does very little good if 90% of your entities are all in the same leaf. Also, if you have a malfunction building the tree, you may end up with a tree thousands of layers deep (also bad).

By design each leaf contains only one element, and for the ~14,000 element test the maximum depth was 65. It's not excessively deep but still seems a bit too deep for the number of elements in it.

edit: average (mean) depth for ~14,000 element test is around 25.

FlyingDodo fucked around with this message at 06:53 on Jun 28, 2011

FlyingDodo
Jan 22, 2005
Not Extinct

Gerblyn posted:

I guess what's happening then is that the nodes in the graph are overlapping too much, so when you check an AABB against the tree it ends up checking a few thousand nodes instead of the 50 or so it would in perfect conditions? Looking at the algorithm you describe for building the tree, I can see why that would happen and I'm not really sure there's a way of fixing it; it sounds as if the type of binary tree you're using simply isn't suited to the task, due to either having too many elements, having the elements too densely packed together or both. Have you tried letting the system put more than one element in each leaf? That would simplify the tree structure and may cut down on unnecessary AABB checks.

Failing that, you might have more luck with a quad tree, like the one described on this page. He's using 1 element per node, but considering the number of test elements you have I'd have 5-10.

Edit: Now that I think about it, with either of these tree structures a leaf should be able to store at least as many elements as a node can store children. i.e. With your binary tree it's better to have a leaf containing two elements than a node containing two leaves, each of which contains one element. The leaf with two elements gets 2 AABB checks (one for each element), where the node with two leaves gets 2-4 (2 to check each leaf and up to 2 to check the elements in the leaves). Similarly a quad tree leaf should be able to store at least 4 elements before splitting.

I think I will stick to an AABB tree for now, but I will try different numbers of elements stored in each leaf. You said that you can see why the algorithm I'm using for building tree is a problem, is there a better way of building the tree? Or a better way to choose which child node to send an inserted element down?

Hopefully increasing the number of elements stored in a leaf will help, perhaps have no limit but instead limit the depth of the tree. Only one way to find out.

FlyingDodo
Jan 22, 2005
Not Extinct

Gerblyn posted:

I believe part of the problem comes from the fact that the algorithm is growing the AABB of a node when an element is placed into it, to make sure the element completely fits. This is causing the nodes to overlap with their siblings, which increases the chance that an AABB check have to search down both siblings, rather than just one of them. This is just speculation on my part, but given what you've said so far it's the only thing I can think of that makes sense.

One possible solution is to have the root node encompass the entirely game world. Then, instead of dynamically shaping the child nodes, you just split a parent node in half, guaranteeing that sibling nodes never overlap. If an element intersects both child nodes, you add it to a list of elements in the parent, rather than trying to re-size one of the children so it fits. Essentially, you do what they guys does in the page I linked in my previous post, except you use a binary tree instead of a quad tree. This should lead to a more balanced tree, and should make your check search the tree more efficiently. The downside is that your elements won't be as evenly distributed between leaves, so if you have elements that are very clustered up around each other, it might actually make things worse (though having lots of elements clumped up together is going to gently caress up most spatial partitioning algorithms anyway).

First though, I think limiting the depth and allowing multiple elements per node is definitely a good place to start, it may fix the issue outright.


I thought about too many nodes being visited, the 14,000 element test visited ~350 nodes on average. Too many? Maybe it is time to throw out the code I have and re-write it from the start, taking into account thing you've said.

FlyingDodo
Jan 22, 2005
Not Extinct
Just using new. However I don't think this is relevant to the speed of querying the tree as nothing is allocated/deallocated when searching. The only allocation that might happen is a re-sizing of an std::vector which collects the results.

edit: for more information; the test data is ~14,000 brushes from a quake3 level. The tree is created from those then each one is sent through the tree to find any brushes bounding boxes that touch the bounding box of the test brush. All 14,000 brushes are tested in this way. Checking all 14,000 with the tree takes ~300-400 milliseconds. Testing without the tree takes ~700-800 milliseconds. So one query using the tree takes on average ~0.021-0.028 milliseconds per query. Without the tree it is about double the time.

FlyingDodo fucked around with this message at 16:33 on Jun 30, 2011

FlyingDodo
Jan 22, 2005
Not Extinct
It is compiled in release mode and I don't think it has to do with std::vector, if I comment out anything to do with it and just traverse the tree during search without collecting the results it still takes just as long. Point noted about memory allocation, something possible add to do in a re-write. However I'm thinking it's just a bad data structure/algorithm. I supposed I better get to work on something new rather than screwing around with what I have.

FlyingDodo
Jan 22, 2005
Not Extinct
I re-wrote my bounding volume hierachy, so it is more like a kd-tree now. There is the ability to put limits on tree depth and the number of elements in a node.

So the algorithm/data structure is now as follow. Each internal node has an axis aligned splitting plane. When something is inserted into the tree if the node is internal and the inserted element spans the splitting plane it stays at that node.

If it's in front, goes to the front child node, if back goes to the back child node. This repeats until it either spans the plane and stays in the internal node or hits a leaf node. If the node is a leaf node the element is inserted into that node.

If the number of elements in a leaf node reach a set limit the node is split by a plane at the centre of the bounding box of that node. The plane is axis aligned, the axis chosen by mod 3 of the depth. Leaf nodes can go over the limit of number of elements if max depth has been reached, and internal nodes don't have a limit because all elements stored in an internal node cannot be split as they span the splitting plane.

Despite this re-write it actually seems to be slower than my previous attempt, even though there can't be any overlap of nodes and there is a limit on depth and allowing for multiple elements per node. It seems like both ways I have tried only reduce the number of bounding box checks by about 60%, still leaving a huge amount.

FlyingDodo
Jan 22, 2005
Not Extinct

ZombieApostate posted:

Fuuuuuuuuck I hate programming sometimes. I just spent several days trying to figure out what went wrong in my conversion from OpenGL 2.x to 3.x and vertex arrays to VBOs/VAOs. Not only did my research leave me with an rear end backward impression of how VAOs are supposed to work, but I introduced a stupid little vertex index offset bug and every time I started to investigate one possibility, it started to look like the other was actually the problem.

On the one hand, I'm relieved that it's finally fixed, but on the other hand I'm pissed off that it took this long to figure it all out. Some of the documentation for the newer OpenGL stuff is absolute garbage. The docs for glDrawElements say the last parameter is supposed to be a pointer to your array of indices, but of course what it ACTUALLY wants is an offset into the buffer you already set. Not that I could find any mention of that until I stumbled across it in a tutorial on some random guy's website. And none of the tutorials I could find go beyond drawing a single box or triangle or whatever, so how VAOs and VBOs are supposed to be set up for multiple objects is a loving mystery unless you can find someone who's been through this mess already to tell you.

:argh: :cry: :psyboom: :suicide:

Take your pick. gently caress.

I had the same problems switching from old fixed function immediate mode to 4.1. It also took me forever to get anything working, the exact same issues with DrawElements and VAO/VBO problems. Next is to get textures working using shaders.

There is very little information on opengl, at least information that is up to date and correct.

FlyingDodo
Jan 22, 2005
Not Extinct
I have a question regarding calculating texture coordinates for a quake3 level (.map NOT .bsp). The textures appear to be scaled and rotated correctly (for about 99.9% of the time) but the translation is not correct a lot of the time. Sometimes textures do appear to be in the correct position but mostly not.



In the code below m_texX and m_texY are an orthonormal basis for the plane that the polygon is on. The basis vectors are rotated according to the texture rotation angle. position is the 3d vertex position, m_translation is the 2d translation for the texture, m_scale is the 2d scaling and m_dimensions is the width/height of the texture.
code:
	double s = ((position.dot(m_texX)) + (m_translation.getX())) / (m_scale.getX() *  m_dimensions.getX());
	double t = ((position.dot(m_texY)) + (m_translation.getY())) / (m_scale.getY() * m_dimensions.getY());
What could I be doing wrong? It seems strange to be so very close to being correct but not quite.
This is a problem that has been bugging me for a very long time. I am trying to figure out why it doesn't work properly but I have absolutely no idea.

FlyingDodo
Jan 22, 2005
Not Extinct
I have changed how I'm calculating texture coordinates, it has improved but it still isn't right. I have two screenshots, one from me and one from the quake3 level editor.

http://imgur.com/a/xTnCg

The top image is from me which has one incorrect texture alignment which stands out but if you compare it to the quake3 editor screenshot you will notice more inconsistencies.

One thing I noticed is that reversing a texture axis can fix an incorrect looking texture, but will break others that looked correct before. My only theory so far is that how I am getting the initial axes is different to how the quake3 editor does it, sometimes they match and sometimes they don't giving incorrect results.

I get the texture axes for a polygon like this:

code:
		MathLib::Plane p(normal,0);
		p.orthoBasis(&m_texX,&m_texY);	

		m_texX = m_rotation.rotatePoint(m_texX);
		m_texY = MathLib::Vector3::ZERO - m_rotation.rotatePoint(m_texY);
and calculate the texture coordinates like this:

code:

	double s = ((position.dot(m_texX) / m_dimensions.getX()) / m_scale.getX()) + (m_translation.getX() / m_dimensions.getX());
	double t = -((position.dot(m_texY) / m_dimensions.getY()) / m_scale.getY()) - (m_translation.getY() / m_dimensions.getY());

Without the negatives in there the texture coordinates end up even worse, with some upside down and even more shifted to the wrong place.

FlyingDodo
Jan 22, 2005
Not Extinct
That looks very useful, thank you. Hopefully I can get this working properly. I've had this program working for a while except for the texture coordinates and has been bugging me for a very long time.

FlyingDodo
Jan 22, 2005
Not Extinct

OneEightHundred posted:

The way Quake 3 calculates brush vectors is based on some extreme legacy code and does not work intuitively.

Take a look at the following functions:

http://www.nanobit.net/doxy/quake3/q3map_2map_8c-source.html#l00680
http://www.nanobit.net/doxy/quake3/textures_8c-source.html#l00075
http://www.nanobit.net/doxy/quake3/surface_8c-source.html#l00062

Well now it works, although I don't quite understand what on earth is going on in the quake3 code. I pretty much had to do a copy-paste. Although I supposed there isn't much choice in it, if the texture coordinates have to be calculated like that I guess just how it has to be.

FlyingDodo
Jan 22, 2005
Not Extinct
Quick question; for collision detection (essentially just ray tracing) with my code on the q3dm1sample map from quake3 on an AMD X4 955 computer takes around 18 seconds to do 1 million ray traces. A bit on the slow side?

FlyingDodo
Jan 22, 2005
Not Extinct
I'm curious as to how it compares to something like q3map in comparison when doing tracing for calculating lightmaps, or just within quake3 in general. Is there any easy way to test quake3's tracing speed?

FlyingDodo
Jan 22, 2005
Not Extinct
I'm not actually considering using lightmaps, I just looking for a way to benchmark my code against an existing games line tracing. I suppose I could do a silly mod to quake3 and make a weapon do a ton of traces and time them and do a console output.

FlyingDodo
Jan 22, 2005
Not Extinct
Speaking of games maps with with territories. I need a way of generating the maps randomly. I have an array which represents a hex tile map. Each territory consists of a list of tile positions.

I was thinking for creating each territory generating a starting tile location, then step through each territory and expanding by one random tile at a time until the whole map is full.

This problem must have been dealt with before, but I'm having difficulty locating any good resources.

FlyingDodo
Jan 22, 2005
Not Extinct
I'm having a lot of trouble trying to animate asf/amc skeletons. I have reduced the problem down to something as simple as possible, by just drawing spheres at each bone. It works fine for drawing the skeleton in the bind pose by only using translation and no rotation. Problems happen when I try to animate it. I am using old style opengl.

Pseudocode showing way I'm doing it now is something like this:

code:
draw(bone* bone){

 glPushMatrix();
 glTranslatef(bone->dirx * bone->length,bone->diry * bone->length,bone->dirz * bone->length);
 drawSphere();

 for(unsigned int i = 0; i < bone->numChildren; i++){
     draw(bone->children[i]);
 }
 glPopMatrix();
}
Doing just this works perfectly fine for the static bind pose, however if I introduce any calls to glRotatef() to rotate the bone it does not animate properly. I have heard that each bone in asf/amc files does have its own rotation axes relative to the world, but if you rotate to the local axes then do the actual bone rotation then draw the child bones the child bones rotation axes will be incorrect, as the new rotation will be relative to the parent. If you pop the matrix before drawing the children then you lose the rotation altogether meaning the child bones will not translate into the correct position. I am trying to think of how I can just use glTranslate,glRotate glPushMatrix and glPopMatrix() function calls to animate properly, without manually touching the opengl matrix.

FlyingDodo fucked around with this message at 17:28 on Aug 9, 2012

FlyingDodo
Jan 22, 2005
Not Extinct
Whats the easiest way to move a point around a sphere controlled by the mouse? Something like an arcball camera, except I only want to move a point rather than create a camera matrix. I'm guessing quaternions are involed somehow.

I have already tried this: http://cgmath.blogspot.co.nz/2009/03/arc-ball-rotation-using-quaternion.html

But it's not working properly, the point does rotate but the rotation does not move correctly. Hard to explain.

FlyingDodo
Jan 22, 2005
Not Extinct
I have a quad tree of terrain where each node generates procedurally. At the moment there are gaps between nodes of different levels of detail.

I'm guessing there are two points to the solution. First working out what the difference in level of detail is with a node next to the current node, and then second changing the higher level of detail node to match up its edges with the nodes it touches.

I'm thinking for the first part getting points in the centre of the edges shifted slightly to outside the current node above/below/left/right then sending the points down the quad tree to see which nodes are along the edges and getting what the levels of detail those nodes are at.

Then using this information to decide how many vertices a node should skip along the edge so the edges join correctly.

Good enough? Or is there a more standard way of doing it?

Adbot
ADBOT LOVES YOU

FlyingDodo
Jan 22, 2005
Not Extinct

Paniolo posted:



For heightmap terrain the most common approach is to generate shim meshes which stitch between the LOD levels.

So I guess the question becomes, what is the best way to find which other nodes share edges of a given node in a quad tree?

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply