Geometry clipping created by combining faces, cap face with stencil not properly aligned

My current project involves the use of geometry where each face is represented as its own mesh. I am in need of clipping the geometry to remove a specific portion of it, with the intention of having a stenciled cap face cover the clipped edges. After reviewing and experimenting with the Three.js clipping stencil example, I have grasped the concept of utilizing a stencil to cap trimmed solid geometry. However, when applying this technique to collections of face geometries, I encounter difficulties. Below is some code that I have been working on, based on the provided example:

body { margin: 0; }
canvas { display: block; }
<script type="module">
import * as THREE from 'https://unpkg.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="c6b2aeb4a3a386f6e8f7f4f6e8f7">[email protected]</a>/build/three.module.js';
import { OrbitControls } from 'https://unpkg.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="b3c7dbc1d6d6f3839d8281839d82">[email protected]</a>/examples/jsm/controls/OrbitControls.js';
import { BufferGeometryUtils } from 'https://unpkg.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="ef9b879d8a8aafdfc1dedddfc1de">[email protected]</a>/examples/jsm/utils/BufferGeometryUtils.js';

var camera, scene, renderer;
var planes, planeObjects;

init();
animate();

function createPlaneStencilGroup( geometry, plane, renderOrder )
{
   var group = new THREE.Group();
   var baseMat = new THREE.MeshBasicMaterial();
   baseMat.depthWrite = false;
   baseMat.depthTest = false;
   baseMat.colorWrite = false;
   baseMat.stencilWrite = true;
   baseMat.stencilFunc = THREE.AlwaysStencilFunc;

   // back faces
   var mat0 = baseMat.clone();
   mat0.side = THREE.BackSide;
   mat0.clippingPlanes = [ plane ];
   mat0.stencilFail = THREE.IncrementWrapStencilOp;
   mat0.stencilZFail = THREE.IncrementWrapStencilOp;
   mat0.stencilZPass = THREE.IncrementWrapStencilOp;

   var mesh0 = new THREE.Mesh( geometry, mat0 );
   mesh0.renderOrder = renderOrder;
   group.add( mesh0 );

   // front faces
   var mat1 = baseMat.clone();
   mat1.side = THREE.FrontSide;
   mat1.clippingPlanes = [ plane ];
   mat1.stencilFail = THREE.DecrementWrapStencilOp;
   mat1.stencilZFail = THREE.DecrementWrapStencilOp;
   mat1.stencilZPass = THREE.DecrementWrapStencilOp;

   var mesh1 = new THREE.Mesh( geometry, mat1 );
   mesh1.renderOrder = renderOrder;

   group.add( mesh1 );

   return group;
}

