Vertical Surface Detection

How do I make the model anchored to one position when clicked? Currently it travels from one part to another along the surface of the fake wall.
const wallFromFloorComponent = {
schema: {
placed: {default: false},
},
init() {
this.raycaster = new THREE.Raycaster()
this.camera = document.getElementById(‘camera’)
this.threeCamera = this.camera.getObject3D(‘camera’)
this.ground = document.getElementById(‘ground’)
const scene = this.el.sceneEl

const placeWall = () => {
  this.data.placed = true
  const wall = document.createElement('a-box')
  wall.id = 'wall'
  wall.setAttribute('material', {color: 'white', transparent: true, opacity: 0.1})
  wall.object3D.scale.set(100, 200, 0.25)
  wall.object3D.rotation.y = this.el.object3D.rotation.y
  wall.setAttribute('position', {
    x: this.el.object3D.position.x,
    y: this.el.object3D.position.y + 25,
    z: this.el.object3D.position.z,
  })
  scene.appendChild(wall)

  const frame = document.createElement('a-entity')
  frame.id = 'frame'
  frame.setAttribute('gltf-model', require('./assets/bot.glb'))
  frame.object3D.scale.set(2, 2, 2)
  frame.setAttribute('place-on-wall', '')
  frame.object3D.rotation.x = THREE.MathUtils.degToRad(270)
  frame.object3D.rotation.z = THREE.MathUtils.degToRad(180)
  scene.appendChild(frame)

  scene.removeEventListener('click', placeWall)

  this.el.parentNode.removeChild(this.el)
}

scene.addEventListener('click', placeWall)

},

tick() {
if (!this.data.placed) {
let pos = new THREE.Vector3(0, 0, 0)
const a = new THREE.Vector2(0, -0.5)

  this.threeCamera = this.threeCamera || this.camera.getObject3D('camera')

  this.raycaster.setFromCamera(a, this.threeCamera)
  const intersects = this.raycaster.intersectObject(this.ground.object3D, true)

  if (intersects.length > 0) {
    pos = intersects[0].point
  }

  this.el.object3D.position.lerp(pos, 0.4)
  this.el.object3D.rotation.y = this.camera.object3D.rotation.y
}

},
}

const placeOnWallComponent = {
schema: {
placed: {default: false},
},
init() {
this.raycaster = new THREE.Raycaster()
this.camera = document.getElementById(‘camera’)
this.threeCamera = this.camera.getObject3D(‘camera’)
this.wall = document.getElementById(‘wall’)
const scene = this.el.sceneEl

this.frame = this.el

const placeOnWall = () => {
  this.data.placed = true
  scene.removeEventListener('click', placeOnWall)
}

this.frame.addEventListener('model-loaded', () => {
  this.frame.setAttribute('animation-mixer', {
    clip: '*',
    timeScale: 1.0,
    loop: 'once',
    clampWhenFinished: true,
  })
})

scene.addEventListener('click', placeOnWall)

},

tick() {
if (!this.data.placed) {
let pos = new THREE.Vector3(0, 0, 0)
const a = new THREE.Vector2(0, 0)

  this.threeCamera = this.threeCamera || this.camera.getObject3D('camera')

  this.raycaster.setFromCamera(a, this.threeCamera)
  const intersects = this.raycaster.intersectObject(this.wall.object3D, true)

  if (intersects.length > 0) {
    const i = 0
    const intersect = intersects[i]
    pos = intersect.point
  }

  this.el.object3D.position.lerp(pos, 0.4)
  this.el.object3D.rotation.y = this.wall.object3D.rotation.y
}

},
}

export {placeOnWallComponent, wallFromFloorComponent}

8th Wall doesn’t support vertical surface tracking. Can you show a video of the behavior you’re seeing?

I know vertical plane detection isnt supported so i am just using a workaround. As you can see, the model spawns lower than it is supposed to whenever the line is a little farther away and it doesnt spawn at all when the line is way too far. Here is my updated code:

