Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom, dynamic themes #109

Open
wtfcarlos opened this issue Aug 18, 2024 · 6 comments
Open

Custom, dynamic themes #109

wtfcarlos opened this issue Aug 18, 2024 · 6 comments

Comments

@wtfcarlos
Copy link

Hello. Love your library and am integrating it into my new project. Thank you for your hard work.
I am wondering what you think would be the bst way to go about creating themes dynamically, for custom dice applications?

For instance, given an array of 6 emoji, i'd like to somehow configure the dicebox such that the dice will show one of each emoji in the dice faces.

The theming system seems a bit imposing, hopefully ther'es a way to do it?

@wtfcarlos
Copy link
Author

For my purposes, a theme that exclusively supports d6 where I can dynamically provide images or text for each of the faces is what I am lookign to build. I am a seasoned engineer, so any ideas or a few pointers would be appreciated and I might be able to implement and contribute back.

@frankieali
Copy link
Contributor

Hi @wtfcarlos. Unfortunately, the theme system is not set up for dynamic face values. I use blender to create the 3d models and bake the textures. I know BabylonJS has support for custom fragment shaders, which I have implemented to dynamically alter the die colors, but altering the die faces was much more complex. These are written in Graphics Library Shader Language (GLSL) which I do not know well enough.
My other dice roller dice-box-threejs should support this feature though. It's a fork of Major's 3D Dice which was forked from Teal Dice (no longer online but mirrored here Darkside Teal Dice). You can see in the dice presets file how the labels and values are configurable.
I know other libraries do support this feature, such as dddice.com and Dice so Nice. Dice So Nice was originally forked from Major's 3D Dice as well but has been heavily altered to integrate with FoundryVTT.

Overall, this seems like a popular feature, so I'm going to add it to the list for the future.

@frankieali
Copy link
Contributor

Digging deeper into dice-box-three, the ability to make a custom set or assign the face labels is not exposed, but I imagine it wouldn't take much work to expose them as a config option. Color, texture and material have already be exposed as a custom color set.

@wtfcarlos
Copy link
Author

wtfcarlos commented Aug 19, 2024

Hello, I was able to implement this for d6 only on the mainstream 3d-dice/dice-box.
The way I did it was by supporting a new theme type that I call dynamic-canvas.
I set it up in such a way that I can provide an array of base64 strings called canvasProvider that would represent each of the 6 faces of the die.

I then use Babylon's CubeTexture to create a compossite custom cube texture that I can apply to a custom material.
Below is the quick and dirty version I came up with, which works in my project with some accessory modifications in other parts of the code:

class ThemeLoader {
  loadedThemes = {};
  themeData = {};
  constructor(options) {
    console.log("constructor options");
    console.log(options);
    this.scene = options.scene;
    this.canvasProvider = options.canvasProvider;
  }

  async createCubeTextureFromBase64(base64Array) {
    if (base64Array.length !== 6) {
      throw new Error(
        "CubeTexture requires exactly 6 images (one for each face)",
      );
    }

    return new CubeTexture(
      "", // Root URL (we don't need this as we are setting the images manually)
      this.scene,
      null,
      false,
      this.canvasProvider,
    );
  }

