Rapid lettering with Three.js

Attempting to etch text onto a surface using Three.js has been successful, thanks to the use of csg.js and ThreeCSG. The outcome is impressive, however, the process is time-consuming, taking approximately 30 seconds on my PC to engrave the word "Hello."

After coming across a site that offers custom jewelry with quick text engraving capabilities, it seems evident that they are not using csg.js. This leads to the question: What other techniques can be utilized to achieve similar results?

One idea involves utilizing bump maps by generating one for each letter, yet uncertainty remains regarding whether this approach is suitable.

Answer №1

After examining the shaders, it appears that the website you provided uses bump maps.

It seems unlikely that a bump map would be created for each individual letter. Instead, all the text would likely be drawn on a single canvas and then applied as a bump map.

If you want to see a demonstration of canvas bump maps, click "Run Code Snippet" below (click and drag in the white box).

// JavaScript code snippet
var camera, scene, renderer, mesh, material, stats;
var drawStartPos = {x:0, y:0};

// Function to set up initial elements
init();
setupCanvasDrawing();
animate();

// Initialize function
function init() {
    // Renderer.
    renderer = new THREE.WebGLRenderer();
    
    renderer.setSize(window.innerWidth, window.innerHeight);
    
    document.getElementById('threejs-container').appendChild(renderer.domElement);

    // Create camera.
    camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000);
    camera.position.z = 400;

    // Create scene.
    scene = new THREE.Scene();

    // Create material
    material = new THREE.MeshPhongMaterial();

    // Create cube and add to scene.
    var geometry = new THREE.BoxGeometry(200, 200, 200);
    mesh = new THREE.Mesh(geometry, material);
    scene.add(mesh);

    // Create ambient light and add to scene.
    var light = new THREE.AmbientLight(0x404040); 
    scene.add(light);

    // Create directional light and add to scene.
    var directionalLight = new THREE.DirectionalLight(0xffffff);
    directionalLight.position.set(1, 1, 1).normalize();
    scene.add(directionalLight);

    window.addEventListener('resize', onWindowResize, false);

    // Stats display
    stats = new Stats();
    document.body.appendChild(stats.dom);
}

// Set up canvas drawing functionality
function setupCanvasDrawing() {
    var drawingCanvas = document.getElementById('drawing-canvas');
    var drawingContext = drawingCanvas.getContext('2d');

    drawingContext.fillStyle = "#FFFFFF";
    drawingContext.fillRect(0,0,128,128);

    material.bumpMap = new THREE.Texture(drawingCanvas);

    var paint = false;

    drawingCanvas.addEventListener('mousedown', function(e){
      paint = true
      drawStartPos = {x:e.offsetX, y:e.offsetY};
    });
    drawingCanvas.addEventListener('mousemove', function(e){
    if(paint){
      draw(drawingContext, e.offsetX, e.offsetY);
      }
    });
    drawingCanvas.addEventListener('mouseup', function(e){
      paint = false;
    });
    drawingCanvas.addEventListener('mouseleave', function(e){
      paint = false;
    });
}

// Drawing function
function draw(drawContext, x, y) {
  drawContext.moveTo(drawStartPos.x, drawStartPos.y);
  drawContext.lineTo(x,y);
  drawContext.stroke();
  drawStartPos = {x:x, y:y};
  material.bumpMap.needsUpdate = true;
}

// Animation function
function animate() {
    requestAnimationFrame(animate);
    mesh.rotation.x += 0.005;
    mesh.rotation.y += 0.01;
    renderer.render(scene, camera);
    stats.update();
}

function onWindowResize() {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
}
// CSS code snippet
body {
    padding: 0;
    margin: 0;
}

#drawing-canvas {
  position: absolute;
  background-color: #000;
  top: 0px;
  right: 0px;
  z-index: 3;
}

#threejs-container {
  position: absolute;
  left: 0px;
  top: 0px;
  width: 100%;
  height: 100%;
  z-index: 1;
}
// HTML code
<script src="https://rawgit.com/mrdoob/three.js/r83/build/three.min.js"></script>
<script src="https://cdn.rawgit.com/mrdoob/stats.js/r17/build/stats.min.js"></script>
<canvas id="drawing-canvas" height="128" width="128"></canvas>
<div id="threejs-container"></div>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Adjust Fabric js Canvas Size to Fill Entire Screen

Currently, I am working with version 4.3.1 of the Fabric js library and my goal is to adjust the canvas area to fit its parent div #contCanvasLogo. I have tried multiple approaches without success as the canvas continues to resize on its own. Below is the ...

Unforeseen SyntaxError: Unexpected symbol detected