const wallFromFloorComponent = {
  schema: {
    placed: {default: false},
  },
  init() {
    this.raycaster = new THREE.Raycaster()
    this.camera = document.getElementById('camera')
    this.threeCamera = this.camera.getObject3D('camera')
    this.ground = document.getElementById('ground')
    const scene = this.el.sceneEl

    const placeWall = () => {
      this.data.placed = true
      const wall = document.createElement('a-box')
      wall.id = 'wall'
      wall.setAttribute('material', {color: 'white', transparent: true, opacity: 0.5})
      wall.object3D.scale.set(100, 200, 0.25)
      wall.object3D.rotation.y = this.el.object3D.rotation.y
      wall.setAttribute('position', {
        x: this.el.object3D.position.x,
        y: this.el.object3D.position.y,
        z: this.el.object3D.position.z,
      })
      scene.appendChild(wall)

      const frame = document.createElement('a-entity')
      frame.id = 'frame'
      frame.setAttribute('gltf-model', require('./assets/bot.glb'))
      frame.object3D.scale.set(2, 2, 2)
      frame.setAttribute('place-on-wall', '')
      frame.object3D.rotation.x = THREE.MathUtils.degToRad(270)
      frame.object3D.rotation.z = THREE.MathUtils.degToRad(180)

      frame.object3D.position.set(
        wall.object3D.position.x,
        wall.object3D.position.y + 3,
        wall.object3D.position.z
      )

      scene.appendChild(frame)

      scene.removeEventListener('click', placeWall)

      this.el.parentNode.removeChild(this.el)
    }

    scene.addEventListener('click', placeWall)
  },

  tick() {
    if (!this.data.placed) {
      let pos = new THREE.Vector3(0, 0, 0)
      const a = new THREE.Vector2(0, -0.5)

      this.threeCamera = this.threeCamera || this.camera.getObject3D('camera')

      this.raycaster.setFromCamera(a, this.threeCamera)
      const intersects = this.raycaster.intersectObject(this.ground.object3D, true)

      if (intersects.length > 0) {
        pos = intersects[0].point
      }

      this.el.object3D.position.lerp(pos, 0.1)
      this.el.object3D.rotation.y = this.camera.object3D.rotation.y
    }
  },
}

const placeOnWallComponent = {
  schema: {
    placed: {default: false},
  },
  init() {
    this.raycaster = new THREE.Raycaster()
    this.camera = document.getElementById('camera')
    this.threeCamera = this.camera.getObject3D('camera')
    this.wall = document.getElementById('wall')
    const scene = this.el.sceneEl

    this.frame = this.el

    const placeOnWall = () => {
      this.data.placed = true
      scene.removeEventListener('click', placeOnWall)
    }

    this.frame.addEventListener('model-loaded', () => {
      this.frame.setAttribute('animation-mixer', {
        clip: '*',
        timeScale: 1.0,
        loop: 'once',
        clampWhenFinished: true,
      })
    })

    scene.addEventListener('click', placeOnWall)
  },

  tick() {
    if (!this.data.placed) {
      let pos = new THREE.Vector3(0, 0, 0)
      const a = new THREE.Vector2(0, 0)

      this.threeCamera = this.threeCamera || this.camera.getObject3D('camera')

      this.raycaster.setFromCamera(a, this.threeCamera)
      const intersects = this.raycaster.intersectObject(this.wall.object3D, true)

      if (intersects.length > 0) {
        const i = 0
        const intersect = intersects[i]
        pos = intersect.point
      }

      // this.el.object3D.position.lerp(pos, 0.4)
      // this.el.object3D.rotation.y = this.wall.object3D.rotation.y
    }
  },
}

export {placeOnWallComponent, wallFromFloorComponent}

I think I see the issue. Can you land your changes and share your project with the support workspace?

1 Like

Done! Hope you can help me out.