martyj Posted April 21, 2016 Share Posted April 21, 2016 I have been testing some camera movement code, and there is a bug with getting the rotation of an Entity OS: Windows 10 LE Version: Beta Branch 4.0 Professional Graphics Card(s): AMD R9 280x, Nvidia GTX 650 TI App Start box = Model::Box(2, 2, 2); box->SetColor(1.0, 0.0, 0.0, 1.0); box->SetPosition(Vec3(5.0, 3.0, 0.0), true); box->SetRotation(Vec3(57.250671f, 9.541766, 114.50135), true); App Loop if (window->KeyHit(Key::L)) { Vec3 next_rot = Vec3(57.493263f, 9.582211, 114.986526); Vec3 rot = box->GetRotation(true); Vec3 diff = next_rot - rot; box->Turn(diff, true); //box->SetRotation(next_rot, true); // Will return the same results with GetRotation afterwards System::Print(next_rot); System::Print(rot); System::Print(diff); System::Print(box->GetRotation(true)); // Bug shows here } This will print the following As you can see, the global rotation of the box changes drastically compared to the turn value. I also wrote a Lua script that shows the error --Initialize Steamworks (optional) Steamworks:Initialize() --Set the application title title="RotateTest" --Create a window local windowstyle = window.Titlebar if System:GetProperty("fullscreen")=="1" then windowstyle=windowstyle+window.FullScreen end window=Window:Create(title,0,0,System:GetProperty("screenwidth","1024"),System:GetProperty("screenheight","768"),windowstyle) window:HideMouse() --Create the graphics context context=Context:Create(window,0) if context==nil then return end --Create a world world=World:Create() world:SetLightQuality((System:GetProperty("lightquality","1"))) --Load a map local mapfile = System:GetProperty("map","Maps/start.map") if Map:Load(mapfile)==false then return end box=Model:Box(2,2,2) box:SetColor(1, 0, 0, 1) box:SetPosition(5.0, 3.0, 0.0, true) box:SetRotation(Vec3(57.250671, 9.541766, 114.50135), true) while window:KeyDown(Key.Escape)==false do --If window has been closed, end the program if window:Closed() then break end --Handle map change if changemapname~=nil then --Clear all entities world:Clear() --Load the next map Time:Pause() if Map:Load("Maps/"..changemapname..".map")==false then return end Time:Resume() changemapname = nil end if window:KeyHit(Key.L) then next_rot = Vec3(57.493263, 9.582211, 114.986526) rot = box:GetRotation(true) diff = next_rot - rot box:SetRotation(next_rot, true) System:Print(next_rot) System:Print(rot) System:Print(diff) System:Print(box:GetRotation(true)) end --Update the app timing Time:Update() --Update the world world:Update() --Render the world world:Render() --Render statistics context:SetBlendMode(Blend.Alpha) if DEBUG then context:SetColor(1,0,0,1) context:DrawText("Debug Mode",2,2) context:SetColor(1,1,1,1) context:DrawStats(2,22) context:SetBlendMode(Blend.Solid) else --Toggle statistics on and off if (window:KeyHit(Key.F11)) then showstats = not showstats end if showstats then context:SetColor(1,1,1,1) context:DrawText("FPS: "..Math:Round(Time:UPS()),2,2) end end --Refresh the screen context:Sync(true) end Quote Link to comment Share on other sites More sharing options...
Rick Posted April 21, 2016 Share Posted April 21, 2016 I'm shocked that works as Turn doesn't show taking a vec3 in the docs. Maybe that's why? http://www.leadwerks.com/werkspace/page/api-reference/_/entity/entityturn-r29 Your first App Loop code has you using Turn() but your example doesn't. Which is it? Using Turn() or not? Quote Link to comment Share on other sites More sharing options...
martyj Posted April 21, 2016 Author Share Posted April 21, 2016 Turn takes in a Vec3 in C++. virtual void Turn(const Vec3& rotation, const bool global = false);//lua virtual void Turn(const float x, const float y, const float z, const bool global=false);//lua It's not a problem with Turn or SetRotation. The problem is with GetRotation. The object actually appears correctly in the scene when you use SetRotation. The value returned from GetRotation is wrong. Quote Link to comment Share on other sites More sharing options...
reepblue Posted April 21, 2016 Share Posted April 21, 2016 Did you try: System::Print(box->GetQuaternion(true)); ?? Quote Cyclone - Ultra Game System - Component Preprocessor - Tex2TGA - Darkness Awaits Template (Leadwerks) If you like my work, consider supporting me on Patreon! Link to comment Share on other sites More sharing options...
thehankinator Posted April 21, 2016 Share Posted April 21, 2016 (edited) I reproduced the issue on LE stable, interesting thing is that if you change next_rot.x to 57.2, the value returned from GetRotation looks okay. Also the test script crashes because local windowstyle = window.Titlebar W in window should be capitalized I stripped out all the extra stuff, problem can be reproduced with the smaller Main.lua script below: local box=Model:Box(2,2,2) box:SetColor(1, 0, 0, 1) box:SetPosition(5.0, 3.0, 0.0, true) box:SetRotation(Vec3(57.250671, 9.541766, 114.50135), true) local next_rot = Vec3(57.493263, 9.582211, 114.986526) local rot = box:GetRotation(true) local diff = next_rot - rot box:SetRotation(next_rot, true) System:Print(next_rot) System:Print(rot) System:Print(diff) System:Print(box:GetRotation(true)) EDIT: For the love of god why wont the forum let me capitalize W in window.TitleBar? That probably explains why the original script had the problem in the first place. Edited April 21, 2016 by thehankinator Quote Link to comment Share on other sites More sharing options...
Josh Posted April 21, 2016 Share Posted April 21, 2016 I suspect you have encountered a case related to Gimbal lock, where the euler is insufficient to describe a rotation. With that roll value, around 57 degrees seems to be the point where the box flips around. This is actually something that caused problems in the Apollo 13 mission: You can't add degrees to Eulers on more than one axis. The Entity:Turn command will smoothly change the rotation of the box without these issues. Press the R and T keys to rotate the box: --Initialize Steamworks (optional) Steamworks:Initialize() --Set the application title title="RotateTest" --Create a window local windowstyle = window.Titlebar if System:GetProperty("fullscreen")=="1" then windowstyle=windowstyle+window.FullScreen end window=Window:Create(title,0,0,System:GetProperty("screenwidth","1024"),System:GetProperty("screenheight","768"),windowstyle) window:HideMouse() --Create the graphics context context=Context:Create(window,0) if context==nil then return end --Create a world world=World:Create() world:SetLightQuality((System:GetProperty("lightquality","1"))) --Load a map local cam = Camera:Create() cam:SetPosition(0,0,-5) local mapfile = System:GetProperty("map","Maps/start.map") if Map:Load(mapfile)==false then return end box=Model:Box(2,2,2) box:SetColor(1, 0, 0, 1) box:SetPosition(5.0, 3.0, 0.0, true) box:SetRotation(Vec3(47.250671, 9.541766, 114.50135), true) while window:KeyDown(Key.Escape)==false do --If window has been closed, end the program if window:Closed() then break end --Handle map change if changemapname~=nil then --Clear all entities world:Clear() --Load the next map Time:Pause() --if Map:Load("Maps/"..changemapname..".map")==false then return end Time:Resume() changemapname = nil end if window:KeyDown(Key.L) then next_rot = Vec3(57.493263, 9.582211, 114.986526) rot = box:GetRotation(true) rot.x = rot.x + 1 diff = next_rot - rot box:SetRotation(rot, true) System:Print(next_rot) System:Print(rot) System:Print(diff) System:Print(box:GetRotation(true)) end if window:KeyDown(Key.T) then box:Turn(0.1,0,0) end if window:KeyDown(Key.R) then box:Turn(-0.1,0,0) end --Update the app timing Time:Update() --Update the world world:Update() --Render the world world:Render() --Render statistics context:SetBlendMode(Blend.Alpha) if DEBUG then context:SetColor(1,0,0,1) context:DrawText("Debug Mode",2,2) context:SetColor(1,1,1,1) context:DrawStats(2,22) context:SetBlendMode(Blend.Solid) else --Toggle statistics on and off if (window:KeyHit(Key.F11)) then showstats = not showstats end if showstats then context:SetColor(1,1,1,1) context:DrawText("FPS: "..Math:Round(Time:UPS()),2,2) end end --Refresh the screen context:Sync(true) end Quote My job is to make tools you love, with the features you want, and performance you can't live without. Link to comment Share on other sites More sharing options...
thehankinator Posted April 21, 2016 Share Posted April 21, 2016 When using: box:SetRotation(Vec3(57.493263, 9.582211, 114.986526), true) Under the hood, is that still considered adding degrees even though it's a hard coded value? 1 Quote Link to comment Share on other sites More sharing options...
Josh Posted April 21, 2016 Share Posted April 21, 2016 I think that is a euler value that is ambiguous. Eulers can't be operated on in an intuitive way when you have roll in the equation. The "real" rotation Leadwerks uses is the object's quaternion, and the eulers are extracted from that. Quaternions are not intuitive in the least, there's actually a whole book on visualizing quaternions: http://www.amazon.com/Visualizing-Quaternions-Kaufmann-Interactive-Technology/dp/0120884003 Quote My job is to make tools you love, with the features you want, and performance you can't live without. Link to comment Share on other sites More sharing options...
thehankinator Posted April 21, 2016 Share Posted April 21, 2016 More of a discussion on the subject rather than the bug report but what's the right way to express a direction that would be an ambiguous euler value like that? Is it best to just avoid using the result of GetRotation()? Quote Link to comment Share on other sites More sharing options...
Josh Posted April 21, 2016 Share Posted April 21, 2016 Really the only time you will be manually inputting a rotation it's going to be an axis-aligned value likle [0,0,0], [90,0,0], etc. Otherwise you will be using Turn(). I can't think of any time you would be inputting random numbers like that. If you want to copy one entity's rotation use GetMatrix / SetMatrix or GetQuaterion / SetRotation (with the quat). Basically Quaternion -> Euler is a potentially lossy operation, like JPEG compression. Quote My job is to make tools you love, with the features you want, and performance you can't live without. Link to comment Share on other sites More sharing options...
martyj Posted April 21, 2016 Author Share Posted April 21, 2016 So long story short: Turn(rot.x, 0, 0) Turn(0, rot.y, 0) Turn(0, 0, rot.z) to apply a full object rotation? Quote Link to comment Share on other sites More sharing options...
martyj Posted April 22, 2016 Author Share Posted April 22, 2016 I am still running into issues even with turning each axis on its own. My case is such that I have a few given Pivots in the game, and I generate multiple points between these pivots to move a camera smoothly between these points. This also rotates the camera based upon the rotation of the points. My test points are kind of uncommon. Vec3 positionstart = Vec3(2, 1, 0) Vec3 rotationstart = Vec3(0, 0, 0) Vec3 positionend = Vec3(5, 3, 0) Vec3 rotationend = Vec3(90, 15, 180) Vec3 rot = box->GetRotation(true); Vec3 new_pos; Vec3 new_rot; cur->nextPoint(Time::GetCurrent(), new_pos, new_rot); Vec3 rotDiff = new_rot - rot; box->SetPosition(new_pos); box->Turn(rotDiff.x, 0, 0, true); box->Turn(0, rotDiff.y, 0, true); box->Turn(0, 0, rotDiff.z, true); Quote Link to comment Share on other sites More sharing options...
Josh Posted April 23, 2016 Share Posted April 23, 2016 So you have predetermined rotations and you want to smoothly interpolate between them? Get the quaternion and use the Quat:Slerp() function. This will provide 100% smooth interpolation between any rotations: http://www.leadwerks.com/werkspace/page/api-reference/_/quat/quatslerp-r898 Then use Entity:SetQuaternion to set the rotation with your quat. Quote My job is to make tools you love, with the features you want, and performance you can't live without. Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.