Transferring PointLight Parameters to a Custom Shader using three.js

I am looking to achieve a similar effect as the undulating sphere demonstrated in the Aerotwist Tutorial. Instead of using a fake GLSL hard-coded light like in the tutorial, I am interested in passing information from a three.js PointLight instance to my shaders, manipulating vertices and normals, and then implementing Phong shading.

My understanding of the GPU considerations when shading a scene in three.js is as follows (specifically with Phong):

  1. No GPU consideration: Utilize a MeshPhongMaterial without custom shaders for simplicity.
  2. Some GPU consideration: Use a pre-written ShaderLib Phong shader for additional control on the GPU side without custom modifications.
  3. Full GPU management: Employ a ShaderMesh and write custom shaders for complete customization by explicitly defining attributes and uniforms.

Q1: Is my understanding accurate?

Q2: Is there an intermediate option between levels 2 and 3 that allows for customizing shaders without creating them from scratch?

Q3: If not, what is the best approach to achieving full customization with level 3? Should I pass light properties as uniforms, modify vertex/normals, and then implement explicit Phong shading calculations?

Answer №1

It's quite simple to achieve what you're looking for using three.js

I'm unsure where it fits in your Q[]

Q1

  1. Even if you are using shaders, they may have been written by someone else for you. You only interface with them. When calling something like MeshBasicMaterial under the hood, a different shader may be compiled based on the input. For example, if there is no map called, UVS may not be processed and included in the shader. Your choice of function calls can still impact the GPU.
  2. If you are dealing with shader chunks, it is possible to tweak things here, but it can be complex. I recommend studying the code, such as phong shading, and start creating your own step by step using the chunks. Understand what inputs yield what outputs.
  3. No need to define attributes. THREE.ShaderMaterial isn't completely from scratch. It offers a good amount of built-in features and properties that can be customized further. Basic attributes like 'position' are already set up, eliminating the need for declaring "attribute vec3 position". MVP matrices, 'cameraPosition', and other essentials are automatically included. Constructing a phong shader from this point is relatively straightforward.

Now, how do you accomplish this. Suppose you're following a tutorial and have this shader:

// same name and type as VS
varying vec3 vNormal;

void main() {


//this is hardcoded you want to pass it from your environment
vec3 light = vec3(0.5, 0.2, 1.0);//it needs to be a uniform

// ensure it's normalized
light = normalize(light);//you can normalize it outside of the shader, since it's a directional light

// calculate the dot product of
// the light to the vertex normal
float dProd = max(0.0,
                dot(vNormal, light));

// feed into our frag color
gl_FragColor = vec4(dProd, // R
                  dProd, // G
                  dProd, // B
                  1.0);  // A

}

This is what you need to do:

GLSL

uniform vec3 myLightPos;//comes in
void main(){
    vec3 light = normalize(myLightPos);//but you better do this in javascript and just pass the normalized vec3
}

Javascript

new THREE.ShaderMaterial({
   uniforms:{
      myLightPos:{
         type:"v3",
         value: new THREE.Vector3()
      }
   },
   vertexShader: yourVertShader,
   fragmentShader: yourFragmentShader

});

Answer №2

Q1: Indeed correct. While some individuals on this platform have shared unauthorized methods for manipulating MeshPhongMaterial, it deviates from the original purpose.

Q2 and Q3: Take a look at ShaderLib.js where you will find the "Normal Map Shader." This serves as an ideal blueprint for your endeavor. Feel free to duplicate and tweak it according to your preferences.

This shader employs a Phong-based lighting model and conveniently interacts with scene lights on your behalf. The implementation is as follows:

var shader = THREE.ShaderLib[ "normalmap" ];

var uniforms = THREE.UniformsUtils.clone( shader.uniforms );

. . .

var parameters = {
    fragmentShader: shader.fragmentShader,
    vertexShader: shader.vertexShader,
    uniforms: uniforms,
    lights: true // enabling this flag grants access to scene lights
};

var material = new THREE.ShaderMaterial( parameters );

Refer to these demonstrations: and .

For coding conventions, consult ShaderLib.js and ShaderChunk.js.

Implemented in three.js r.67

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

The button functionality gets hindered within the Bootstrap well

I'm trying to figure out what's wrong with my code. Here is the code: https://jsfiddle.net/8rhscamn/ <div class="well"> <div class="row text-center"> <div class="col-sm-1">& ...

Display everything when an option is clicked

I have a filter that is working perfectly. When I select a specific category, it filters out only rows with that category. However, I am stuck on how to display all rows again after clicking on the first option. My objective is to show all rows when "Categ ...

