Converting text input from user into pre-made number models

bartosz.stepien
I need to be able to enter 4 digits of a year and have those years show up as custom objects - in this case a diamond-covered year on a piece of jewelry. We would need models for each number 0 1 2 3 4 5 6 7 8 9 …

Comments

10 comments

  • Comment author
    bartosz.stepien

    I need to be able to enter 4 digits of a year and have those years show up as custom objects - in this case a diamond-covered year on a piece of jewelry.

    We would need models for each number 0 1 2 3 4 5 6 7 8 9 and a text attribute would let customers enter a year like 2 0 2 0 and the numbers would be replaced with the corresponding models. How can we achieve this?

    0
  • Comment author
    Phil

    Hi Bartosz,

    To be clear, it sounds like you are trying to represent each text character (i.e. 0-9) with a pre-made 3D model instead of using Text Shapes to build a model from text. Correct?

    Here are instructions on how you can accomplish this. A demo of the final result can be found here.

    Step 0: Create Assets & Get Asset Ids

    First, upload the 3D assets for each character (i.e. 3D models representing 0 - 9).

    Then, create an empty placeholder model (i.e. create a Model asset on Threekit with no nodes).

     

    Finally, get the ID of each asset, which can be retrieved from the URL of the asset detail page. We will need these later.

     

    Step 1: Setup Anchors

    In the parent asset (i.e. the asset we’re configuring), import four (i.e. one for each character) models. These will be used as anchors for the character models. It does not matter what models are imported or where they are placed. Those properties will be controlled by Asset Rules. However, it would be easiest to import 1, 2, 3, & 4 as a memory aid.

     

    Step 2: Create Attributes

    Create 4 Part Reference attributes (one for each character) and a String attribute (for the text input).

     

    Step 3: Create Rule to Set Models

    Create a rule with no conditions (i.e. one that always fires) and add actions to set each Anchor Node (i.e. the models we imported in Step 1) to it’s corresponding attribute.

     

    Step 4: Create Rules to Update Placement (optional)

    We may want to move the Anchors (change the transform) depending on how many characters are entered. For example, if the user enters 20 instead of 2020, we would want the letters aligned in the center instead of the first 2 anchor positions.

    To do this, we create one rule for each character length that controls where each anchor is placed. NOTE: This can be done with a script as well and that may be the preferred approach if there were many characters.

    Each rule should have conditions that detect how many Anchors have been set (i.e. the number of characters) and actions that set the position to each Anchor.

    Here is a finished rule

     

    To set the position, create an Set Property Action

     

    Set the Translation property of the Anchor

     

    Step 5: Add Configuration Script

    Now that we have the rules setup, we need to add a script that will set the Anchors according to the text input. This can be done by adding a Custom Script action to the rule that always fires.

     

    Here is a script to use as a template.

    // Store the assetId for each number in an array
    const numberAssets = [
      "8a1b066f-ce4a-44d0-a4d8-80aeddf9001d",
      "ce1b3943-00d7-4017-a592-9dc3bfb97473",
      "eb261263-f999-4985-ba18-d0ca2a12f7cd",
      "742a0517-82ba-49d7-9c75-ebbd49276cde",
      "89c861e9-4af1-4bb2-8ebd-9f6b4fe92ad5",
      "4987fcbb-dbc3-4d10-abb8-387b701f3404",
      "cfa295ec-b4e0-4056-bd08-aed2ac612ea4",
      "48630611-c9ac-4cbc-81ba-013d361bffae",
      "9e01787f-c13f-4718-a790-8061c446b60d",
      "8cb83b35-9995-475b-b104-fc92608a5e2a",
    ];
    
    // Use the Placeholder Model to set Anchors w/no value.
    const placeholder = { assetId: "1f4eaa40-a788-4773-b1a5-30a04e0f7463" };
    
    const anchorReset = {
      Anchor1: placeholder,
      Anchor2: placeholder,
      Anchor3: placeholder,
      Anchor4: placeholder,
    };
    
    let player;
    
    async function onChange() {
      if (!player)
        if (/(preview|admin).threekit.com$/gi.test(window?.location?.origin))
          // Find player on platform
          player = window.api._store.getIn(["player", "players"]).first().api;
        else if (window.player)
          // Find player on embed
          player = window.player;
        else return console.warn("Cannot find player");
    
      // Get the configurator
      if (!window.configurator)
        window.configurator = await player.getConfigurator();
    
      // Only fire if the Text has changed
      const nextConfig = window.configurator.getConfiguration();
      if (window.prevConfig?.Text === nextConfig.Text) return;
      window.prevConfig = nextConfig;
    
      const update = nextConfig.Text.split(")
        .map((int) => numberAssets[int]) // Map the input character to the assetId
        .map((assetId, index) => ({ [`Anchor${index + 1}`]: { assetId } })) // Create the config updates
        .reduce(
          (acc, cur) => ({ ...acc, ...cur }), // Reduce attribute values to a single object
          anchorReset // Use anchorReset as the initial value to ensure empty Anchors are cleared
        );
    
      return window.configurator.setConfiguration(update);
    }
    
    // onChange is an async function, meaning it returns a Promise
    // Returning this to the config script ensures other rules are fired w/a consistent order of operations
    return onChange();
    

    On Embed: Assign Player to Window

    The script needs to access the Player API. On initialization, assign the player to the window.

    window
        .threekitPlayer({
          assetId: "00000000-0000-0000-0000-000000000000",
          authToken: "00000000-0000-0000-0000-000000000000",
          el: document.getElementById("player-el"),
        })
        .then((player) => {
          window.player = player;
        });
    
    0
  • Comment author
    bartosz.stepien

    Hello Phil,
    Thank you so much for taking the time to create this demo.
    Tomorrow I will be checking it based on our case.
    Thank you very much.

    0
  • Comment author
    Phil

    @bartosz.stepien FYI, I updated the script to reflect the change I made.

    let player;
    
    async function onChange() {
      if (!player)
        if (/(preview|admin).threekit.com/gi.test(window?.location))
          player = window.api._store.getIn(["player", "players"]).first().api;
        else player = window.player;
      if (!player) return;
    
    ...
    
    0
  • Comment author
    bartosz.stepien

    Hello,

    I have a question about deformers. There is a way to do some deforms on top of this 3d inputed models?(Image not migrated)[//tk-dev-forum.s3.dualstack.us-east-1.amazonaws.com/original/1X/c577fa8df64556597508373ba6451b2d3854c1d2.png"]

    Some latice or bend? Why I’m asking is that the numbers are bended a litle bit. In attachment I put some references on this effect (it is for 2018).

    I know how deformers are woring in profesional 3D software and I wondering if is possible do this in here?

    This will be helpful for me if we can do that. I was see that some deformers are under operators but I cant put this on "anchor” I think because this is not yet a model 3d but only null in the space.

    Thanks!

    0
  • Comment author
    bartosz.stepien

    I have one idea about this.I can put a "bend modifier” on each number with default 0 value.

    And in final model asset add some hidden attributes that will be drivig this bend angle regarding input position.

    Please give me some fresh ideas how can I achieve this effect.

    Best

    0
  • Comment author
    Phil

    Hi Bartosz,

    That’s an interesting problem. Normally, if we were using a Text Shape to define all characters, then we could easily apply a Bend Deformer (or some operator) to all characters. In this case, since each character is a model, we will have to coordinate the deformation across the children.

    I don’t have a clean answer off the top of my head. Maybe try combining a Bend Deformers & a Stretch operator.

    If you can get it working w/out configuration (i.e. just the 3D side), I can probably help you figure out how to hook it up to the configurator.

    0
  • Comment author
    Nicole Premo

    Hi Bartosz,

    Another option that might work is the "UV Warp” operator for meshes. It is an operator that lets you warp geometry around a source piece of geometry.

    Firstly, create a source piece of the geometry of the desired deformed shape. This can be created in the platform or imported and make sure it has plenty of segments. The segements help the "UV Warp” operator work more accurately.

     

    Then apply the "UV Warp” operator to the indivual meshes you want warped. Use the Dimension and Justification for each letter to adjust the placement. Change Ridgity to Component. Vertex Ridgity can give a messy result. Input your source geoemtry and use the world cordinates. I attached my settings below.

     

    Let me know if you have any more questions.

    0
  • Comment author
    andrewq

    Is this method performant enough to handle 27 different letters? Or should I leave it up to the website to handle all of this assetID swapping?

    0
  • Comment author
    William Thompson

    This is being used in projects for the entire alphabet, Threekit is performant enough to handle it but is up to the implementers to make sure the assets, textures, etc are all optimized for the web.

    0

Please sign in to leave a comment.