When an object rotates around an axis not ve3(0,0,0), the craft.physics miscalculates its position

I just found a bug in the craft.physics, using the craft.model.cube, setting the offset to vec3(0.4,0.4,0.4) and rotating, the craft.physics calculated the wrong position, and could not handle the collision correctly, the Blue Dot in the video is the click position, after rotating click object invalid, click next to it in the white space, will trigger.

Simply put, if the offset is not zero, the craft.physics calculation will go wrong after the rotation

https://youtu.be/iAkYIk2CoLI

The test code:

--

function setup()
    -- Create a new craft scene
    scene = craft.scene()
    scene.ambientColor = color(218, 158, 79)
    scene.sky.active = false
    
    -- Setup camera and lighting
    scene.sun.rotation = quat.eulerAngles(125, 125, 0)
    
    assert(OrbitViewer, "Please include Cameras project as a dependency")
    gViewer = scene.camera:add(OrbitViewer, vec3( 0.0,  0.5,  0.5), 8, 1, 400)
    gViewer.rx=-45
    gViewer.ry=45
    
    myChest1 = Cube(scene:entity())   
    -- myChest2 = Cube(scene:entity(), vec3(1.8, 0.6, 0.1),vec3(0)) 
end

function update(dt)
    scene:update(dt)
    myChest1:update()
    -- myChest2:update()
end

-- Called automatically by codea 
function draw()
    update(DeltaTime)
    scene:draw()	
    sprite(asset.builtin.UI.Blue_Circle,CurrentTouch.x,CurrentTouch.y)
end

Cube = class()

function Cube:init(entity,pos,offset)
    self.camera = scene.camera:get(craft.camera)
    self.state = true
    self.root = scene:entity()
    self.root.position = vec3(x,y,z) or vec3(1.5, 0.3, 0.5)
    local r0 = self.root:add(craft.renderer, craft.model.cube(vec3(0.8,0.2,0.8),vec3(0.3,0.1,0.4)))
    
    self.top = entity
    self.top.parent = self.root
    self.top.position = pos or vec3(0.1, 0.6, 0.1)
    self.top:add(craft.rigidbody, STATIC)
    self.top:add(craft.shape.box, vec3(0.8,0.8,0.8), offset or vec3(0.4,0.4,0.4))
    local r2 = self.top:add(craft.renderer, craft.model.cube(vec3(0.8,0.8,0.8),offset or vec3(0.4,0.4,0.4)))
    r2.material = craft.material(asset.builtin.Materials.Specular)
    r2.material.diffuse = color(135, 178, 28)
    self.angle = 0
    self.y = 0.6
    
    touches.addHandler(self, -1, false)
end

function Cube:update(dt)
    self.root.rotation = quat.eulerAngles(0,  0, self.angle)
    self.top.rotation = quat.eulerAngles(0,  0, self.angle*80)
    
    local a = self.top.worldPosition + vec3(0,0,-1)
    local b = self.top.worldPosition + vec3(0,0,1)
    scene.debug:line(a, b,color(16, 239, 5))    
end

function Cube:interact()
    if not self.open then
        self.open = true
        tween(1.6, self, {angle = 90, y=10}, {easing=tween.easing.backOut,loop = tween.loop.once })
    else
        self.open = false
        tween(1.6, self, {angle = 0, y=0.6}, tween.easing.cubicIn)
    end
end


function Cube:touched(touch)
    if touch.state == BEGAN then

        -- Returning true will capture this touch and prevent other handlers from getting it
        local origin, dir = self.camera:screenToRay(vec2(touch.x, touch.y))
        
        -- Do a raycast to check if touch is hitting the bulb
        local hit = scene.physics:raycast(origin, dir, 300)
        -- print(self.top.position)
        if hit and hit.entity == self.top then
            self:interact()
            self.state = not self.state
            print("Touch Began (Captured - "..touch.id..")",origin)
            return true
        end
    elseif touch.state == ENDED and self.state then
        print("Touch Ended (Captured - "..touch.id..")")
    end
end

@binaryblues Modified a program I have using a parent and it looks like I got the same results.

Ignore my other post I deleted if you saw it.

@dave1707 Thank you so much for the extension, and I did exactly what you said. Inspired by you, I wonder if scale has the same problem. After all, they are all calculated by the same matrix. I will do a test on scale later.
Btw. That’s the only response I saw.

The scale is OK

https://youtu.be/D19Km49pVNw

@Simeon @binaryblues Here’s another example that shows the problem with rotation around a parent object. Run the code and slide the blue parameter all the way left. The blue box tilts and the ball bounces to the left. Do the same for the other 2 sliders. The balls bounce left as they should.

Run the code again but this time slide the green parameter. The green and blue boxes tilt and the green box ball bounces left but the blue one doesn’t.

Run the code again and slide the red parameter. All the boxes tilt but only the red box ball bounces correctly.

The children don’t seem to work correctly when a parent is moved.

I guess that’s just the way kids are, they never want to do what their parents want.


function setup()
    parameter.number("red",-10,0,0)
    parameter.number("green",-10,0,0)
    parameter.number("blue",-10,0,0)
    
    scene = craft.scene()
    scene.sky.active = false
    scene.camera.z = -30

    s1=createSphere(vec3(0,8,0),DYNAMIC)    
    s2=createSphere(vec3(-4,8,4),DYNAMIC)    
    s3=createSphere(vec3(-8,7,8),DYNAMIC)    
    
    c1=scene:entity()
    w1=c1:add(craft.rigidbody,STATIC)
    w1.restitution=1
    c1.position=vec3(0,-4,0)
    c1.model = craft.model.cube(vec3(3,1,3))
    c1:add(craft.shape.model,c1.model)
    c1.material = craft.material(asset.builtin.Materials.Standard)
    c1.material.diffuse = color(255,0,0)
    
    c2=scene:entity()
    w2=c2:add(craft.rigidbody,STATIC)
    w2.restitution=1
    c2.position=vec3(-4,2,4)
    c2.model = craft.model.cube(vec3(3,1,3))
    c2:add(craft.shape.model,c1.model)
    c2.material = craft.material(asset.builtin.Materials.Standard)
    c2.material.diffuse = color(0,255,0)
    
    c3=scene:entity()
    w3=c3:add(craft.rigidbody,STATIC)
    w3.restitution=1
    c3.position=vec3(-4,2,4)
    c3.model = craft.model.cube(vec3(3,1,3))
    c3:add(craft.shape.model,c1.model)
    c3.material = craft.material(asset.builtin.Materials.Standard)
    c3.material.diffuse = color(0,0,255)
    
    c2.parent=c1
    c3.parent=c2   
end

function update(dt)
    c1.eulerAngles=vec3(0,0,red)
    c2.eulerAngles=vec3(0,0,green)
    c3.eulerAngles=vec3(0,0,blue)
    scene:update(dt)
end

function draw()
    update(DeltaTime)
    scene:draw()	   
end

function createSphere(pos,typ)
    local sphere1=scene:entity()
    local s1=sphere1:add(craft.rigidbody,typ)
    s1.restitution=1
    sphere1.position=pos
    sphere1.model = craft.model.icosphere(.5,1)
    sphere1:add(craft.shape.sphere,.5)
    sphere1.material = craft.material(asset.builtin.Materials.Specular)
    sphere1.material.diffuse=color(255)
    return sphere1
end

@dave1707 Perfect example! You dug deeper and brilliant metaphor. I think all the parents feel the same way. Thanks a lot.

I recorded it, it’s the demo video:

https://youtu.be/0pBWagXFk4E