What is the best way to create a sharp light effect on a sphere in three.js?

My three.js scene features a sphere and directional light. The sphere appears to gradually darken as you look at it. How can I speed up the transition from light to dark? Is there a way to make the light appear "sharper"?

var scene, camera, renderer, controls, sphere, geometry, material, light;

scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.x = 3;
camera.position.z = 6;
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0xffffff, 1);
document.body.appendChild(renderer.domElement);

geometry = new THREE.SphereGeometry(1, 32, 32);
material = new THREE.MeshPhongMaterial({
color: 0x777777
});
sphere = new THREE.Mesh(geometry, material);
scene.add(sphere);

light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(0, 10, 10);
scene.add(light);

renderer.render(scene, camera);
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r83/three.js"></script>

Answer №1

To achieve the desired effect, one method is through the use of toon shading. Consider experimenting with MeshToonMaterial. You can also create a custom gradientMap to specify the illuminated areas of the material.

var scene, camera, renderer, controls, sphere, geometry, material, light;

scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.x = 3;
camera.position.z = 6;
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0xffffff, 1);
document.body.appendChild(renderer.domElement);

geometry = new THREE.SphereGeometry(1, 32, 32);
material = new THREE.MeshToonMaterial({
color: 0x777777
});
sphere = new THREE.Mesh(geometry, material);
scene.add(sphere);

light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(0, 10, 10);
scene.add(light);

renderer.render(scene, camera);
<script src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="ed99859f8888adddc3dcdcd8">[email protected]</a>/build/three.js"></script>

Answer №2

To adjust the shininess of a material, simply set the material.shininess. For more information on materials in Three.js, you can refer to this link

var scene, camera, renderer, controls, sphere, geometry, material, light;

scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.x = 1;
camera.position.z = 2;
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0xffffff, 1);
document.body.appendChild(renderer.domElement);

geometry = new THREE.SphereGeometry(1, 32, 32);
material = new THREE.MeshPhongMaterial({
color: 0x777777,
shininess: 400,
});
sphere = new THREE.Mesh(geometry, material);
scene.add(sphere);

light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(0, 10, 10);
scene.add(light);

renderer.render(scene, camera);
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r83/three.js"></script>

Even when using a MeshToonMaterial, it is essential to specify a value for shininess if you wish to eliminate specular highlights completely.

var scene, camera, renderer, controls, sphere, geometry, material, light;

scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.x = 1;
camera.position.z = 2;
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0xffffff, 1);
document.body.appendChild(renderer.domElement);

geometry = new THREE.SphereGeometry(1, 32, 32);
material = new THREE.MeshToonMaterial({
color: 0x777777,
shininess: 0,

});
sphere = new THREE.Mesh(geometry, material);
scene.add(sphere);

light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(0, 10, 10);
scene.add(light);

renderer.render(scene, camera);
<script src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="c6b2aeb4a3a386f6e8f7f7f3">[email protected]</a>/build/three.js"></script>

In addition, unless you are utilizing a gradientMap, the relative intensity of light is fixed within your scene.

var scene, camera, renderer, controls, sphere, geometry, material, light;

scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.x = 0;
camera.position.z = 2;
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0xffffff, 1);
document.body.appendChild(renderer.domElement);

geometry = new THREE.SphereGeometry(1, 32, 32);
material = new THREE.MeshToonMaterial({
color: 'red',
shininess: 0,
gradientMap: new THREE.DataTexture(
new Uint8Array([
0, // black 
255, // white
]),
2, 
1, 
THREE.LuminanceFormat, 
),
});
sphere = new THREE.Mesh(geometry, material);
scene.add(sphere);

light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(50, 50, 30);
scene.add(light);

renderer.render(scene, camera);
<script src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="fa8e92889f9fbacad4cbcbcf">[email protected]</a>/build/three.js"></script>

It's important to note that the cutoff threshold in the gradientMap is influenced by its dimensions. To alter this threshold, consider adjusting the size and colors within the map itself.

var scene, camera, renderer, controls, sphere, geometry, material, light;

scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.x = 0;
camera.position.z = 2;
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0xffffff, 1);
document.body.appendChild(renderer.domElement);

geometry = new THREE.SphereGeometry(1, 32, 32);
material = new THREE.MeshToonMaterial({
color: 'red',
shininess: 0,
gradientMap: new THREE.DataTexture(
new Uint8Array([
0, // black 
0,
255, // white 
255, 
255,
]),
5, 
1, 
THREE.LuminanceFormat, 
),
});
sphere = new THREE.Mesh(geometry, material);
scene.add(sphere);

light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(50, 50, 30);
scene.add(light);

renderer.render(scene, camera);
<script src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="384c504a5d5d78081609090d">[email protected]</a>/build/three.js"></script>

If you wish to define multiple colors or divisions in the gradientMap, ensure to include all desired colors within the map itself.

var scene, camera, renderer, controls, sphere, geometry, material, light;

scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.x = 0;
camera.position.z = 2;
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0xffffff, 1);
document.body.appendChild(renderer.domElement);

geometry = new THREE.SphereGeometry(1, 32, 32);
material = new THREE.MeshToonMaterial({
color: 'white',
shininess: 0,
gradientMap: new THREE.DataTexture(
new Uint8Array([
255, 0, 255, // purple 
0, 255, 255, // cyan 
]),
2, 
1, 
THREE.RGBFormat, 
),
});
sphere = new THREE.Mesh(geometry, material);
scene.add(sphere);

light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(50, 50, 30);
scene.add(light);

renderer.render(scene, camera);
<script src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="dda9b5afb8b89dedf3ecece8">[email protected]</a>/build/three.js"></script>