  async loadDynamicCanvasMaterial(options) {
    const { theme } = options;

    const cubeTexture = await this.createCubeTextureFromBase64(
      this.canvasProvider,
    );

    const material = new StandardMaterial(theme, this.scene);
    material.diffuseTexture = cubeTexture;
    material.diffuseTexture.level = 1;
    material.diffuseTexture.coordinatesMode = Texture.SKYBOX_MODE;
    material.diffuseColor = new Color3(0, 0, 0);

    material.specularPower = 1;
    material.specularColor = new Color3(0, 0, 0); // Use a lower value to reduce brightness

    material.reflectionTexture = cubeTexture; // Or set this as diffuseTexture based on your needs
    material.reflectionTexture.coordinatesMode = Texture.SKYBOX_MODE;
    material.reflectionTexture.level = 1;

    material.backFaceCulling = false;
    material.sideOrientation = StandardMaterial.ClockWiseSideOrientation;

    return material;
  }

 
  }```

@wtfcarlos
Copy link
Author

wtfcarlos commented Aug 19, 2024

This video shows how it works for my project.

trimmed.mov

This is obviously a hack that only supports d6, but this is just exactly what I need for my project.

My project will continue using this library heavily, and I can foresee needing more custom adjustments, but I think I'm confident I can modify the library to do anythign I need for my basic d6 purposes

@wtfcarlos
Copy link
Author

wtfcarlos commented Aug 19, 2024

The mesh file config I'm using declares a simple cubic mesh d6 and a simple cubic d6_collider, with simple UV mappings. Hope this can help out someone in the future! I could see a way of supporting other dice in the future with a more careful approach.

{
  "producer": {
    "name": "Carlos Rey",
    "version": "0.0.1",
  },
  "gravity": [
    0,
    -9.81,
    0
  ],
  "colliderFaceMap": {
        "d6": {
            "0": 1,
            "1": 5,
            "2": 4,
            "3": 2,
            "4": 6,
            "5": 3,
            "6": 1,
            "7": 5,
            "8": 4,
            "9": 2,
            "10": 6,
            "11": 3
        }
  },
  "meshes": [
    {
      "name": "d6",
      "id": "d6",
      "billboardMode": 0,
      "position": [-0.6, 0, 0],
      "rotationQuaternion": [0, 0, 0, -1],
      "scaling": [1, 1, 1],
      "isVisible": true,
      "isEnabled": true,
      "pickable": false,
      "positions": [
        -1, -1, -1,
         1, -1, -1,
         1,  1, -1,
        -1,  1, -1,
        -1, -1,  1,
         1, -1,  1,
         1,  1,  1,
        -1,  1,  1
      ],
      "normals": [
        0, 0, -1,
        0, 0, -1,
        0, 0,  1,
        0, 0,  1,
        0, -1, 0,
        0, -1, 0,
        0,  1, 0,
        0,  1, 0,
        -1, 0, 0,
        -1, 0, 0,
        1, 0, 0,
        1, 0, 0
      ],
        "uvs": [
          0, 0, 0.16666666666666666, 1,
          0.16666666666666666, 0, 0.3333333333333333, 1,
          0.3333333333333333, 0, 0.5, 1,
          0.5, 0, 0.6666666666666666, 1,
          0.6666666666666666, 0, 0.8333333333333334, 1,
          0.8333333333333334, 0, 1, 1
        ],
      "indices": [
        0, 1, 2, 0, 2, 3,
        4, 5, 6, 4, 6, 7,
        0, 1, 5, 0, 5, 4,
        2, 3, 7, 2, 7, 6,
        0, 3, 7, 0, 7, 4,
        1, 2, 6, 1, 6, 5
      ],
      "metadata": {
        "formatVersion": 3
      }
    },
    {
      "name": "d6_collider",
      "id": "d6_collider",
      "billboardMode": 0,
      "position": [-0.6, 0, 0],
      "rotationQuaternion": [0, 0, 0, -1],
      "scaling": [1, 1, 1],
      "isVisible": true,
      "isEnabled": true,
      "pickable": false,
      "positions": [
        -1, -1, -1,
         1, -1, -1,
         1,  1, -1,
        -1,  1, -1,
        -1, -1,  1,
         1, -1,  1,
         1,  1,  1,
        -1,  1,  1
      ],
      "normals": [
        0, 0, -1,
        0, 0, -1,
        0, 0,  1,
        0, 0,  1,
        0, -1, 0,
        0, -1, 0,
        0,  1, 0,
        0,  1, 0,
        -1, 0, 0,
        -1, 0, 0,
        1, 0, 0,
        1, 0, 0
      ],
        "tangents": [
            1, 0, 0,
            1, 0, 0,
            1, 0, 0,
            1, 0, 0,

            -1, 0, 0,
            -1, 0, 0,
            -1, 0, 0,
            -1, 0, 0,

            0, 0, -1,
            0, 0, -1,
            0, 0, -1,
            0, 0, -1,

            0, 0, 1,
            0, 0, 1,
            0, 0, 1,
            0, 0, 1,

            1, 0, 0,
            1, 0, 0,
            1, 0, 0,
            1, 0, 0,

            1, 0, 0,
            1, 0, 0,
            1, 0, 0,
            1, 0, 0
        ],
      "uvs": [
        0, 0, 1, 0, 1, 1, 0, 1,
        0, 0, 1, 0, 1, 1, 0, 1,
        0, 0, 1, 0, 1, 1, 0, 1,
        0, 0, 1, 0, 1, 1, 0, 1,
        0, 0, 1, 0, 1, 1, 0, 1,
        0, 0, 1, 0, 1, 1, 0, 1,
        0, 0, 1, 0, 1, 1, 0, 1,
        0, 0, 1, 0, 1, 1, 0, 1,
        0, 0, 1, 0, 1, 1, 0, 1,
        0, 0, 1, 0, 1, 1, 0, 1,
        0, 0, 1, 0, 1, 1, 0, 1,
        0, 0, 1, 0, 1, 1, 0, 1
      ],
      "indices": [
        0, 1, 2, 0, 2, 3,
        4, 5, 6, 4, 6, 7,
        0, 1, 5, 0, 5, 4,
        2, 3, 7, 2, 7, 6,
        0, 3, 7, 0, 7, 4,
        1, 2, 6, 1, 6, 5
      ],
      "metadata": {
        "formatVersion": 3
      }
    }
  ]
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants