Using ThreeJS/WebGL to Send Functions to Shaders

I have created a custom noise function that accepts a 3D coordinate (x, y, z) and returns a noise value between 0 and 1. I am interested in incorporating this function into my vertex shader to animate vertex positions. Can I access this external function from within the vertex shader, or do I need to rewrite it directly in the shader code?

Appreciate any guidance on this matter.

Answer №1

To incorporate your function into the vertex shader itself, you can embed it as a string within the shader code. If you wish to reuse the same function across multiple shaders, consider utilizing string substitution, search and replace, or templates.

Here's an example:

const noiseSnippet = `
   vec3 noise(float v) {
      ...
   }
`;

const someVertexShaderSource = `
   ${noiseSnippet}

   varying vec2 vUv;

   void main() {
       vUv = uv;
       vec3 p = position + noise(position.x);
       vec4 mvPosition = modelViewMatrix * vec4(p, 1.0);
       gl_Position = projectionMatrix * mvPosition;
   }
`;

See below for a working demonstration:

// Function snippet from: https://gist.github.com/patriciogonzalezvivo/670c22f3966e662d2f83
const noiseSnippet = `
float mod289(float x){return x - floor(x * (1.0 / 289.0)) * 289.0;}
vec4 mod289(vec4 x){return x - floor(x * (1.0 / 289.0)) * 289.0;}
vec4 perm(vec4 x){return mod289(((x * 34.0) + 1.0) * x);}

float noise(vec3 p){
    vec3 a = floor(p);
    vec3 d = p - a;
    d = d * d * (3.0 - 2.0 * d);

    vec4 b = a.xxyy + vec4(0.0, 1.0, 0.0, 1.0);
    vec4 k1 = perm(b.xyxy);
    vec4 k2 = perm(k1.xyxy + b.zzww);

    vec4 c = k2 + a.zzzz;
    vec4 k3 = perm(c);
    vec4 k4 = perm(c + 1.0);

    vec4 o1 = fract(k3 * (1.0 / 41.0));
    vec4 o2 = fract(k4 * (1.0 / 41.0));

    vec4 o3 = o2 * d.z + o1 * (1.0 - d.z);
    vec2 o4 = o3.yw * d.x + o3.xz * (1.0 - d.x);

    return o4.y * d.y + o4.x * (1.0 - d.y);
}
`;

const vs = `
  ${noiseSnippet}

  uniform float time;

  void main() {
    float n = noise(vec3(position) + time) * 2. - 1.;
    vec3 p = position + vec3(0, n * .1, 0);
    vec4 mvPosition = modelViewMatrix * vec4(p, 1.0);
    gl_Position = projectionMatrix * mvPosition;
  }
`;
const fs = `
  precision mediump float; 
  void main() {
    gl_FragColor = vec4(1, 0, 0, 1);
  }
`;

const camera = new THREE.PerspectiveCamera(40, 1, 1, 3000);
camera.position.z = 4;

const scene = new THREE.Scene();

const geometry = new THREE.BoxGeometry(1, 1, 1);
const uniforms = {
  time: { value: 0, },
};
const material = new THREE.ShaderMaterial({
  uniforms: uniforms,
  vertexShader: vs,
  fragmentShader: fs,
  wireframe: true,
});
var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);

renderer = new THREE.WebGLRenderer();
document.body.appendChild(renderer.domElement);


function resizeCanvasToMatchDisplaySize(canvas) {
  const width = canvas.clientWidth;
  const height = canvas.clientHeight;
  if (canvas.width !== width || canvas.height !== height) {
    renderer.setSize(width, height, false);
    camera.aspect = width / height;
    camera.updateProjectionMatrix();
  }
}

function render(time) {
  time *= 0.001;  // convert to seconds
  uniforms.time.value = time * 4.;
  
  resizeCanvasToMatchDisplaySize(renderer.domElement);
  
  mesh.rotation.y = time;
  
  renderer.render(scene, camera);
  
  requestAnimationFrame(render);
}
requestAnimationFrame(render);
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r83/three.min.js"></script>

Answer №2

To include a function in a shader, it must be directly written within the vertex shader source code. It is not possible to bring in a function from another shader by passing it as a parameter or any other method of importation.

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

Tips to swap selections in a Select2 dropdown box