For more than two colors or divisions, ensure to include additional colors within the gradientMap.

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

Emphasize Expandable Sections based on Search Term

I have been working on developing an HTML page for my company that will showcase a list of contacts in an "experts list". Currently, the list is structured using collapsible DIVs nested within each other. Additionally, the HTML page features a search func ...

Issue with JQuery UI Tabs not displaying additional HTML pages in JavaScript

One issue I'm facing is that I added Tabs from JQuery UI on my website. The tab containing paragraphs loads fine, but the tabs linked to other HTML pages (which don't have tabs) won't load. Here is my .js file code and .html code: $(funct ...

Is it possible in Angular JS to only load a service in the specific JS file where it is needed, rather than in the app.js file

I attempted to do something like: var vehicle_info = angular.module('psngr.vehicle_info', []).factory('vehicle_info', ['$rootScope', '$timeout', '$q', vehicle_info]); var name = vehicle_info.getNameOfVclas ...

How can I incorporate a feature in my Angular application that allows users to switch between different view types, such as days, using JavaScript

Greetings, community! I am currently utilizing version 5 of the fullcalendar library from https://fullcalendar.io/ in my Angular 9 application. I have noticed that the calendar offers various options to change the view type as shown below: https://i.stac ...

What is preventing the listener from activating?

I came across some HTML code that looks like this: <form id="robokassa" action="//test.robokassa.ru/Index.aspx" method="post"> <input type="text" id="OutSum" name="OutSum" value="" placeholder="Сумма пополнения"> ...

What steps can be taken to stop the update function from inserting data into MongoDB from a Meteor application

Within my Meteor method, I have implemented a function to check for existing documents. If the document is not found, it gets inserted into the database. However, if it is found during a second attempt, the document is updated and a new one is also inserte ...

Determine the percentage of clicks on an HTML5 canvas radial progress bar

Recently, I designed a circular progress bar displaying a specific percentage. However, I am facing a challenge in determining how to calculate the percentage when a user clicks on either the black or green part of the circle. Could you provide insight on ...

Using expect() within the .then() function when writing Jasmine unit tests for AngularJS

I'm currently struggling with the .then() function while trying to implement Jasmine unit testing. Here is the code that's giving me trouble: describe("getBuilding", function () { it("checks getBuilding", function () { var id_building = 4; ...

Combining Flask with Ajax: AttributeError - WSGIRequestHandler does not have the attribute 'environ'

Currently, I am working on using ajax to trigger the execution of a Python file that continuously monitors changes in a text file. If any changes are detected, it will communicate back to ajax for further actions. The Python script must start running as so ...

How come the callback in Jquery fadeOut keeps looping repeatedly, and what can I do to stop this from happening?

My approach involves fading out a div box and implementing a callback function as shown below: function closeWindow(windowIdPrefix, speed) { $("#" + windowIdPrefix + "_ViewPanel").fadeOut(speed, function() { resetWindow(windowIdPre ...

An onClick event is triggered only after being clicked twice

It seems that the onClick event is not firing on the first click, but only works when clicked twice. The action this.props.PostLike(id) gets triggered with a delay of one click. How can I ensure it works correctly with just one click? The heart state togg ...

When attempting to call a recursive method in Vue with a changing `this` object, an error is thrown: "RangeError: Maximum call stack size exceeded"

Update integrate codePen into the project. https://codepen.io/jiaxi0331/pen/xxVZBMz Description encountered an issue while trying to call the parent method recursively Code export default { methods: { dispatch(componentName, event, value) { ...

Handling keypress events in jHtmlArea

Currently working on a text-to-symbol conversion tool as a non-profit project, I have encountered an issue: For the WYSIWYG editing of the text, I am in search of a sleek and compact wysiwyg editor (like jHtmlArea). Since this editor displays floating div ...

Save JSON Tree data in the Database

Given a tree structure JSON, I am tasked with creating an API to insert all the data into a database at once. The organization entities can have multiple parents and children relationships. An example of the JSON data: { "org_name": "orga ...

Verify if a certain value exists in an array while using ng-if inside ng-repeat

Currently, I have a loop using ng-repeat that goes through a list of wines obtained from an API. Alongside this, there is an array variable containing all the IDs of wines that have been marked as favorites and retrieved from the database. My goal is to sh ...

Guide to appending the chosen item from a search bar to a fresh array using vue3 js

Does anyone know how to resolve the issue I'm facing with adding selected items from a dropdown list to a new array and displaying them on the page? Currently, I have added an onblur event to the input field to hide the dropdown when clicked outside, ...

Methods for applying a style property to a div element with JavaScriptExecutor in Selenium utilizing C#

I have been attempting to change the style of a div element using JavascriptExecutor in C#, but so far, nothing has happened. IJavaScriptExecutor js = (IJavaScriptExecutor)driver; IWebElement element = driver.FindElement(By.XPath("//div[contains(@class, ...

What exactly is the mechanism behind the functionality of ng-cloak?

Recently, I've been delving into the ng-cloak source code and trying to understand its inner workings. If you're interested, you can take a look at the source code here. From what I gather, it seems that the ng-cloak attribute is removed during ...

After using `setAttribute`, React is unable to produce any audio

Currently, I am facing an issue with a React component where it should play sound from an array of IDs stored in the database by setting the ID to the src attribute for the source tag. However, this functionality is not working as expected. Interestingly, ...

The issue with the <Button> component not properly linking in next.js

Having trouble with a button wrapped inside a custom Navbar component. The code snippet in question is: <NavBtn> <Link href="/contact" passHref> <Button> Contact Me </Button> </Link> & ...