Manipulating an SVG graphic's attributes by linking them to an external geometry in Three.js

Delving into the world of Three.js, I've embarked on a project to design a 3D kit creator for my college assignment.

Through my study, I've grasped the basics of setting up scenes, scene objects, geometries, materials, and textures.

I've reached a stage where I've established a scene, imported an external geometry - a .json model from Blender, and successfully applied a simple SVG graphic as a texture.

https://i.sstatic.net/cGfHB.png

Yet, I've hit a roadblock. The challenge now is to personalize the colors of the SVG (jersey design) on the model.

My initial plan was to dynamically manipulate the HTML attributes of the mapped SVG using JavaScript.

However, I encountered some issues with this approach:

  1. Three.js requires models and textures to be set up within it before being displayed in the browser through a canvas element, making it difficult to access and alter SVG attributes through the browser inspector.
  2. The texture loader function of Three.js seems to only accept file paths as inputs instead of directly using raw SVG code.

After seeking advice, I was encouraged to explore if there are any built-in features in Three.js that allow manipulation of SVG textures or ways to manually access SVG attributes.

Despite extensively searching through resources and documentation, I haven't found a solution yet.

Which brings me to my query:

How can one access and modify the properties of an SVG graphic applied as a texture to an external geometry in Three.js?

Perhaps there's something essential that I've missed or alternate approaches that could be explored? In any case, thank you for dedicating your time to read, offer insights, and provide assistance.

Stay blessed and appreciative.

Answer №1

To address this issue, a potential solution involves dynamically creating a texture programmatically by converting an array of pixels into a texture. This texture can then be utilized in a custom shader.

For further insights, you may refer to the following article: Exploring Dynamic Texture Implementation in Custom Shaders.

While this process is demonstrated using Autodesk Forge Viewer instead of plain Three.js, the fundamental methodology remains consistent as it is reliant on Three.js code.


//Implementation of customized shader with updatable dynamic texture
createShader (options) {

  // Vertex Shader code
  const vertexShader = options.vertexShader || `
    attribute float pointSize;
    attribute vec4 color;
    varying vec4 vColor;
    void main() {
      vec4 vPosition = modelViewMatrix * vec4(position, 1.0);
      gl_Position = projectionMatrix * vPosition;
      gl_PointSize = pointSize;
      vColor = color;
    }
  `

  // Fragment Shader code
  const fragmentShader = options.fragmentShader || `
    uniform sampler2D texture;
    varying vec4 vColor;
    void main() {
      vec4 tex = texture2D(texture, gl_PointCoord);
      if (tex.a < 0.2) discard;
      if (vColor.a == 0.0) {
        gl_FragColor = vec4(tex.r, tex.g, tex.b, tex.a);
      } else {
        gl_FragColor = vColor;
      }
    }
  `

  const tex = options.texture || defaultTex

  // Shader material parameters
  const shaderParams = options.shaderParams || {
      side: THREE.DoubleSide,
      depthWrite: false,
      depthTest: false,
      fragmentShader,
      vertexShader,
      opacity: 0.5,
      attributes: {
        pointSize: {
          type: 'f',
          value: []
        },
        color: {
          type: 'v4',
          value: []
        }
      },
      uniforms: {
        texture: {
          value: THREE.ImageUtils.loadTexture(tex),
          type: 't'
        }
      }
    }

  // creates shader material
  const material =
    new THREE.ShaderMaterial(
      shaderParams)

  const generateTexture = (size, radius) => {

    const pixels = []

    for (let u = 0; u < size; ++u) {

      for (let v = 0; v < size ; ++v) {

        const dist = Math.sqrt(
          (u/size - 0.5) * (u/size - 0.5) +
          (v/size - 0.5) * (v/size - 0.5))

        if (dist < 0.1) {

          pixels.push(0xff, 0x00, 0x00, 0xff)

        } else if (dist < (radius - 0.05)) {

          pixels.push(0xff, 0x00, 0x00, 0x00)

        } else if (dist < radius) {

          pixels.push(0xff, 0x00, 0x00, 0xff)

        } else {

          pixels.push(0x00, 0x00, 0x00, 0x00)
        }
      }
    }

    const dataTexture = new THREE.DataTexture (
      Uint8Array.from (pixels),
      size, size,
      THREE.RGBAFormat,
      THREE.UnsignedByteType,
      THREE.UVMapping
    )

    dataTexture.minFilter = THREE.LinearMipMapLinearFilter
    dataTexture.magFilter = THREE.LinearFilter 
    dataTexture.needsUpdate = true

    return dataTexture
  }

  const stopwatch = new Stopwatch()

  let radius = 0.0

  return {
    setTexture: (tex) => {

      const {texture} = shaderParams.uniforms

      texture.value = THREE.ImageUtils.loadTexture(tex)

      texture.needsUpdate = true

    },
    update: () => {

      const dt = stopwatch.getElapsedMs() * 0.001

      radius += dt * 0.25

      radius = radius > 0.5 ? 0.0 : radius

      const {texture} = shaderParams.uniforms

      texture.value = generateTexture(96, radius)

      texture.needsUpdate = true

    },
    material
  }
} 

https://i.sstatic.net/bLRyO.gif

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

Begin composing in Excel

