Unleashing the power of ShaderMaterial for achieving the perfect shadow

When using InstancedBufferGeometry to generate multiple boxes and updating their positions with Perlin noise, I encountered an issue where the mesh was casting shadows incorrectly. How can I calculate the correct shadow for this scenario?

vertexShader

attribute vec3 offset;
attribute vec4 orientation;
attribute vec3 color;

varying vec3 pos;
varying vec3 vNormal;
varying vec3 vWorldPosition;
varying vec3 vColor;

vec3 applyQuaternionToVector( vec4 q, vec3 v ){
    return v + 2.0 * cross( q.xyz, cross( q.xyz, v ) + q.w * v );
}

THREE.ShaderChunk["common"]
THREE.ShaderChunk["shadowmap_pars_vertex"]

void main() {
    vColor = color;

    vec3 vPosition = applyQuaternionToVector( orientation, position );
    pos = vPosition + offset;

    vNormal = normalMatrix * vec3(normal + normalize(offset) * 0.3);

    vec4 worldPosition = modelMatrix * vec4(pos, 1.0);
    vWorldPosition = worldPosition.xyz;

    gl_Position = projectionMatrix * modelViewMatrix * worldPosition;
    THREE.ShaderChunk["shadowmap_vertex"]
}

fragmentShader

THREE.ShaderChunk['common']
THREE.ShaderChunk['packing']
varying vec3 pos;
varying vec3 vNormal;
varying vec3 vWorldPosition;
varying vec3 vColor;

uniform vec3 lightPosition;

THREE.ShaderChunk['shadowmap_pars_fragment']
void main() {
    vec3 lightDirection = normalize(lightPosition + pos);

    float c = max(0.0, dot(vNormal, lightDirection)) * 2.;
    gl_FragColor = vec4(.3+c , .3+c , .3+c , 1.);
    THREE.ShaderChunk['shadowmap_fragment']
}

Check out the demo here

Using three.js r.106
Thanks

var scene, camera, renderer;
var plane, temp, vnh, point;
var radius = 10;
var stats = new Stats();
var start = Date.now();
var options = {
  scale: 200,
  density: 2.5
}
var currentQ = new THREE.Quaternion();
var initedBoxes = false;

var init = function() {
  // Initialize code goes here
  
}

var animate = function() {
  // Animation logic goes here
}

var render = function() {
  // Rendering code goes here
}

init();
<html>

<head>
  <title>Instanced buffer test</title>
  <style>
    * {
      padding: 0px;
      margin: 0px;
    }
    
    html,
    body {
      overflow: hidden;
    }
  </style>

  // External script imports go here

</head>

<body>
// Body content goes here
</body>

</html>

Answer №1

To ensure that the mesh casts a proper shadow, simply using a ShaderMaterial for the .material property of the mesh is not enough.
The shadow cast by point lights depends on the .customDepthMaterial property. This means you need to create a shader (ShaderMaterial) that renders the object with model transformations to the shadow map.


The mesh's shadow may be partially clipped by the near plane of the shadow camera.
By adjusting the near plane (e.g., setting it to 0.1 instead of 0.5) using the .near property of the perspective shadow camera (light1.shadow.camera), this issue can be resolved:

light1 = new THREE.SpotLight( 0xffffff, 2, 200, 10 );
light1.position.set( -30, 30, 40 );
light1.castShadow = true;
light1.shadow.mapSize.x = 2048;
light1.shadow.mapSize.y = 2048;
light1.shadow.camera.near = 0.1;
scene.add(light1);

Furthermore, there are some issues in the shader. The following statement:

vec3 lightDirection = normalize(lightPosition + pos);

is incorrect because a direction is calculated as the vector from one point to another using the (-)-operator (e.g., lightPosition - pos). However, fixing this won't solve the issue since lightPosition is a point in world space and pos is a point in model space.

To resolve this, calculate the vector in view space, as shown in the code snippet below:

vLightDir = mat3(viewMatrix) * (lightPosition - vWorldPosition);

Since worldPosition represents a position in world space, it should be transformed by the viewMatrix rather than the modelViewMatrix.

Vertex shader:
// Vertex shader code goes here
Fragment shader:
// Fragment shader code goes here

The provided JavaScript and HTML snippets contain code for initializing a scene, creating lights, geometry, materials, and shaders. The main functionalities include animating vertices based on noise, implementing shadows, and setting up controls for various parameters. Enjoy exploring and customizing the code for your projects!

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

Arrange the elements according to time in an array

I am in possession of some data retrieved from an API and I am looking to organize it based on the time stamp (iStart). Any suggestions or guidance on how to accomplish this task? The dataset consists of around 12 items, each containing various informati ...

Unable to retrieve all the necessary data from the LinkedIn API

