On 12/21/2018 at 11:02 PM, Gnollrunner said:Well I tend to be too lazy to analyze code ? but ..... here's some code from one of my simpler object follow classes that I use with DirectX 11 for cameras. I'm not gong to claim it's the most efferent or anything but it works OK. I should say I used my own libraries so the code might look a little alien but I guess it should be easy enough to understand.
First an explanation ...... m_clTarget in the second code block is of type CDLPositionRecord which is a class that holds the position, and three vectors that point forward, up and right in relation to whatever character (or any object really) that you want to follow. You really only need two of the vectors to define an object's orientation, but having all three is sometimes convenient. Here's what the class and it's parent look like. You can ignore iFrame. Note that CDLPositionStruct is the same as CDLPositionRecord for all practical purposes.
struct CDLPositionStruct { CDLPositionStruct() {} CDLPositionStruct(EDLPositionDefault eDummy) : clPosition(0.0,0.0,0.0), clFace(0.0,0.0,1.0), clUp(0.0,1.0,0.0), clRight(1.0,0.0,0.0) {} CDLDblPoint clPosition; CDLDblVector clFace; CDLDblVector clUp; CDLDblVector clRight; }; /** ***************************************************************** ** ***************************************************************** **/ struct CDLPositionRecord : public CDLPositionStruct { IDLFrame iFrame; };
Here is the code that actually controls the camera:
void CDLReferenceFollow::Update(const CDLRenderData *pRenderData) { // Are we tracking? if (m_bTracking) { CDLObject *pTargetParent = this->m_pTarget()->GetParent()->GetParent(); // Target's reference and this reference should have the same parent assert(m_pParent == pTargetParent); // If our target moved or we changed elevation or azimuth we must recalculate m_bTargetMoved = m_pTarget()->GetFocus(m_clTarget); } m_mxChange.lock(); if (m_bChanged || m_bTargetMoved ) { CDLPositionStruct clTemp; CDLDblQuaternion clARot(this->m_clTarget.clUp,this->m_fCAzimuth); clTemp.clFace = clARot.Rotate(this->m_clTarget.clFace); clTemp.clRight.CrossProduct(clTemp.clFace, this->m_clTarget.clUp); CDLDblQuaternion clERot( clTemp.clRight,this->m_fCElevation); clTemp.clFace = clERot.Rotate(clTemp.clFace); // Normalize for good measure clTemp.clFace.Normalize(); clTemp.clUp.CrossProduct(clTemp.clFace, clTemp.clRight); clTemp.clPosition = m_clTarget.clPosition - (clTemp.clFace * this->m_fCDistance); // Thread safe store m_clPos.store(clTemp); m_bChanged = m_bTargetMoved = false; } m_mxChange.unlock(); }
At the top we are basically getting the position of our character (if tracking is turned on). You can ignore most of this, but just know that m_clTraget gets the character position and orientation data. We also get m_bTargetMoved which is really an optimization that tells us if the character data changed from the last call but it's not so important to implement this.
m_bChanged is another optimization which tells us if either the Azimuth, Elevation or Distance from the target character has changed. These values are relative to the target character position and orientation. So for instance you could just set them to follow directly behind the character at some fixed distance, or you could have some elevation or even view the character from the side as it moves. Whatever the case the camera will always point to the clPosition field of m_clTarget. In general you want to make that its head.
We next use all our data to calculate the position and orientation of our camera and put it directly into clTemp, which is then copied to m_clPos, which is just an atomic version of a CDLPositionStruct for thread safety.
Finally we clear our m_bChanged and m_bTargetMoved and unlock our mutex.A couple more things. My stuff has to work on a spherical world so the character can be at any orientation. You could simplify this a lot if you assume a flat world with the character always pointing up, but then again you can use this for spacecraft too so there are some advantages. You can also change m_fCAzimuth, m_fCElevation and m_fCDistance freely at any time, so it's easy to attach those to the mouse and/or keyboard.
Hope this helps somewhat.. Good luck!Edit: one more point. For this kind of camera you will probably eventually have to add collision detection which is not yet in my code. One way to do this is to simply walk back from the character along the camera facing vector and then set the distance to just before the first collision. It's not so bad once you have your world data in an octree or some other collision friendly data structure, but it's something to consider.
Would you be able to go into more detail about what exactly you're doing here?
CDLDblQuaternion clARot(this->m_clTarget.clUp,this->m_fCAzimuth);
clTemp.clFace = clARot.Rotate(this->m_clTarget.clFace);
clTemp.clRight.CrossProduct(clTemp.clFace, this->m_clTarget.clUp);
CDLDblQuaternion clERot( clTemp.clRight,this->m_fCElevation);
clTemp.clFace = clERot.Rotate(clTemp.clFace);
I've not done Quaternion's before so it's a little confusing