Is there a way to dynamically clear a Select2 option list and reload it with new data? Despite setting the data as suggested, it seems to only append the new data without clearing the existing options. $("#optioner").select2(); $("#doit").click(functio ...

Can you explain the distinction between these two Redux reducer scenarios?

While looking at someone else's code for a reducer, I noticed this snippet: export default function reducer(state, action) { switch(action.type) { case 'ADD_TODO': Object.assign({}, state, { ...

Interactive jQuery tabbed interface with drop-down selectors, inconsistent display of drop-down options when switching between tabs

After receiving assistance from members oka and Mike Robinson, I have successfully created two tables for users to interact with using tabs and dropdowns. Both tables have the same structure and feature a dropdown menu to show/hide columns. Users can sele ...

Can you use ng-show within ng-if in Angular?

How can I make this input only show a property is true per the ng-if? The current code looks like this: <input type="button" class="naviaBtn naviaBlue" ng-if="ppt.Globals.hasDebitCard" ng-click="alertShow = (alertShow == 2 ? -1 : 2)" value="outstandin ...

What could be causing certain javascript functions to not work properly?

Currently, I am using JavaScript and AJAX to validate a registration form. The functions restrict(elem) and checkusername() are both working as intended. When the AJAX passes the checkusername variable to PHP, it checks if the username exists and displays ...

When utilizing an 'imported' asynchronous function, make sure to clean up the useEffect

Please do not mistake this for a duplicate. Despite my thorough search on various blogs and sources, I have yet to find a solution. My primary question is 'how can I address the error of react state change in unmounted component, and also cancel an a ...

Malfunctioning string error in Django view caused by boolean inconsistencies

Looking to extract variables from a post request made by Javascript. Upon inspecting the received variables in my view, I found the following: >>> print request.body {"p":"testprd","cash":false,"cheque":true,"debit":false,"credit":true} The valu ...

What is the process for setting up a new router?

When it comes to templates, the vuestic-admin template from https://github.com/epicmaxco/vuestic-admin stands out as the perfect fit for my needs. However, I have a specific requirement to customize it by adding a new page without displaying it in the side ...

ReactJs - Reactstrap | Issue with Jumbotron displaying background color

I am trying to create a gray background using Jumbotron in reactstrap. After installation and reference in required places - index.js import 'bootstrap/dist/css/bootstrap.css'; Jumbotron has been implemented in SignIn.js - import Re ...

Utilize a Google Chrome extension to interact with the DOM of the active tab

Alright, so I've got a good grasp on JavaScript/jQuery and can use them for various tasks. However, my current challenge involves manipulating the DOM of the open tab. I'm curious to know if it's feasible or if all the actions performed by a ...

What is the best approach for retrieving a User from my Angular front-end service?

INQUIRY: I'm attempting to retrieve the details of the currently logged in user in my Angular 2 frontend service with the following code: UserModel.findById(userID, function (err, user) { It appears that this behavior is achievable from the browse ...

What is the best way to handle an ajax call while working with the main Vue instance?

I have a VueJS component that makes an AJAX call to GitHub using the following code: (Child) Component Vue.http.get('user/repos').then((response) => { console.log(response); }, (response) => { console.log(response); }); The issue ...

JS backbone require global models in js

I am looking to implement a UserSession model that will handle loading and saving session IDs into cookies using the jQuery cookie plugin. Below is the code for my UserSession model module: define(['jQuery', 'Underscore', 'Backbo ...

How can user input be converted into a JavaScript variable?

Looking for help with my webpage - I want users to input their name and age. After hitting submit, I'd like the first input to be stored in a variable called 'name', and the second input in a variable called 'age'. Is this doable? ...

What is the best way to evaluate a sequence of actions and their outcomes?

Recently, I've dived into the world of writing automated tests for a React application. Along the way, I encountered some intriguing questions about the best approach to testing a series of interactions within the app. Let's imagine a scenario w ...

Exploring the potentials of AngularJs Datatables Promise and the ignited power of Ignited

I am currently facing an issue with populating a datatable in AngularJS. DataTables warning: table id=DataTables_Table_0 - Requested unknown parameter '0' for row 0, column 0. For more information about this error, please see http://datatables.n ...

What is the best way to save a large quantity of objects to a server using ajax and php?

Imagine a scenario where I have a page containing 100 objects, each around 700 bytes when converted to json format. When it comes to saving these objects to the php based controller, there are several options available to me. Option 1: For each object ( ...

Error in React Bootstrap: ReferenceError - 'openModal' is not defined

Whenever the button is clicked, my intention is for a modal to open. I have written the code for it, but I'm encountering errors that I can't seem to resolve. Here's the snippet of my code: import React from "react"; import { M ...

Using Rails to Pass Front-End JavaScript Data from an External API to the Controller

I need to retrieve coordinates from an external API, specifically the Google Maps API, and then send it to my controller. However, I am encountering a 500 internal server error when using jQuery/Ajax for this task. Researching the issue online suggests tha ...

Imposing the situation

In my current class, I have a private property and a public method for access: Person = function () { this.Name = "asd"; var _public = new Object(); _public.Name = function (value) { if (value == undefined) { //Get return ...