I am looking to manipulate an existing Excel file by writing values from an array and closing it all on the client side. Here is the code snippet I have been using: for (var c=0; c<arrMCN.length; c++) { var mcnCreate = arrMCN[c]; var mcnNumber =mcnCre ...

Exploring the power of D3's nested appends and intricate data flow

Currently diving into the world of D3, I've encountered a perplexing issue that has yet to be resolved. Unsure if my confusion stems from a lack of familiarity with the library or if there's a key procedure eluding me, I feel compelled to seek gu ...

The ng-repeat function in AngularJs does not display the data despite receiving a successful 200 response

As part of my academic assignment, I am exploring Angularjs for the first time to display data on a webpage. Despite receiving a successful http response code 200 in the Chrome console indicating that the data is retrieved, I am facing issues with displayi ...

Leveraging _.after() within an asynchronous callback, causing contamination of an array variable

I am hoping that this question is unique and not a duplicate. I tried looking for similar questions here, but couldn't find any matching results. When working with node.js, the code below seems to be causing pollution in the storage variable. I' ...

Struggling with a Python CGI script that refuses to open a file sent to it via AJAX

After encountering multiple issues while attempting to upload a file to a server using HTML and Javascript in my previous post, I decided to take a different approach. I now have an HTML form and a Python script located in the cgi directory of my webserver ...

The seamless integration of React.js with HTML

My friend and I are beginners in the world of programming, with a solid grasp of html, CSS, and JavaScript. We're currently collaborating on a small project where we aim to create a chat system. While researching resources for our project, we came acr ...

The functionality of $state.go within $stateChangeStart in the app.run is not functioning properly in AngularJS

Having some trouble getting $state.go() function to work. The $on('$stateChangeStart'...); is functioning properly, and I can see the console message when trying to access a protected state without permission. However, the $state.go('toState ...

Is there a way to display the "back button" on a subview?

As a newcomer to Ionic, I am finding navigation to be the most challenging aspect. My app has two tabs - "Dashboard" and "Friends". When I click on the Dashboard tab, I want it to navigate to a subview called "subview_dash", without displaying the tabs in ...

Creating session variables in Joomla using checkboxes and AJAX

I'm currently working on implementing session variables in Joomla with AJAX when checkboxes are selected. Below is the code snippet from select_thumb.ajax.php file: $_SESSION['ss'] = $value; $response = $_SESSION['ss']; echo ...

Using the onclick event in JavaScript to create transition effects for swapping images

I am working on a website where I display 3 images. Instead of redirecting the users to a new page, I want to keep them on the same page. Question: How can I implement a functionality where clicking a <button> will display 3 new images in the view w ...

Guide to interacting with the Li element using JavaScript in Selenium

Is there a way to click on the item inside the li element using a Selenium script with JavaScript? I've tried different methods like By.cssSelector or by css, but I keep getting an ElementClickInterceptedError: element click intercepted:Other element ...

Tips for handling a promise that has not been fulfilled

Is there a way to return a promise and trigger its failure block right away? Check out this unconventional method: if (fail) { var q = $q.deferred(); $timeout(function() { q.reject("") }, 1); return q.promise; } else { return ...

What is the best method to update the accessor value of my react table depending on certain data conditions?

const data = { name:"test1", fclPrice:100, lclPrice:null, total:"50" } and here are the two columns: const Datatable = [ { Header: 'Name', accessor: 'name' }, { Header: 'Price', ac ...

Geometry of a Wireframe Cube

After upgrading from r59 to r62, I couldn't help but notice that the wireframe CubeGeometry now displays an extra diagonal line on each face. Is there a solution to this issue? volumeGeometry = new THREE.CubeGeometry(w, h, depth); volumeMaterial = ne ...

The Xero Node OAuth Authorize Callback URL is malfunctioning after granting access

When utilizing the xero-node library to produce a Request Token using the getRequestToken function, the URL provided does not automatically redirect the user to the designated callback address specified in the configuration. Instead, a screen displaying a ...

Calculating a 30-minute interval between two given times using JavaScript/jQuery

My goal is to generate a list of times between a specified start and stop time, with half-hour intervals. While I have achieved this using PHP, I now wish to accomplish the same task using JavaScript or jQuery. Here is a snippet of my PHP code which may ...

How to retrieve a single value from a collection document in Meteor

I'm in the process of extracting a specific value from a Meteor collection document to incorporate it into a three.js setting. My goal is to generate a three.js object that makes use of information stored in the database, which remains constant at thi ...

Are Viewmodel contents empty after ajax request?

Currently working on an ASP.NET MVC application, I am in the process of developing a search page that showcases both the search box and the table of results simultaneously. To achieve this functionality, I have utilized Partial Views along with AJAX/JSON c ...

Import a JavaScript file with beneficial test functions for selenium testing

Utilizing the runScript command in selenium has proven to be incredibly helpful for me. I've been using it to calculate values within a table and then store the result like so: <tr> <td>runScript</td> <td>var cumulativ ...

The elegant-admin template's mobile navigation toggle is missing

I recently downloaded an admin theme and added the CSS to my Django static files. However, after doing so, the mobile toggle feature disappeared. I double-checked all the CSS and JS links in the index template, and they are correctly linked to the paths, b ...