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.

I have shared the project but yet to receive any updates.

After testing the project more it looks like this might be an issue related to the model being culled. Can you apply this component to your character and tell me if you’re still seeing the issue?