What are all the functionalities provided by jquery select?

Currently, I am venturing into testing out a new jQuery plugin. let myPlugin = new MyPlugin(); $(#myPlugin).someFunction(); console.log($(myPlugin)) I'm curious - is there a way for me to see a full list of the available functions/methods for me to ...

Display issue with React TypeScript select field

I am working with a useState hook that contains an array of strings representing currency symbols such as "USD", "EUR", etc. const [symbols, setSymbols] = useState<string[]>() My goal is to display these currency symbols in a select field. Currently ...

Unable to retrieve the contents of a previous shopping cart

I need to update my shopping cart. I am trying to retrieve the information from my old cart, but for some reason, it's not working properly and I keep getting a quantity of 1. Below is the code for the app.post request: app.post("/add-to-cart/:i ...

Creating a Yeoman application with a personalized Node.js server

As I embark on the journey of developing a node.js and angular application using the powerful Yeoman tool, I can't help but wonder about one thing. Upon generating my application, I noticed that there are predefined tasks for grunt, such as a server ...

Is there a way to maintain the checked status of the checkboxes after a page refresh?

Is there a way to keep the checkboxes checked even after the page is refreshed in this code snippet? Any code sample or explanation on how to achieve this would be highly appreciated. The complete project code can be found here: https://github.com/Orelso/P ...

How can I load data into Vuex store before the application starts?

Within the created hook of App.vue, I am initiating a dispatch call to my store. Subsequently, in a child component, I attempt to retrieve this data using a getter. However, an issue arises as the child component is loaded before the data is stored, causin ...

Is there a way to divide a string and insert something into the new array that is created?

I am facing an issue with adding a new fruit to a string that is converted into an array. Here's the scenario: var fruits = "banana,apple"; In an attempt to add a new fruit to this list, I tried converting it to an array and then using the push meth ...

Tips on presenting messages to users after clicking the submit button?

I am trying to extract data from a table. I am unsure if my current code is able to retrieve the value from the table. <script> function validateForm() { var x = document.forms["assessmentForm"]["perf_rating11"].value; var y = document.f ...

Calculate the total width of all images

I'm on a mission to calculate the total width of all images. Despite my attempts to store image widths in an array for easy summing, I seem to be facing some challenges. It feels like there's a straightforward solution waiting to be discovered - ...

Struggling to navigate the world of JavaScript and find the sum of odd numbers?

Currently facing a roadblock with a codewars exercise and in need of some assistance. The exercise involves finding the row sums of a triangle consisting of consecutive odd numbers: 1 3 5 7 9 11 13 15 17 ...

Failed to perform the action using the Angular Post method

Currently, I am exploring the use of Angular with Struts, and I have limited experience with Angular. In my controller (Controller.js), I am utilizing a post method to invoke the action class (CartAction). Despite not encountering any errors while trigge ...

create a JavaScript array variable for posting items

My goal is to use this javascript to make four posts for the 'var msg' array. However, it currently posts 'encodeURIComponent(msg[i])' four times instead. How can I resolve this issue? var msg = ['one', 'two& ...

Passing a JSONArray to a webview using addJavascriptInterface can provide valuable data

Within my Android app assets, I have stored an HTML page that I want to display using a WebView and add parameters to the webpage. To achieve this, I populated all the values in a JSONArray and utilized 'addJavascriptInterface' to incorporate th ...

Prevent scrolling on browser resize event

I am working on a basic script that adds a fixed class to a specific div (.filter-target) when the user scrolls beyond a certain point on the page. However, I am wondering how I can prevent the scroll event from triggering if the user resizes their brows ...

Unfortunately, CORS is preventing me from sending a POST request through AJAX

I'm currently working on integrating an API into my website. I'm attempting to send a POST request with JSON data, but I keep encountering an error code when trying to make the request. Interestingly, sending the request using curl does not pose ...

RxJS emits an array of strings with a one second interval between each emission

Currently, my code is set up to transform an Observable<string[]> into an Observable<string>, emitting the values one second apart from each other. It's like a message ticker on a website. Here's how it works at the moment: const ...

Adding a line break ( ) in a paragraph within a TypeScript file and then transferring it to HTML does not seem to be functioning properly

Angular Website Component: HTML file <content-section [text]="data"></content-section> TypeScript file data = `Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's stand ...

Determine the identifier of the subsequent element located within the adjacent <div> using jQuery

I have a form with multiple input elements. While looping through some elements, I need to locate the id of the next element in the following div. You can find the complete code on jsfiddle $(":text[name^=sedan]").each(function(i){ var curTxtBox = $(thi ...