``Creating apertures in a rectangular shape using three.js: A step-by-step guide

I've been attempting to create two holes in a simple rectangle using three.js, but I'm facing an issue where the holes aren't showing up correctly with a 3D effect. Below is my current approach:

const modelContainer = document.getElementById('containerModel');

// Setting up Scene
const scene = new THREE.Scene();
scene.background = new THREE.Color(0xEEEEEE);

// Initializing Camera
const camera = new THREE.PerspectiveCamera(
  50,
  modelContainer.clientWidth / modelContainer.clientHeight,
  1,
 1000);
camera.position.set(0, 150, 400);
scene.add(camera);

// Adding Light
const light = new THREE.PointLight(0xffffff, 0.8);
camera.add(light);

// Creating Group
const group = new THREE.Group();
scene.add(group);

// Drawing Rectangle
const rectShape = new THREE.Shape()
  .moveTo(0, 0)
  .lineTo(0, 120)
  .lineTo(200, 120)
  .lineTo(200, 0)
  .lineTo(0, 0);

// Defining Holes
const hole = new THREE.Path()
  .moveTo(144, 60)
  .absarc(134, 60, 10, 0, Math.PI * 2, true);
rectShape.holes.push(hole);
const hole2 = new THREE.Path()
  .moveTo(77, 60)
  .absarc(67, 60, 10, 0, Math.PI * 2, true);
rectShape.holes.push(hole2);

const extrudeSettings = {
  depth: 20,
  bevelEnabled: true,
  bevelSegments: 2,
  steps: 2,
  bevelSize: 1,
  bevelThickness: 1,
};
const geometry = new THREE.ExtrudeBufferGeometry(rectShape, extrudeSettings);
geometry.center();
geometry.rotateX(Math.PI * -0.5);
const material = new THREE.MeshPhongMaterial({
  color: 0x222222,
});
const mesh = new THREE.Mesh(geometry, material);
group.add(mesh);

// Setting Up Renderer
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(modelContainer.clientWidth, modelContainer.clientHeight);
new OrbitControls(camera, renderer.domElement);
modelContainer.appendChild(renderer.domElement);

function animate() {
  requestAnimationFrame(animate);
  renderer.render(scene, camera);
}
animate();

function onWindowResize() {
  camera.aspect = modelContainer.clientWidth / modelContainer.clientHeight;
  renderer.setSize(modelContainer.clientWidth, modelContainer.clientHeight);
  camera.updateProjectionMatrix();
}
window.addEventListener('resize', onWindowResize, false);

Here is the result that I achieved: https://jsfiddle.net/9y0a64nx/27/

Interestingly, when substituting the rectangle with a circle shape, the holes display correctly: https://jsfiddle.net/9y0a64nx/28/

I am seeking guidance on how to achieve the same 3D effect for the holes as seen with the circle shape.

Thank you for any assistance provided!

Answer №1

To achieve the desired outcome, make sure to reverse the order when defining your outer rectangular shape:

const rectShape = new THREE.Shape()
    .moveTo(0, 0)
    .lineTo(rectLength, 0)
    .lineTo(rectLength, rectWidth)
    .lineTo(0, rectWidth)
    .lineTo(0, 0);

Remember that holes should be defined in a reversed order (CW vs. CCW).

Check out the updated live example here: https://jsfiddle.net/ktjqe2L4/

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

AngularJS Datepicker with parentheses in the Controller.js

I recently started working with angularJS in Brackets and I am attempting to implement a datepicker from https://codepen.io/anon/pen/ZvVxqg However, when I paste the JS file into my controller.js in Brackets, an error occurs. Below are the code snippets ...

Tips for creating a Google Chart using temperature and humidity data sourced from an XML file

Below is the XML file I am working with: <data> <temp>21</temp> <humidity>17</humidity> <analog>670</analog> <analog>908</analog> <analog>628</analog> <analog>909</analog> <L ...

What is the best way to continuously click a JavaScript link until it disappears?

Many websites utilize single-page pagination to display more content with each click. It can be beneficial to view all the content on one page, such as for web crawling purposes. Much like automatically clicking a button using Greasemonkey, how can JavaScr ...

Executing pure JavaScript code in Grails using Groovy

this is a duplicate of Executing groovy statements in JavaScript sources in Grails with a slight variation, my intention is to only render the js-code without enclosing it in script tags picture someone loading a script from my server within their html l ...

Utilizing jQuery to place an element beside another and maintain its position