Encountering an issue while attempting to send raw data as parameters in express. Specifically, there is an error occurring at the 'fields' variable... function getWithQuery(req,res){ console.log(req.params); var query = {name: new RegEx ...

Unveiling the secrets of leveraging Vue Router global navigation guard to efficiently verify multiple conditions

Within a Vue 3 application utilizing Pinia, my objective is to accomplish the following: Direct a user to the sign-in page when authentication is not verified. Direct a user to a verification page if authenticated but not yet verified. Direct a user to th ...

Retrieve calling image from array on rollover

Currently working on a website where I want to incorporate multiple rollovers using the same base image (distributed black pixels all over the page to create a popup effect). I decided that the best way to approach this is to use an array with all the ro ...

Include CakePHP named parameters in the URL when selecting from a list

If I have a selection list like the one below: <select name='languages'> <option value='german'>German</option> <option value='english'>English</option> </select> How can I use Jav ...

Interacting with a non-stringified object displayed in the browser console using TestCafe

Upon receiving a page that logs an object to the console, I encountered an issue when trying to access this object using getBrowserConsoleMessages(). The object appeared as the String "[object Object]" in the console, making it impossible for me to parse ...

Employing Visual Composer within WordPress has resulted in the raw JavaScript not being properly applied to my raw HTML code

Sharing some code that functions properly in my browser and I want to implement on my WordPress page: <!doctype html> <html lang="en"> <head> <meta charset="UTF-8> <!-- Getting jQuery --> <script src="http://ajax.goog ...

What is the best way to extract a JSON string from the login PHP response?

I am working on creating a basic website along with an Android application that both retrieve data from the same database. While I have no issues in dealing with Android, I am facing difficulty in handling JSON strings in HTML. How can I fetch the JSON res ...

What is the best way to include my PHP session variable within my JavaScript code?

i have a dynamic table that the enables to perform CRUD operations on a database. after logging in the user is directed to index.php, here a table is displayed with values stored in the database table "ajaxtable". i have joined "ajaxtable" table and "membe ...

Splitting a td tag into multiple columns dynamically with Angular

I am attempting to dynamically split the table element into separate columns. My desired layout should resemble this: https://i.sstatic.net/C81tg.png The values for name and surname are fixed at 1, but the values for subjects and grades can vary (there ma ...

Integrating JQuery with Sencha Touch: A Comprehensive Guide

Can you show me how to use JQuery with Sencha Touch? I have a Sencha button but when I click on it, nothing happens. I've checked that JQuery is working. xtype: 'button', text: 'Get result', docked: 'bottom', id: 'm ...

Can the image upload file size be customized or adjusted?

Recently, I've come across a standard input file code that looks like this: <Label class="custom-file-upload"> <input type="file" onChange={onDrop} /> Upload Photo </Label> I have been thinking about limiting the size of the ...

Displaying column data in a popup modal using DataTables

I am facing an issue with displaying a long string from a column in my table in a popup modal. Upon clicking the button to launch the modal, instead of opening the modal, the page refreshes and nothing is logged to the console. Below is the HTML code for ...

What is the process of editing a webpage to affect the display on a different webpage?

I am currently working on creating two webpages. One will serve as a customization page where users can upload images and input text, which will then be displayed on another page. I am wondering if it is possible to achieve this functionality using CSS and ...

A guide on sorting JSON data with Javascript/jquery

I have a set of JSON data: {"X1":"3","X2":"34","Y1":"23","Y2":"23","Z1":"234","Z2":"43",...} My goal is to rearrange and group this data as follows: var newDataJson1 = { "X":{"X1":"3","X2":34}, "Y":{"Y1":"23","Y2":"23"}, ... } ALSO, I want to stru ...

Disable the scroll bar on a bootstrap modal

<span class="education"style="font-size:170%;line-height:150%;">&nbsp;Education <br> <small style=" color:gray;font-size:60%;">&nbsp; Blue Ridge University,2012-2014 </small> <br> <sma ...

I'm attempting to solve the retrieved data from a firebase query, but unfortunately, the data is refusing to resolve

I've been attempting to retrieve data from firebase using Node.js, but I'm having trouble resolving it. Specifically, I need to extract the timestamp from the data stored in firebase. I've tried using promises and forEach loops, but haven&a ...

Hide the scrollbars on the sidebar

I'm attempting to recreate a sleek scrollbar that caught my eye on the website . To achieve this, I need to have a screen larger than 955px in order to display the sidebar. However, when my sidebar overflows in the y direction, it causes an additional ...

Tips for displaying subtotal in a Vue application using Firebase Realtime Database

I am currently troubleshooting a method in my Vue app that is designed to calculate the total value of all items sold. Despite seeing the correct values in both the database and console log, the calculation seems to be incorrect. Could there be an issue wi ...

What causes arguments to be zeroed out during a WebAssembly imported function call?

I created a WASM module manually that can be decompiled using wasm2wat to reveal the code below. (module (type (;0;) (func)) (type (;1;) (func (param i32 i32))) (import "std" "print" (func (;0;) (type 1))) (func (;1;) (type 0) ...