Tips for creating a mirrored image on an IcosahedronGeometry using three.js

My goal is to create a rotating IcosahedronGeometry in three.js and have it reflect an image on the front side of the geometry.

After successfully creating the IcosahedronGeometry and implementing rotation on its axis, I encountered an issue when trying to reflect an image on the front side.


var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(
  75,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);

// RENDERER
var renderer = new THREE.WebGLRenderer({
  antialias: true
});

// RENDERER - SIZE OF CANVAS
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor('#ffffff');
document.body.appendChild(renderer.domElement);

// RESPONSIVE RENDERING
window.addEventListener('resize', () => {
  renderer.setSize(window.innerWidth, window.innerHeight);
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
});

var groundMaterial = new THREE.MeshPhongMaterial({
  shininess: 100,
  color: 0xffffff,
  specular: 0xffffff
});
const cubeCamera = new THREE.CubeCamera(75, 1000, 512);
scene.add(cubeCamera);
// GEOMETRY
var geometry = new THREE.IcosahedronGeometry(2, 1);
var material = new THREE.MeshStandardMaterial({
  color: 0x98bbbd,
  side: THREE.FrontSides,
  roughness: 1,
  metalness: 0.5,
  envMap: cubeCamera.renderTarget
});

material.roughness = 0;
material.metalness = 1;
material.flatShading = true;
material.envMap = cubeCamera.renderTarget.texture;
var sphere = new THREE.Mesh(geometry, material);
scene.add(sphere);

console.log(sphere.position);
console.log(cubeCamera.position);
cubeCamera.position.copy(sphere.position);
cubeCamera.update(renderer, scene);

// FLOOR
var floorTexture = new THREE.ImageUtils.loadTexture('images/woman.png');
// floorTexture.wrapS = floorTexture.wrapT = THREE.RepeatWrapping;
// floorTexture.repeat.set(1000, 1000);
var floorMaterial = new THREE.MeshBasicMaterial({
  map: floorTexture,
  side: THREE.BackSide
});
var floorGeometry = new THREE.PlaneGeometry(5, 5, 1, 1);
var floor = new THREE.Mesh(floorGeometry, floorMaterial);
floor.position.y = 0;
floor.position.x = 0;
floor.position.z = 3;
scene.add(floor);

cubeCamera.lookAt(floor);
// CONTROLS
var orbit = new THREE.OrbitControls(camera, renderer.Mesh);
camera.position.z = 5;

// LIGHTS
var topLeftLight = new THREE.PointLight(0xffffff, 1, 1);
topLeftLight.position.set(-50, 50, -25);
scene.add(topLeftLight);
// Additional light configurations...

// update function
function render() {
  requestAnimationFrame(render);
  sphere.rotation.x += 0.005;
  sphere.rotation.y += 0.005;

  sphere.visible = false;
  cubeCamera.update(renderer, scene);
  sphere.visible = true;

  renderer.render(scene, camera);
}
render();

My objective is to achieve a rotating IcosahedronGeometry with an image reflected on its front side. Although I attempted to use a cube camera and align it with a PlaneGeometry featuring an image texture, the desired reflection effect was not achieved. My intention is to simulate a similar visual effect, even if it does not exactly replicate the reference image provided.

Aspiring to attain the desired result through experimentation and refinement.

Answer №1

Here are 3 important points to consider:

  1. Make sure to call cubeCamera.update before accessing cubeCamera.renderTarget.texture

  2. When initializing CubeCamera, the correct parameters are new CubeCamera(near, far, size).

    The existing code had new CubeCamera(75, 1000, 512), meaning only objects within the range of 75 to 1000 units from the camera would be visible. Since the image plane is 3 units away, it would not be visible.

  3. Avoid using lookAt with the CubeCamera as it is designed to look in all directions.

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(
  75,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);

// RENDERER
var renderer = new THREE.WebGLRenderer({
  antialias: true
});

// RENDERER - SIZE OF CANVAS
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor('#ffffff');
document.body.appendChild(renderer.domElement);

// RESPONSIVE RENDERING
window.addEventListener('resize', () => {
  renderer.setSize(window.innerWidth, window.innerHeight);
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
});

