Building a babylon.js project that also uses godot-ecmascript

Heya fam!

We’ve started a project to port the game engine for Cryptovoxels (written in babylon) over to godot, and it’s been going really well. Our plan for a while has been to make a native client that can go in the steamvr and oculus stores. I had been hoping to use babylon native, but after some experimentation, we discovered Godot and so have spent the past few weeks building out a prototype. It’s come together really well. We’ll keep our babylon.js version for running on the web, and develop the godot version alongside. There’s no way we’d want to use a webassembly build of godot, babylon.js is just so much more superior on the web.

We’re using godot-ecmascript which uses quickjs (ecmascript 2020 support) and has really nice typescript type definitions. We’re planning to have a single codebase containing both the godot and babylonjs code, which will either be compiled into a web bundle (using esbuild) for the web, or into godot .jsx files.

The biggest problem so far is that all our world geometry is in the left handed babylon.js coordinate space, so we have to futz with all the numbers to make it work in the right handed godot coordinate space.

Anyway - two cool opensource projects working well together!

Ben

1 Like

Related question: why BabylonNative was not good enough for your need? It would have saved you a lot of work

cc @bghgary

Heya! Yeah BabylonNative was our plan for ages, and I did a bit of prototyping with it. The main reasons we’re trying out godot is:

  • Since you can’t use JITted javascript on iOS, I wanted the core engine to run in C++ (culling, animating, meshing). We could have ported parts of BN core over to c++, but it would’ve been a lot of work, and godot seems to have ok performance so far.
  • One of the big reasons we wanted to go native was to build lots of c++ modules (voxel mesher), and godot has a nice interface for doing native development (gdnative) with fast reloads
  • Godot is a few years ahead of where BN is in terms of development lifecycle

We’ll keep reviewing BN and I wouldn’t be surprised if we end up using it for something, but at the moment, we’re going to have one codebase with two code paths:

async generateGodot() {
  let m = new godot.QuadMesh()
  m.size = new godot.Vector2(1, 1)

  let texture

  try {
    texture = (await this.fetchTexture(this.description.url)) as godot.Texture
  } catch (e) {
    texture = godot.load('res://textures/no-image.png')
  }

  let material = new godot.SpatialMaterial()
  material.set_blend_mode(godot.SpatialMaterial.BLEND_MODE_MUL)

  ...
}

async generateBabylon(texture): BABYLON.Mesh {
  if (this.description.uScale && this.description.vScale) {
    texture.uScale = this.description.uScale
    texture.vScale = this.description.vScale
  }
  const plane = BABYLON.MeshBuilder.CreatePlane('feature/image', { size: 1 }, this.scene)
  const material = new BoundMaterial('feature/image', this.scene)
  material.bindMesh(this.mesh)

  material.specularColor.set(0, 0, 0)
  material.emissiveColor.set(1, 1, 1)
  material.diffuseTexture = texture
  material.backFaceCulling = false
  material.zOffset = -4
  material.alpha = 0.999

  ...
}
4 Likes

Lovely thanks!

For anyone else doing this, you need to invert the z axis on position - and for rotation you need to do this:

  static set_common_rotation(instance, rotation) {
    // Get babylon quaternion
    // let q = Quaternion.RotationYawPitchRoll(rotation[1], rotation[0], rotation[2])

    let q = Quaternion.FromEulerAngles(rotation[0], rotation[1], rotation[2])
    let gq = new godot.Quat(-q.x, -q.y, q.z, q.w)

    // Convert to godot euler
    let r = gq.get_euler()
    instance.set_rotation(r)
  }
1 Like

I think you can avoid this conversion by setting scene.useRightHandedSystem = true;