@UberGoober I’ll try playing with that later. I have other things I need to do for the next few hours.
@UberGoober Is this closer. Tap the screen above or below the middle to select that entity. Then use the sliders to rotate that entity. I only did 2 entities, but it can be expanded.
viewer.mode=STANDARD
function setup()
rectMode(CENTER)
parameter.integer("gx",-180,180,0)
parameter.integer("gy",-180,180,0)
parameter.integer("gz",-180,180,0)
scene = craft.scene()
scene.camera.position=vec3(0,0,-5)
ground1 = scene:entity()
ground1.model = craft.model.cube(vec3(1,.2,1))
ground1.material = craft.material(asset.builtin.Materials.Specular)
ground1.material.map = readImage(asset.builtin.Surfaces.Desert_Cliff_Roughness)
ground1.position = vec3(0,1,1)
ground1.eulersForParameterSliders = vec3(0,0,0)
ground2 = scene:entity()
ground2.model = craft.model.cube(vec3(1,.2,1))
ground2.material = craft.material(asset.builtin.Materials.Specular)
ground2.material.map = readImage(asset.builtin.Surfaces.Desert_Cliff_Roughness)
ground2.position = vec3(0,-1,1)
g1=vec3(0,0,0)
g2=vec3(0,0,0)
s=0
fill(255)
end
function update(dt)
scene:update(dt)
draw()
end
function draw()
background(0)
if s==1 then
g1=vec3(gx,gy,gz)
elseif s==2 then
g2=vec3(gx,gy,gz)
end
ground1.rotation=quat.eulerAngles(g1.x,g1.y,g1.z)
ground2.rotation=quat.eulerAngles(g2.x,g2.y,g2.z)
scene:draw()
hold1=g1
hold2=g2
fill(255)
if s==1 then
text("selected",50,HEIGHT*.75)
elseif s==2 then
text("selected",50,HEIGHT*.25)
end
end
function touched(t)
if t.state==BEGAN then
if t.y >HEIGHT/2 then
s=1
gx=hold1.x
gy=hold1.y
gz=hold1.z
ground1.rotation=quat.eulerAngles(g1.x,g1.y,g1.z)
else
s=2
gx=hold2.x
gy=hold2.y
gz=hold2.z
ground1.rotation=quat.eulerAngles(g2.x,g2.y,g2.z)
end
end
end
@dave1707 storing the display Eulers in hold1 and hold2 is basically the same solution as storing the display Eulers on the entities, right?
In both cases it’s creating a new variable to hold the display values, and I think either implementation would be fine.
What I’m wondering is if it can be done without creating any new variables, just purely by reverse-engineering the display values from the entity’s quats or Eulers or some combination.
It’s not a huge deal to create a new variable, of course, I just wondered if someone knew a solution to the reverse-engineering problem.
I’m lucky your demo turned out to be so close to the thing I’m actually doing, it made it a lot easier to discuss.
@UberGoober Is this any better. Removed the hold variable.
viewer.mode=STANDARD
function setup()
rectMode(CENTER)
parameter.integer("gx",-180,180,0)
parameter.integer("gy",-180,180,0)
parameter.integer("gz",-180,180,0)
toggle=false
scene = craft.scene()
scene.camera.position=vec3(0,0,-5)
ground1 = scene:entity()
ground1.model = craft.model.cube(vec3(1,.2,1))
ground1.material = craft.material(asset.builtin.Materials.Specular)
ground1.material.map = readImage(asset.builtin.Surfaces.Desert_Cliff_Roughness)
ground1.position = vec3(0,1,1)
ground1.eulersForParameterSliders = vec3(0,0,0)
ground2 = scene:entity()
ground2.model = craft.model.cube(vec3(1,.2,1))
ground2.material = craft.material(asset.builtin.Materials.Specular)
ground2.material.map = readImage(asset.builtin.Surfaces.Desert_Cliff_Roughness)
ground2.position = vec3(0,-1,1)
gx1,gy1,gz1=0,0,0
gx2,gy2,gz2=0,0,0
s=0
fill(255)
end
function update(dt)
scene:update(dt)
draw()
end
function draw()
if s==1 then
gx1,gy1,gz1=gx,gy,gz
elseif s==2 then
gx2,gy2,gz2=gx,gy,gz
end
ground1.rotation=quat.eulerAngles(gx1,gy1,gz1)
ground2.rotation=quat.eulerAngles(gx2,gy2,gz2)
scene:draw()
if s==1 then
text("selected",50,HEIGHT*.75)
elseif s==2 then
text("selected",50,HEIGHT*.25)
end
end
function touched(t)
if t.state==BEGAN then
if t.y >HEIGHT/2 then
s=1
gx=gx1
gy=gy1
gz=gz1
ground1.rotation=quat.eulerAngles(gx1,gy1,gz1)
else
s=2
gx=gx2
gy=gy2
gz=gz2
ground1.rotation=quat.eulerAngles(gx2,gy2,gz2)
end
end
end
@UberGoober i’m not sure i understand what you’re trying to do. are you trying to get the euler angles out of a rotated thing, rather than save a set for each thing in your own code? what can we get from the thing? can we get a quat? are we looking for a way to convert quat to euler? or … would it help to back up a step and look at what you want to accomplish in-screen? or … something else?
thanks!
if you just want the angles from a thing, i think it’s thing.rotation:angles()
check the quat docs in the reference
are you trying to get the euler angles out of a rotated thing, rather than save a set for each thing in your own code?
Yes, I want to use the rotated thing’s own baked-in quats, or its baked-in Eulers, to calculate the values that should be shown on x,y,z sliders.
what can we get from the thing? can we get a quat? are we looking for a way to convert quat to euler?
We can get quats and Eulers. But:
- the Eulers we get out, as you may know, often don’t match the Eulers we put in, so they’re unreliable, and often not useful on x,y,z sliders, which is the whole source of the trouble I’m having.
- the quats we get out can be converted to Eulers using the angles() function, but again, the Eulers we use to calculate a quat are not guaranteed to be the Eulers we get out of it.
In the end it’s not a huge deal to store a set of values for each individual entity, so if there’s no way to calculate this, I’ll just do that.
does thing.rotation:angles() not do it? got a test?
if we put them back and the thing isn’t differently rotated, it’s all good, innit? there’s more than one way to get to a given rotation, and some paths create gimbal lock, so working with quats is often better. for one-shot user input euler is ok.
grr, guess i have to code something …
No you don’t
@RonJeffries Look in my post above that the formatting is all screwy on. There’s a commented-out line that says “doesn’t work”.
Remove the comment marks and comment out the line below it. You’ll see the results.
@RonJeffries I forgot to mention it’s easiest to see what’s going wrong if you set the sliders to negative values during the test.
@UberGoober Thats why I was using variables to keep track of everything. I noticed that if I tried to just use the quat commands, I wasn’t getting the angles out that I was putting in.
Yes. After quite some experimentation, I think what is going on is this:
Codea draws rotated things, like most systems, using quaternions. There are technical reasons for this including avoiding gimbal lock and the ease of “adding” and “subtracting” rotations to adjust angles.
When you put in a set of eulerAngles, quat jumps through its own orifice to compute the direct rotation to the desired angle. This is almost never the same as moving by the angles you put in: it goes straight there.
When you convert a rotation back to euler angles, you therefore almost never get back what you put in. However, what you get back should, when stuffed back in to the eulerAngles function, return an equivalent rotation (not even necessarily the same one, but one that will produce the safe effect).
In short, there is no way to get back the angles you put in. This is not a bug, it is the nature of the compromise to make euler angles work at all.
I don’t know what the basic problem is that you’re trying to solve, but if you truly need the angles and can’t live with saving the rotations, I think you’re stuck with wrapping the eulers into a class or a bunch of variables or a table or something of that kind.
@RonJeffries thanks for the unwrapping you did there.
If you try the code I suggested, with the change to the comments I suggested, you’ll see that the angles returned by the quarternions do not, in fact, work identically to the Eulers put in.
I don’t know why this should be. The logic that you used to make that conclusion is the same logic that led me to try it, but having tried it, unless I did something wrong, it just doesn’t work.
i’m not sure why, but i think the angles are coming back ok - though possibly changed as described above - but they’re not going correctly into the parameter fields.
i added a print after the setting of gc etc. as you can see in the attached pic, the numbers are non-zero but the parameters aren’t updated.
i was seeing the same thing with dave’s program, modded to fetch the values from the rotation and set gx gy gz. sometimes the parameters don’t set on screen, but the numbers print as expected.
@RonJeffries Wait, so you’re not seeing the blocks change their positions when you switch back and forth between them? Did you set the sliders to negative numbers?
no, i do not see the blocks switch. here’s my prog:
viewer.mode=STANDARD
function setup()
scene = craft.scene()
scene.camera.position=vec3(0,1,-4)
ground = scene:entity()
ground.model = craft.model.cube(vec3(1,.2,1))
ground.material = craft.material(asset.builtin.Materials.Specular)
ground.material.map = readImage(asset.builtin.Surfaces.Desert_Cliff_Roughness)
ground.position = vec3(1,1,1)
ground.eulersForParameterSliders = vec3(0,0,0)
ground2 = scene:entity()
ground2.model = craft.model.cube(vec3(1,.2,1))
ground2.material = craft.material(asset.builtin.Materials.Specular)
ground2.material.map = readImage(asset.builtin.Surfaces.Desert_Cliff_Roughness)
ground2.position = vec3(-1,1,1)
ground.eulersForParameterSliders = vec3(0,0,0)
controlledBlock = ground
fill(255)
parameter.integer("gx",-180,180,0)
parameter.integer("gy",-180,180,0)
parameter.integer("gz",-180,180,0)
parameter.boolean("switchControlledBlock", false, function(switchState)
if switchState == true then
controlledBlock = ground2
ground.eulersForParameterSliders = vec3(gx,gy,gz)
else
controlledBlock = ground
ground2.eulersForParameterSliders = vec3(gx,gy,gz)
end
if controlledBlock.eulersForParameterSliders then
gx,gy,gz = controlledBlock.rotation:angles().x, controlledBlock.rotation:angles().y, controlledBlock.rotation:angles().z
--gx,gy,gz = controlledBlock.eulersForParameterSliders.x, controlledBlock.eulersForParameterSliders.y, controlledBlock.eulersForParameterSliders.z
print(switchState, gx,gy,gz)
end
end)
end
function update(dt)
controlledBlock.rotation=quat.eulerAngles(gx,gy,gz)
scene:update(dt)
end
function draw()
update(DeltaTime)
scene:draw()
if switchControlledBlock == true then
text("eulers control block on right",WIDTH/2,HEIGHT/2+150)
else
text("eulers control block on left",WIDTH/2,HEIGHT/2-150)
end
end
part of the problem here is parameter.integer. use parameter.number. you can’t set a parameter.integer to a non-integer value. it’s ignored, i think, if you do.