EulerAngles arrrgh

I thought I could save a craft entity’s EulerAngles as a vec3, change the rotation around elsewhere in the code, and then use the saved vec3 if I needed to restore that previous rotation, but nope.

It seems like EulerAngles change every time you assign them.

How can I save/restore an entity’s rotation?

@UberGoober Is this what you want. Start the program and tap the screen to save the image at the home positions. Use the sliders to rotate the image then tap the screen to set it back to the home position.

viewer.mode=STANDARD

function setup() 
    parameter.integer("gx",-180,180,0)
    parameter.integer("gy",-180,180,0)
    parameter.integer("gz",-180,180,0)
    save=false
    str1="tap screen to save rotation angles"
    str2="tap screen to restore rotation angles"
    
    scene = craft.scene()
    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)
    scene.camera.position=vec3(0,1,-4) 
    fill(255) 
end

function update(dt)
    ground.rotation=quat.eulerAngles(gx,gy,gz)
    scene:update(dt)
end

function draw()
    update(DeltaTime)
    scene:draw()	
    if not save then
        text(str1,WIDTH/2,HEIGHT/2)
    else
        text(str2,WIDTH/2,HEIGHT/2)
    end
end

function touched(t)
    if t.state==BEGAN then 
        if save==false then
            hold=vec3(gx,gy,gz)
            save=true
        else
            gx,gy,gz=hold.x,hold.y,hold.z
        end        
    end
end

@dave1707 fantastic. Thanks heaps and heaps!

@dave1707

I tried to nudge your code towards my actual use case and I got the strange results I’m seeing in my actual use case.

If you want to see it, try setting all the sliders to negative numbers and then tapping the screen a bunch of times.


viewer.mode=STANDARD

function setup()
    parameter.integer("gx",-180,180,0)
    parameter.integer("gy",-180,180,0)
    parameter.integer("gz",-180,180,0)
    toggle=false
    str1="tap screen to save rotation angles"
    str2="tap screen to swap rotation angles"
    
    scene = craft.scene()
    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)
    scene.camera.position=vec3(0,1,-4)
    fill(255)
end

function update(dt)
    ground.rotation=quat.eulerAngles(gx,gy,gz)
    scene:update(dt)
end

function draw()
    update(DeltaTime)
    scene:draw()
    if not toggle then
        text(str1,WIDTH/2,HEIGHT/2)
    else
        text(str2,WIDTH/2,HEIGHT/2)
    end
end

function touched(t)
    if t.state==BEGAN then
        if toggle==false then
            hold1=quat.eulerAngles(gx,gy,gz)
            if hold2 then
                local recoveredEulers = hold2:angles()
                gx,gy,gz=recoveredEulers.x,recoveredEulers.y,recoveredEulers.z
            else
                gx,gy,gz = 0,0,0
            end
            toggle=true
        else          
            hold2=quat.eulerAngles(gx,gy,gz)
            local recoveredEulers = hold1:angles()
            gx,gy,gz=recoveredEulers.x,recoveredEulers.y,recoveredEulers.z
            toggle=false
        end
    end
end

@UberGoober Tap above the middle of the screen to save the angles, Tap below the middle to restore the angles.

viewer.mode=STANDARD

function setup()
    parameter.integer("gx",-180,180,0)
    parameter.integer("gy",-180,180,0)
    parameter.integer("gz",-180,180,0)
    toggle=false
    
    scene = craft.scene()
    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)
    scene.camera.position=vec3(0,1,-4)
    fill(255)
end

function update(dt)
    ground.rotation=quat.eulerAngles(gx,gy,gz)
    scene:update(dt)
end

function draw()
    update(DeltaTime)
    scene:draw()
    text("save angles",WIDTH/2,HEIGHT/2+50)
    text("restore angles",WIDTH/2,HEIGHT/2-50)
end

function touched(t)
    if t.state==BEGAN then
        if t.y >HEIGHT/2 then
            hold=vec3(gx,gy,gz)
            print("saved")
        else
            gx,gy,gz=hold.x,hold.y,hold.z
            ground.rotation=quat.eulerAngles(gx,gy,gz)
            print("restored")
        end
    end
end

I think I get it. It seems like the crucial thing is that you’re setting the visible x, y, z of the parameters separate from using those values in the quarternion.

I modified it again to be a step closer to what I’m going to use it for. It seems to work. Am I doing it right?


-- dave1707 Quats 2 viz ubergoober

viewer.mode=STANDARD

function setup()
    swapVec = vec3()
    scene = craft.scene()
    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)
    scene.camera.position=vec3(0,1,-4)
    fill(159,100,229)
    parameter.boolean("switchAngleSets", false, function(switchState)
        print(switchState)
        local newVec = swapVec
        swapVec = vec3(gx,gy,gz)
        gx,gy,gz = newVec.x, newVec.y, newVec.z
        ground.rotation = quat.eulerAngles(gx,gy,gz)
    end)
    parameter.integer("gx",-180,180,0)
    parameter.integer("gy",-180,180,0)
    parameter.integer("gz",-180,180,0)
end

function update(dt)
    ground.rotation=quat.eulerAngles(gx,gy,gz)
    scene:update(dt)
end

function draw()
    update(DeltaTime)
    scene:draw()
    if switchAngleSets == true then
    text("angle set A",WIDTH/2,HEIGHT/2+50)
        else
    text("angle set B",WIDTH/2,HEIGHT/2-50)
        end
end

Yeah, it’s posting from the iPhone that screws up the formatting. Apparently Vanilla Forums don’t work the same in their phone-size mode as they do in their full-size mode.

you can edit in the squiggles after pasting.

It seems to work OK. It’s switches between the 2 settings.

@UberGoober I guess I’m not sure what you’re trying to accomplish. Do you have a lot of items where you want to save their original rotation values and be able at some point return them to that original rotation.

Well as you can see I tried four times to post my latest version and the formatting didn’t work on any of them.

The real kick in the crotch is that the formatting did work correctly in the preview.

Empty line


-- dave1707 Quats 2 viz ubergoober 2

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
           -- does not work: 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
        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

Empty line

Just use the ` character three times instead of the ~ character

So that version is the closest yet to my actual use case.

As you can see I had to do it by storing the Eulers to show on the sliders as a separate variable on the entities themselves.

In practice I may have to do this between 30 or 40 entities or more, so if I have to store the Eulers separately I’ll either have to do what I did here or make a separate table to store them in, which doesn’t seem a lot different.

Unless there’s some way to get the properties that should go on the sliders from the existing attributes of an entity, but I haven’t been able to do that—can you?

@skar

I’ll try that, but you should know that I’ve used the ~~~ marks successfully in tons of other posts—in fact every single other post where I’ve posted code.

Edit: as you can see above I tried it and it still didn’t work.

Maybe you need a line space between the top of the post and the first three `

I’m concerned that everybody’s going to get all caught up in how the posts are formatted and my question will be lost.

@dave1707, I haven’t found a way to derive the right values to show on the parameter sliders from the entity’s own attributes. Can it be done?

That’s basically right.

I have a bunch of on-screen entities that I can cycle through and use x, y, z sliders to rotate.

When I move from one entity to the next, I need to set the sliders to the correct values for the current object.

But I can’t get those values from the entity’s own Eulers or from using rotation:angles(), it seems.

So I may have to take the klutzy path of directly storing them on the entity.

@UberGoober When you tap on an entity, you want the rotation values for that entity to update the x,y,z sliders and you want to rotate the entity with the sliders or reset that entity to it original rotation.

Yeah, that sounds right, though I’m not as concerned with restoring rotation as I am with updating the sliders.