function init()
{
   scene = new THREE.Scene();

   camera = new THREE.PerspectiveCamera( 36, window.innerWidth / window.innerHeight, 1, 100 );
   camera.position.set( 2, 2, 2 );

   initLights();

   planes = [
      new THREE.Plane( new THREE.Vector3( 0, - 1, 0 ), 0.42 ),
      new THREE.Plane( new THREE.Vector3( 0, 0, - 1 ), 0.25 )
   ];
   
   var material = new THREE.MeshStandardMaterial( {
      color: 0x00ff00,
      metalness: 0.1,
      roughness: 0.75,
      side: THREE.DoubleSide,
      clippingPlanes: planes,
      clipShadows: true,
      shadowSide: THREE.DoubleSide,
   } );
   
   // Simple sphere geometry. Something I know works, for comparison.
   var sphereGeom = new THREE.SphereBufferGeometry( 0.5, 32, 32 );
   sphereGeom.translate( -1.1, 0, 0 );
   
   // Make a cube out of 6 planes and merge them together
   var planeGeoms ......
.......

There are currently two clipping planes in effect, a cube composed of six individual PlaneGeometries, and a solid sphere included for comparison purposes. The stencil for the cube was created using a merged BufferGeometry object formed by combining the individual planes. While the stencil for the cube appears correct in terms of shape and size, only one cap face is rendered and not aligned with either of the clipping planes. Are there additional steps required in manipulating the stencil or the clipping plane beyond what the existing example provides to make it function appropriately on this type of geometry?

Answer №1

It was discovered that the PlaneBufferGeometries being merged for the stencil did not align with the positions of the plane meshes using those geometries. This discrepancy caused the cap face to be drawn incorrectly. The oversight was failing to account for the fact that a transform applied to a Mesh does not carry over to the geometry used elsewhere. By applying the transform matrices from the plane meshes to the PlaneBufferGeometries slated for merging, the issue was resolved.

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

Mongoose: strange outcomes observed when trying to delete the final element from an array

Update: I made a change in my approach by filtering the array directly and saving it instead of using updateOne and $pull. Surprisingly, this fixed the issue of html elements getting removed. However, the same problem persists when deleting the last item i ...

Selecting options using AngularJS to parse through a list

I am faced with a challenge involving a collection of strings representing years. Here is an example: $scope.years = ["2001", "2002", "2003", ...]; My goal is to display these values in a select tag within a web page. However, whenever I attempt this usi ...

How the React Component Class Executes OnChange Event in a Closure

When working on my React code, I found myself creating a closure by calling "onChange." class CityInput extends React.Component { constructor( props ){ super( props ); this.state = { city : "", country : "" ...

The latest update of MS CRM 2013 now includes a version number for WebResources that are of script

I came across an unusual issue in MS CRM 2013 that seems to be intentional, and I need some assistance in finding a workaround for it. The problem is that calling the getScript jQuery method from a WebResource is not possible. In CRM, a version string is ...

What is the best method for generating a large number of Express.js routes quickly and efficiently?

Is there a way to efficiently generate multiple routes in Express? I am looking to create routes in the format localhost:3000/${insert address here} Should I use a for loop or is there a built-in feature in Express that can help with this? For instance, ...

Can you recommend any effective JavaScript and AJAX interface designs for websites?

I admire how websites like FogBugz and Facebook provide dynamic user interfaces by loading content asynchronously. Are there specific methods and techniques for implementing this on other sites? I'm interested in a solution that generates a unique ha ...

Enhancing planetary textures with high resolution using Three.js technique

Creating realistic textures for planets has proven to be quite challenging. Despite using a 4096k image wrapped around a high poly sphere, there are performance issues due to the large file size and the texture appearing pixelated at close range. One solu ...

Remove a specific item from a MongoDB Collection using its ID

I have a MongoDB collection named "Members" which stores data for each member including first name, last name, and an autogenerated Object ID. I am able to retrieve the data using ExpressJS and display it with VueJS. While my get and post methods are worki ...

What are the best practices for incorporating React state into a dynamic filter component?

I am working on a filter component that will help me display specific data to the DOM based on user-selected filters. However, I am facing a dilemma regarding how to maintain state without resetting the filter input and how to render the filtered data with ...

How can the reference to a promise be used in Node.js UnhandledRejection event parameters?

When an error occurs, we have options for handling it such as recording it in logs, displaying it on the page or console, and more. But what about the promise reference passed to the handler as the second parameter? process.on('unhandledRejection&apos ...

Tips for rendering objects in webgl without blending when transparency is enabled

My goal is to display two objects using two separate gl.drawArrays calls. I want any transparent parts of the objects to not be visible. Additionally, I want one object to appear on top of the other so that the first drawn object is hidden where it overlap ...

Display toolbar title on small screens in separate lines

Recently, I encountered an issue while using v-toolbar in my vue app. Despite my efforts, I couldn't find a way to split the title into multiple lines on small screens. Currently, it displays as "Secti...." on smaller devices. Can anyone assist me wit ...

Steps to invoke the function that showcases the dynamic content of the initial tab using Angular Bootstrap upon the loading of the form or window

Utilizing an angular bootstrap tab, I am aware that the ng-click event on a tab will trigger any function upon clicking the tab. I am aiming to have some dynamic content load on the first tab when the form is loaded. The HTML code snippet is as follows: ...

Converting a curl command to a $.ajax() call in JavaScript: A step-by-step guide

I'm attempting to retrieve data from the Zomato API by using jquery ajax, however, they have provided a curl command instead. curl -X GET --header "Accept: application/json" --header "user-key: key" "https://developers.zomato.com/api/v2.1/cities" Is ...

Discover updates within a JQuery Ajax call

I am sorry if this question sounds simple, but I would like to know how to set up a function that triggers when the Ajax data changes from the previous request. window.setInterval(function(){ $.get("feed", function(data){ if (data.changed ...

Ways to guarantee that a task is completed only after another task has finished

Attempting to avoid duplication as I find myself in the midst of a significant issue. Currently working on a JavaScript codebase consisting of thousands of lines. The specific problem at hand involves: methodA being invoked from within its own class. met ...

What is the best method for using XMLhttpRequest in PHP to append options to a select element?

I'm looking to dynamically fetch values from a MySQL database using PHP and then add them as choices within a select element. Here is my HTML code: <label for='listDivision'>Division</label><select id='listDivision&apos ...

Apollo Server Studio is failing to detect the schema configured in Apollo setup

Here is the stack I'm working with: Apollo Server, graphql, prisma, nextjs I've set up a resolver.ts and schema.ts for my graphql configuration under /graphql resolver.ts export const resolvers = { Query: { books: () => books, } ...

"Commander.js does not process query strings when used in conjunction with node

I developed a CLI tool using commander.js which has been released on npm. This command-line interface utilizes node-fetch to fetch data from an external API. However, I have received reports from some users stating that the query string in the fetch URL is ...

What is the best way to separate an array of numbers into individual digits using JavaScript?

I am looking to transform an array const myArr = [ 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106 ] into a new array with digits split like this: const splited = [ 9, 4, 9, 5, 9, 6, 9, 7, 9, 8, 9, 9, 1, 0, 0, 1, 0, 1, 1, 0, 2, 1, 0, 3, 1, 0, ...