I have attempted the following: Code Snippet in HTML: <a id="li_ui_li_gen_1432549871566_0-link" class="" href="javascript:void(0);" onclick="onLinkedInLoad();" style="margin-bottom: 20px;"> Javascript Function: function onLinkedInLoad(logintype) ...

Encountering difficulties in updating CSS styles using the useState hook in React

I am currently working on creating a modal in react that changes the background color when opened. The goal is to have the background color darken when the modal is activated and return to normal when the modal is closed. I attempted to achieve this using ...

Instead of modifying the selected class, jQuery generates inline styles

Utilizing the following code to dynamically create a class: $("head").append('<style type="text/css"></style>'); var newStyleElement = $("head").children(':last'); newStyleElement.html('.move{transform: translateX(1 ...

Steps to incorporate this jQuery script

After receiving a solution to my problem, I'm struggling with how to actually put it into practice. $(function(){ $.get('file1.php', function(data){ $('#dropdown1').html( data ); }); // when dropdown1 is chang ...

Jumbling a word by shuffling its letters into a random order

The objective of the program is to take the word you input into a box, split it into an array of letters, and then shuffle them. Following that, it should capitalize the first letter and lowercase the rest before displaying the result in the same box. I a ...

Is there a method in Adobe AIR for JS that allows for the storage of non-persistent data?

Working on a project, I am developing an app using Adobe AIR and have opted for the HTML/Ajax version. At this point, the project is relatively small, consisting of a login section and a details section. My goal is to display the login.html page upon app ...

Implementing jQuery to easily upload and display images

Discover a handy jQuery script that enables you to preview an image before uploading it. <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <scrip ...

Divergence between two distinctive occurrences in Google Analytics

Why are there differences in the number of unique events recorded by Google Analytics for two consecutive events? I have set up onClick tracking for a button. When the button is clicked, an event (Event 1) is sent to Google Analytics and a CSS-selector ap ...

Looking to retrieve the mouse coordinates using JavaScript

How can I use JavaScript to track the mouse position on a canvas? Upon visiting this page: http://billmill.org/static/canvastutorial/mouse.html They provide this code snippet: function initializeMouse() { canvasMinimumX = $("#canvas").offset().left; ...

What's the best way to retrieve the id or index of a card within a list?

Struggling to fetch the id's of documents retrieved from a MongoDB database and displayed on React and Material-Ui cards. Tried logging id in functions and APIs, but receiving 'undefined' or metadata from the delete function. Delete functi ...

problem encountered while attempting to transmit data to multer in React

I was attempting to upload an image to the backend using Multer. I have reviewed the backend code multiple times and it appears to be correct. Could there be an issue with my front-end code? Here is a POST code snippet: const response = await fetch(' ...

Vue.js navigation guards, restrict access to all unauthorized routes, grant entry to specific routes upon successful authentication

I'm currently working on implementing a navigation guard in Vue.js with a specific logic: I want to restrict access to all routes that require authentication and redirect users to the login page if they are not authenticated. The only exception is the ...

What is the reason behind State's disappearance only after a variable has been assigned to

Currently, I am working on a file gallery with a straightforward setup. The gallery consists of a master component and two sub-components. In the image preview section, there are left and right arrows that trigger a function named "clickHandler." This func ...

Transferring user input data from Angular 2 to Slim PHP endpoint

Help needed with parsing form-data in Slim PHP. How can I put form-data into an array in Slim PHP? I have tried different methods but the data always gets kicked out in one array with no specific way to target the form data. Any suggestions would be helpf ...

How can I set a unique color for the top face of a cylinder in Threejs?

Looking to create a basic cylinder with a unique color on its top face. I've managed to generate the cylinder and apply a material. Here's my latest code snippet: var zylinder = {}; zylinder._width = 1; zylinder._height = 1; zylinder._color = 0 ...

How can I customize an SVG using CSS when it's being accessed from another directory on my computer?

I find myself in a bit of a bind at the moment. Within my code lies an SVG depicting a map of the United States. Upon clicking on a specific state, the entire country fades away, revealing a separate SVG displaying only that state. Each of the 50 states is ...

Difficulty with the D3.js grid and tick functionality

Dealing with x-axis grid line formatting issues in a D3.js graph that I've created. var data = [{ x: '12-May-12', y: 5 }, { x: '30-Apr-12', y: 28 } // more data points listed here var margin = { top: 30, ...

Styled-Elements Text or Passages

Can we apply styling to text or paragraphs with styled-components? And if so, how can we insert text into the component? For instance, consider this Footer component: const Footer = () => ( <footer className="site-footer"> <p className= ...

Switching up the content of an HTML page with JavaScript or JQuery: what you need

Is it possible to update HTML content using JavaScript or JQuery? https://i.sstatic.net/EWOXg.png I am trying to change the contents from 1 to 5 in a sequential order based on the time shown in the image. How can I achieve this using JavaScript or JQuery ...