var groundMaterial = new THREE.MeshPhongMaterial({
  shininess: 100,
  color: 0xffffff,
  specular: 0xffffff
});
const cubeCamera = new THREE.CubeCamera(0.001, 10, 512);
scene.add(cubeCamera);
// GEOMETRY
var geometry = new THREE.IcosahedronGeometry(2, 1);
var material = new THREE.MeshStandardMaterial({
  color: 0x98bbbd,
  side: THREE.FrontSide,
  roughness: 1,
  metalness: 0.5,
});
cubeCamera.update(renderer, scene);

material.roughness = 0;
material.metalness = 1;
material.flatShading = true;
material.envMap = cubeCamera.renderTarget.texture;
var sphere = new THREE.Mesh(geometry, material);
scene.add(sphere);

// FLOOR
var loader = new THREE.TextureLoader();
var floorTexture = loader.load('https://i.imgur.com/UKBsvV0.jpg');
var floorMaterial = new THREE.MeshBasicMaterial({
  map: floorTexture,
  side: THREE.BackSide
});
var floorGeometry = new THREE.PlaneGeometry(5, 5, 1, 1);
var floor = new THREE.Mesh(floorGeometry, floorMaterial);
floor.position.y = 0;
floor.position.x = 0;
floor.position.z = 3;
scene.add(floor);

// CONTROLS
var orbit = new THREE.OrbitControls(camera, renderer.Mesh);
camera.position.z = 5;

// LIGHTS
var topLeftLight = new THREE.PointLight(0xffffff, 1, 1);
topLeftLight.position.set(-50, 50, -25);
scene.add(topLeftLight);

var topRightLight = new THREE.PointLight(0xffffff, 1, 10);
topRightLight.position.set(50, 150, -25);
scene.add(topRightLight);

var lightBottomRight = new THREE.PointLight(0xffffff, 1, 100);
lightBottomRight.position.set(40, -50, 25);
scene.add(lightBottomRight);

var lightBottomLeft = new THREE.PointLight(0xffffff, 1, 100);
lightBottomLeft.position.set(-40, -50, 25);
scene.add(lightBottomLeft);

var lightTopRight = new THREE.PointLight(0xffffff, 1, 100);
lightTopRight.position.set(40, 50, 25);
scene.add(lightTopRight);

var lightTopLeft = new THREE.PointLight(0xffffff, 1, 100);
lightTopLeft.position.set(-40, 50, 25);
scene.add(lightTopLeft);

var backLight = new THREE.PointLight(0xffffff, 1, 100);
backLight.position.set(0, 0, -25);
scene.add(backLight);

var light = new THREE.AmbientLight(0x404040, 2); // soft white light
scene.add(light);

// update function
function render() {
  sphere.rotation.x += 0.005;
  sphere.rotation.y += 0.005;

  sphere.visible = false;
  cubeCamera.update(renderer, scene);
  sphere.visible = true;

  renderer.render(scene, camera);
  requestAnimationFrame(render);
}
render();
<script src="https://threejsfundamentals.org/threejs/resources/threejs/r105/three.min.js"></script>
<script src="https://threejsfundamentals.org/threejs/resources/threejs/r105/js/controls/OrbitControls.js"></script>

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

Common mistakes made while working with decorators in Visual Studio Code

Having trouble compiling TypeScript to JavaScript when using decorators. A persistent error message I encounter is: app.ts:11:7 - error TS1219: Experimental support for decorators is a feature that is subject to change in a future release. Set the ' ...

Sending a JSON array in an AJAX request results in receiving null values in an MVC application

I've been trying to send an array of JSON objects to my controller action, but it keeps showing up as null. Here's the JavaScript code I'm using: function UpdateSelected() { var items = {}; //Loop through grid / sub grids and crea ...

Learn how to extract substrings from a variable within an API using Vue.js