I need ElementA to be positioned next to ElementB as shown in this example. The key difference is that I want ElementA to move along with ElementB if the latter is relocated. Is there a way to keep a specific element fixed to another one? Re-calculating ...

Adding JSON data to a table with the keys in the first row is a simple process that can be achieved

Previously, I have created tables with XML formatted results and JSON data in the "key: data" format. To access the data, I would use syntax like results.heading1 and then map the data into a table by matching the key with the data. Now, a new client is o ...

Having trouble getting CSURF (CSRF middleware) to function properly with XSRF in AngularJS

Struggling to get the CSRF middleware working with Express and Angular? You're not alone. Despite various guides on the internet, the process remains unclear. Express 4.0 uses csurf as its CSRF middleware, while Angular requires setting X-XSRF-TOKEN. ...

Is it possible to incorporate JavaScript files into a TypeScript (ts, tsx) project that has already been built?

Recently, I was given a task to incorporate additional pages into the current project which has been developed using the following technologies: Laravel: 8.12 React: 17.0.2 NextJS: 10.0.9 Tailwind CSS: 2.0.4 React Query: 3.13.0 [ REST] TypeScript: 4.2.3 M ...

The issue encountered when trying to load Javascript through PHP

As a beginner, please be patient with me. I am attempting to dynamically load this JavaScript easy slider into a div on my index page using the following code ... switch($_GET['page']) { case '#YELLOW' : $page = ' <div id ...

I'm encountering an issue in my server.js file where I am unable to read the property 'collection' as it is undefined

I have encountered an error in my code: /home/ubuntu/workspace/server.js:43 db.collection('quotes').find().toArray(function(err, results) { ^ TypeError: Cannot read property 'collection' of undefined at Object.<anonymous> ( ...

When using IndexedDB with a Javascript To-Do list, the dates for all items appear to be the same after adding a new item to the list

I developed a To-Do List using Javascript, HTML, and IndexedDB to store the items in the database so that they won't be deleted when the browser is refreshed. I also want to include the date for each item, however, whenever I add an item, the date end ...

Ways to obtain every image placed onto an element

Using the img tag within div.image-block sets a background. Images can be added to .block3 through drag and drop. Is there a way to create a container that includes all elements from .image-block? <style> .image-block { position: relat ...

Node.js and Express constantly face the challenge of Mongoose connecting and disconnecting abruptly

I have been running an Express (Node.js) app connected to MongoDB using Mongoose for a while now. Everything was working smoothly until recently, when it started acting up. It appears that the server is establishing a connection with MongoDB only to disco ...

Having an issue where I receive the error message "this.cancelOrderFunction is not a function" when trying to execute a method within a child component in Vue.js

I'm facing an issue while trying to execute a method that changes the text content of the currentStatus variable when the Confirm Cancel button is clicked. The button is located in the child component within a dialog box, while the method is supposed ...

When attempting to use $.ajax to send JSON, it instead sends a query string

I'm having an issue where I'm using ajax to send JSON data with the following script: var sendData = {"test":"opa"}; console.log(sendData); $.ajax({ contentType: "application/json", method: "POST", url: "/test", dataType: "json", ...

Using third-party libraries like jQuery, CSS, and JavaScript in your React project by directly importing them into the index.html file can be a more efficient approach compared

When working with React, is it advisable to import external JavaScript, jQuery, and CSS files into the index.html file in the public folder? Are there any potential performance implications associated with this practice? I have utilized some jQuery functi ...

Storing specific items in an array for easy access on the following page

I have some code that extracts specific keys and values from a row and then sends them to the next page. let HistoryData = []; for (const [key, value] of Object.entries(this.Items)) { HistoryData.push(value) } this.$router.push( ...

How can I utilize React hook to choose multiple items?

I am currently working on developing a next js application. As part of this project, I have been tasked with creating a custom dropdown select menu using react hooks, specifically useState. The code I have written for this is as follows. Data- export defa ...

Which event occurs first for a4j:jsFunction, reRender or oncomplete?

After running a jsFunction, I want the javascript to execute once the re-rendering is completed. I assume that the "oncomplete" javascript function is triggered after the re-rendering process, but I'm not entirely certain. Any insights on this? Appre ...

Is it not possible to use array splice with a string that is in array format (i.e., split string

Why doesn't array splice work with a string that has been formatted into an array using the split() method? function _formatText(text) { var textList = text.replace(/\s+/g, ",").split(","); return textList.splice(1, 0, "<br />").join ...