0

I’ve spent two days going back and forth, and it’s still the same. The text engraving depth varies on my curved 3D ring model—one side of the letter is deep, while the other side is not. I’m trying to use my .glb ring model, change its texture to silver, and add text that appears in the middle and looks engraved. I also want to be able to use x and y sliders to move the text. I could really use some help with this.

Main problem is: 1. wrong text alignment after i input text (its not in the middle of y axis. 2. Text looks not evenly deep.

{% assign model_found = false %} 

{% for media in product.media %}
  {% if media.media_type == 'model' %}
    {% assign model_url = media.sources[0].url %}
    
    <!-- 3D Model Container -->
    <div id="3d-container" style="width: 100%; height: 0; padding-bottom: 75%; position: relative;"></div>

    <!-- Text Input for Engraving -->
    <div style="margin-top: 20px; text-align: center;">
      <input type="text" id="engraveText" placeholder="Type your text here" style="padding: 10px; font-size: 16px; width: 60%; max-width: 300px;">
      <input type="color" id="textColor" value="#000000" style="padding: 10px; margin-left: 10px;">
    </div>

    <!-- Text Size and Position Sliders with Real-Time Value Display -->
    <div style="margin-top: 20px; text-align: center;">
      <label for="textSize">Text Size: <span id="textSizeValue">100</span></label>
      <input type="range" id="textSize" min="10" max="200" value="100" style="width: 50%; max-width: 300px;">
      <br>
      <label for="textPosX">Position X: <span id="textPosXValue">50</span></label>
      <input type="range" id="textPosX" min="0" max="100" value="50" style="width: 50%; max-width: 300px;">
      <label for="textPosY">Position Y: <span id="textPosYValue">50</span></label>
      <input type="range" id="textPosY" min="0" max="100" value="50" style="width: 80%; max-width: 300px;">
    </div>

    <!-- Invert and Mirror Text Buttons -->
    <div style="margin-top: 20px; text-align: center;">
      <button id="invertText" style="padding: 10px; font-size: 16px;">Invert Text</button>
      <button id="mirrorText" style="padding: 10px; font-size: 16px; margin-left: 10px;">Mirror Text</button>
    </div>

    <!-- Material Selection -->
    <div style="margin-top: 20px; text-align: center;">
      <label for="materialSelect">Choose Material:</label>
      <select id="materialSelect" style="padding: 10px; font-size: 16px;">
        <option value="metal">Metal</option>
        <option value="silver">Silver</option>
        <option value="gold">Gold</option>
      </select>
    </div>

    <!-- Engraving Depth Slider -->
    <div style="margin-top: 20px; text-align: center;">
      <label for="engravingDepth">Engraving Depth: <span id="engravingDepthValue">0.05</span></label>
      <input type="range" id="engravingDepth" min="0.01" max="0.2" step="0.01" value="0.05" style="width: 80%; max-width: 300px;">
    </div>

    <!-- Hidden input to store engraving data for order processing -->
    <input type="hidden" id="engravingDataInput" name="engravingData" value="">

    <!-- Include Three.js -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>

    <!-- Include GLTFLoader for loading 3D models -->
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/loaders/GLTFLoader.js"></script>

    <!-- Include OrbitControls -->
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/controls/OrbitControls.js"></script>

    <!-- Include RGBELoader for HDRI -->
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/loaders/RGBELoader.js"></script>

    <script>
      document.addEventListener('DOMContentLoaded', function() {
        const container = document.getElementById('3d-container');
        const containerWidth = container.clientWidth;
        const containerHeight = container.clientHeight;

        // Initialize Three.js Scene
        const scene = new THREE.Scene();

        // Load HDRI environment
        const rgbeLoader = new THREE.RGBELoader();
        rgbeLoader.load('https://dl.polyhaven.org/file/ph-assets/HDRIs/hdr/1k/brown_photostudio_02_1k.hdr', function (texture) {
          texture.mapping = THREE.EquirectangularReflectionMapping;
          scene.environment = texture;
          scene.background = texture; 
        });

        // Initialize Camera
        const camera = new THREE.PerspectiveCamera(75, containerWidth / containerHeight, 0.1, 1000);
        camera.position.set(0, 2, 5);

        // Initialize Renderer
        const renderer = new THREE.WebGLRenderer({ antialias: true });
        renderer.setPixelRatio(window.devicePixelRatio);
        renderer.setSize(containerWidth, containerHeight);
        renderer.physicallyCorrectLights = true;

        renderer.toneMapping = THREE.ACESFilmicToneMapping;
        renderer.toneMappingExposure = 2.0;  

        container.appendChild(renderer.domElement);

        // Add Ambient and Directional Lighting
        const ambientLight = new THREE.AmbientLight(0xffffff, 2);
        scene.add(ambientLight);

        const directionalLight = new THREE.DirectionalLight(0xffffff, 2);
        directionalLight.position.set(5, 10, 7.5).normalize();
        scene.add(directionalLight);

        // Initialize OrbitControls
        const controls = new THREE.OrbitControls(camera, renderer.domElement);
        controls.enableDamping = true;
        controls.dampingFactor = 0.05;
        controls.enablePan = false;

        let isTextInverted = false;
        let isTextMirrored = false;

        // Load the 3D Model
        const gltfLoader = new THREE.GLTFLoader();
        const modelUrl = "{{ model_url | escape }}";
        gltfLoader.load(modelUrl, function(gltf) {
          const model = gltf.scene;
          scene.add(model);
          model.position.set(0, 0, 0);

          const box = new THREE.Box3().setFromObject(model);
          const center = box.getCenter(new THREE.Vector3());
          model.position.sub(center);

          function updateTextInRealTime() {
            const text = document.getElementById('engraveText').value.trim();
            const color = document.getElementById('textColor').value;
            const textSize = document.getElementById('textSize').value;
            const posX = document.getElementById('textPosX').value;
            const posY = document.getElementById('textPosY').value;
            const material = document.getElementById('materialSelect').value;
            const engravingDepth = document.getElementById('engravingDepth').value;

            document.getElementById('textSizeValue').textContent = textSize;
            document.getElementById('textPosXValue').textContent = posX;
            document.getElementById('textPosYValue').textContent = posY;
            document.getElementById('engravingDepthValue').textContent = engravingDepth;

            const canvas = document.createElement('canvas');
            const context = canvas.getContext('2d');

            const canvasWidth = 1024;
            const canvasHeight = 1024;
            canvas.width = canvasWidth;
            canvas.height = canvasHeight;

            context.clearRect(0, 0, canvasWidth, canvasHeight);
            context.fillStyle = '#ffffff';
            context.fillRect(0, 0, canvasWidth, canvasHeight);

            context.font = `Bold ${textSize}px Arial`;
            context.textAlign = 'center';
            context.textBaseline = 'middle';
            context.fillStyle = color;

            // Adjust the Y-coordinate calculation
            const adjustedPosX = (canvasWidth * posX) / 100;
            const adjustedPosY = (canvasHeight * (100 - posY)) / 100; // Invert Y-axis

            if (isTextInverted) {
              context.scale(-1, 1);
              context.translate(-canvasWidth, 0);
            }

            if (isTextMirrored) {
              context.save();
              context.scale(1, -1);
              context.translate(0, -canvasHeight);
              context.fillText(text, adjustedPosX, canvasHeight - adjustedPosY);
              context.restore();
            } else {
              context.fillText(text, adjustedPosX, adjustedPosY);
            }

            const newTexture = new THREE.CanvasTexture(canvas);
            newTexture.needsUpdate = true;

            const bumpTexture = new THREE.CanvasTexture(canvas);
            bumpTexture.needsUpdate = true;

            const displacementTexture = new THREE.CanvasTexture(canvas);
            displacementTexture.needsUpdate = true;

            model.traverse(function(child) {
              if (child.isMesh) {
                let metalness = 1.0;
                let roughness = 0.15;
                let color = new THREE.Color(0xffffff);

                if (material === 'silver') {
                  roughness = 0.05;
                  color.setHex(0xC0C0C0);
                } else if (material === 'gold') {
                  roughness = 0.15;
                  color.setHex(0xD4AF37);
                } else {
                  roughness = 0.25;
                }

                const textMaterial = new THREE.MeshPhysicalMaterial({
                  map: newTexture,
                  bumpMap: bumpTexture,
                  bumpScale: 0.15,
                  displacementMap: displacementTexture,
                  displacementScale: parseFloat(engravingDepth),
                  roughness: roughness,
                  metalness: metalness,
                  clearcoat: 1.0,
                  envMap: scene.environment,
                  reflectivity: 1.0,
                  transparent: true,
                  color: color,
                  side: THREE.DoubleSide,
                });

                child.material = textMaterial;
                child.material.needsUpdate = true;
              }
            });

            const engravingData = {
              text: text,
              color: color,
              textSize: textSize,
              posX: posX,
              posY: posY,
              isTextInverted: isTextInverted,
              isTextMirrored: isTextMirrored,
              material: material,
              engravingDepth: engravingDepth
            };

            document.getElementById('engravingDataInput').value = JSON.stringify(engravingData);
          }

          document.getElementById('engraveText').addEventListener('input', updateTextInRealTime);
          document.getElementById('textSize').addEventListener('input', updateTextInRealTime);
          document.getElementById('textPosX').addEventListener('input', updateTextInRealTime);
          document.getElementById('textPosY').addEventListener('input', updateTextInRealTime);
          document.getElementById('textColor').addEventListener('input', updateTextInRealTime);
          document.getElementById('materialSelect').addEventListener('change', updateTextInRealTime);
          document.getElementById('engravingDepth').addEventListener('input', updateTextInRealTime);
          document.getElementById('invertText').addEventListener('click', function() {
            isTextInverted = !isTextInverted;
            updateTextInRealTime();
          });
          document.getElementById('mirrorText').addEventListener('click', function() {
            isTextMirrored = !isTextMirrored;
            updateTextInRealTime();
          });

          updateTextInRealTime();

          function animate() {
            requestAnimationFrame(animate);
            controls.update();
            renderer.render(scene, camera);
          }
          animate();
        });
      });
    </script>
  {% endif %}
{% endfor %}
New contributor
Aurelijus Sankauskas is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
1
  • 1
    Note that you're very unlikely to get an answer to this unless you provide a working example of the problem. Commented Sep 14 at 17:27

0

Browse other questions tagged or ask your own question.