Exploring VueJs for the first time and looking to split a string by comma (,) retrieved from an API into separate variables. The data is coming from a JSON server. "featured-property": [ { "id": "1", " ...

Experiencing difficulties in installing opensea-js using NPM

While working on my project, I encountered an issue when trying to install opensea-js as a dependency. My Node version is v14.16.0 and NPM version is v7.7.5. Every time I run the command npm install --save opensea-js, it results in an error. I attempted c ...

An error arises with the THREE.Euler().copy method in versions 88 and 89

After updating to revision 88 and beyond, I encountered an issue with the following code: function moveAndLookAt(dstpos, dstlookat, duration = 500) { TWEEN.removeAll(); var origpos = new THREE.Vector3().copy(camera.position); // original position ...

When using a wildcard router in Node.js/Express.js, the static router may not be recognized

While using this specific route along with my other routes, I encounter an issue with serving static files: var public_dir = path.join(__dirname, 'public'); app.use('/public', express.static(public_dir)); However, when I add the follo ...

Retrieve a specified quantity of JSON data from an external API

Dealing with a recently received API from an external source: (please note: the data returned is extensive) I'm aware that I can retrieve this large object by using the following method: $.getJSON('https://www.saferproducts.gov/RestWebServices ...

Experimenting with an rxjs service to perform a GET request within the component

When calling the service function, the syntax is as follows: get getLayerToEdit(): BehaviorSubject<VectorLayer> { return this.layerToEdit; } This function is then invoked in the ngOnInit method like this: ngOnInit() { this.annoServic ...

Issue with Material-ui IconButton's edge properties not functioning as expected

Is there a way to position the delete icon on the right side of the screen? It seems like using edge= "end" is not working as expected. If you'd like to take a look, here is the sandbox link: https://codesandbox.io/s/admiring-silence-vwfoe? ...

An effective way to prevent right-clicking on iframes across all websites

I am facing an issue with disabling right click for the iframe. I've successfully disabled it for the default URL of the IFrame, but when displaying any other webpage, the right click remains usable. Below are the sample codes I have used: document.o ...

What causes the JavaScript code to output the number 3?

What is the reason behind the output a == 3 in this code snippet? var x = "abc"; var y = 3; var z = "xyz"; var a = x && y || z; Here is the link to interact with the code: http://jsfiddle.net/thinkingmedia/qBZAL/ One might assume that a == true ...

Vue 3 - Child Component Script Not Updating with Reactive Prop Changes

I am facing an issue where I am trying to pass a reactive data as a prop to a child component in Vue 3. The data updates correctly in the child component's template, but it does not reflect in the child component's script. In the parent component ...

Transforming JSON data into XML using Angular 7

It turns out the xml2js npm package I was using doesn't support converting JSON to XML, which is exactly what I need for my API that communicates with an application only accepting XML format. In my service file shipment.service.ts import { Injecta ...

Is there a way to incorporate the load page plugin specifically for JavaScript while ensuring that my PHP code is still functional?

Is there a way to implement the loading page plugin "PACE" for PHP code execution instead of just JavaScript? I am more comfortable with PHP, CSS, and HTML, but not very experienced in JavaScript/AJAX. The PACE plugin is designed to show a progress bar fo ...

What is the best way to align two bootstrap buttons next to each other?

Is there a way to align buttons on a modal side by side? One button is a download link and the other a mirror link. I attempted to use a custom class with CSS property "display: inline-block;" but it did not work as expected. Any suggestions on how to achi ...

Eliminate item from array based on certain criteria

In certain scenarios, I must update the filters. Under specific data conditions, I am required to eliminate 1 item from an array. Here is the code snippet: useEffect(() => { let canceled = false; const filters = [ new C ...

The JavaScript indexOf method in an unordered list incorrectly returns the index of a specific event

Looking to retrieve the index number of an 'li' element within a 'ul' from the HTML structure. I attempted to convert the 'ul' into a list and access its children using: [...ul.children] However, upon targeting any of the chi ...

"Cross-origin resource sharing problem while working with NodeJs, Express, and React on

Currently, I am working on a small project where I am using NodeJs and Express for the backend and React for the client side. In order to tackle CORS policy issues, I have implemented the "cors" npm package on the server side, but unfortunately, it doesn& ...

Updating the state after receiving API results asynchronously following a function call

I am attempting to update the state asynchronously when my fetchWeather function is executed from my WeatherProvider component, which calls an axios request to a weather API. The result of this request should be mapped to a forecast variable within the fet ...

Tips for storing form data in MongoDB

I'm currently working on a form and I need help extracting text from the form in order to save it into MongoDB. Here is an excerpt from my tweets.ejs file: <form method="post" action="/tweets"> <input type="text" id="txt" name="text"/> & ...