Creating an Icosahedron with realistic behavior

I am currently working on creating a d20, which is a dice with 20 sides or an icosahedron. Here is how I have been approaching it:

const IcosahedronDice = (props) => {
  const [ref] = useBox(() => ({ mass: 1, position: [0, 10, 0] }));
  return (
    <mesh ref={ref} position={[0, 2, 0]} castShadow receiveShadow>
      <icosahedronBufferGeometry attach="geometry" args={[1, 0]}/>
      <meshStandardMaterial attach="material" color="#802d2d" />
    </mesh>
  )
}

The problem I'm facing is that while using "useBox", the dice collides like a box and rotates accordingly, even though its appearance is still that of an icosahedron. When attempting to use "useConvexPolyhedron" instead (which should be more suitable for an icosahedron), the object passes through my plane without any collision.

Plane:

const Plane = () => {
  const [ref] = usePlane(() => ({ rotation: [-Math.PI / 2, 0, 0] }));
  return (
    <mesh ref={ref} position={[0, 0, 0]} rotation={[-Math.PI / 2, 0, 0]} receiveShadow>
      <planeBufferGeometry attach="geometry" args={[100, 100]} />
      <meshStandardMaterial attach="material" color="#49687a" />
    </mesh>
  )
}

I have tried searching for a solution in the documentation, but so far, I have not found anything helpful. It's unclear whether I'm missing something or if the documentation itself is too complex.

Edit: The complete code:

import './App.css';
import { Canvas } from '@react-three/fiber';
import { OrbitControls, Stars, Icosahedron } from '@react-three/drei';
import * as THREE from 'three'
import { Physics, useBox, usePlane, useConvexPolyhedron } from '@react-three/cannon';

const IcosahedronDice = (props) => {
  const icosahedron = new THREE.IcosahedronGeometry(4)
  
  const [ref] = useBox(() => ({ mass: 1, position: [0, 10, 0] })); // THIS should be useConvexPolyhedron
  return (
    <mesh ref={ref} position={[0, 2, 0]} castShadow receiveShadow>
      <icosahedronBufferGeometry attach="geometry" args={[1, 0]}/>
      <meshStandardMaterial attach="material" color="#802d2d" />
    </mesh>
  )
}

const Plane = () => {
  const [ref] = usePlane(() => ({ rotation: [-Math.PI / 2, 0, 0] }));
  return (
    <mesh ref={ref} position={[0, 0, 0]} rotation={[-Math.PI / 2, 0, 0]} receiveShadow>
      <planeBufferGeometry attach="geometry" args={[100, 100]} />
      <meshStandardMaterial attach="material" color="#49687a" />
    </mesh>
  )
}
const DiceCanvas = () => {
  return (
    <Canvas>
      <Stars />
      <OrbitControls />
      <ambientLight intensity={0.5} />
      <spotLight
        position={[10, 10, 10]}
        intensity={0.5}
        penumbra={1}
        castShadow
      />
      <Physics>
      <IcosahedronDice position={[0, 0, 4]} rotation={[0, 1, 0]}/>
        <Plane />
      </Physics>
    </Canvas>
  );
}

export default DiceCanvas;

Answer №1

While working on my project, I faced some challenges in obtaining a Rhombicubeoctahedron (26th sided die) to work with. My approach involves importing a GLTF for the shape, but I believe you can adapt it to suit your needs as well.

const D26 = (props) => {
  // Importing the shape here.
  const { nodes, materials } = useGLTF('/beveled_die.glb'); 
  // Calculating geometry for the `Cube` object (which is actually a 26 sided polyhedron).
  const geo = useMemo(() => toConvexProps(nodes.Cube.geometry), [nodes]); 
  // Using the `useConvexPolyhedron` hook and passing in the calculated geometry.
  const [ref, api] = useConvexPolyhedron(() => ({ mass: 1, ...props, args: geo }));

I pass the memoized geometry object to the arguments of ConvexPolyhedron. The utility function toConvexProps performs the necessary conversions:

const toConvexProps = (bufferGeometry) => {
  const geo = new Geometry().fromBufferGeometry(bufferGeometry);
  geo.mergeVertices();
  return [geo.vertices.map((v) => [v.x, v.y, v.z]), geo.faces.map((f) => [f.a, f.b, f.c]), []]; 
};

Here's the jsx for D26:

<group
  ref={ref} 
  onClick={(e) => {
  ...
  {...props}
  dispose={null}
>
  <mesh
    castShadow
    material-color="#1e293b"
    receiveShadow
    geometry={nodes.Cube.geometry}
    material={materials.Material}
  />
  ...
</group>

In addition, here's the jsx for my Canvas:

<Canvas gl={{ alpha: false }} camera={{ position: [0, -12, 16], zoom: 3 }}>
  <hemisphereLight intensity={0.35} />
  <spotLight position={[30, 0, 30]} angle={1} penumbra={1} intensity={1} castShadow />
  <Suspense fallback={null}>
    <Physics gravity={[0, 0, -30]}>
      <Plane color={'#334155'} />
      <Rhombicuboctahedron position={[4, -4, 0]} />
    </Physics>
  </Suspense>
</Canvas>

The Plane components mentioned align with what I'm using, so that should be suitable for your scenario too.

Apologies for the lengthy response, but I hope this information helps you in resolving your concerns!

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

Setting Vuetify component props dynamically depending on certain conditions

I've implemented a navbar component in my web app using the v-app-bar Vuetify component. However, I'm facing an issue where I need to dynamically set the props of the v-app-bar based on the current page the user is viewing. <v-app-bar absolu ...

Setting up Node.js for production on Nginx: A comprehensive guide

I am working on developing a chat system using angularjs and nodejs. To enable message sending and receiving, I have implemented socket.io. Initially, I set up a node.js server using localhost cmd. Everything is functioning properly, but now I need to dep ...

Is it possible to determine the current scroll position using <a name=#page> in JavaScript?

I am currently in the process of creating a website to showcase a comic, with each page being accessed by scrolling using < a name=#page(number) > in HTML. For example, the button to navigate to the next page would look like this: <a href="#page ...

Utilizing Vue.js and Webpack to Handle Requests for Multiple Incorrect Resource Links

After utilizing Vue.js single file components to construct a website and appreciating the modular approach, I've encountered an issue. The browser appears to be requesting multiple versions of resources instead of just one URL for each. HeaderBar.vue ...

Can the value of a key automatically default to the parent's value if it is not found in the child?

When looking at the JSON example provided, is there a method to automatically switch back to the parent object key if the child object does not contain the key? // Example of i18n JSON "parent": { "foo": "foo", "bar": "bar", "child" ...

What issue can be identified in this sample of an https.request?

Trying out this specific example always leads to no return whatsoever. const https = require('https') const options = { hostname: 'encrypted.google.com', port: 443, path: '/', method: 'GET', // key: f ...

Tips for assigning an AngularJS value to jQuery

Displaying a value in a view using {{ myvalue }}. Assigning the value from the controller as $scope.myvalue = "123"; Attempting to send this value myvalue to an ajax call. Need to assign angularjs value to jquery value. How can I accomplish assigning t ...

The script functions smoothly on XAMPP, however, it encounters issues when deployed on

I've encountered an issue with a script that is designed to display posts and images from a user. While it works perfectly fine on Xampp, I'm facing an issue on the host server where only the posts are visible but not the images that the user has ...

what is the best way to ensure the execution of requests within async.each in nodejs?

I am facing an issue with my code that uses async.each to iterate through an array and execute a function called "check" for each element. The check function contains a request, but when I run the code, I find that Node.js is not executing the check functi ...

Display all items that contain a specified string using JavaScript

I'm in need of some assistance with a problem that I've been struggling with. I have several JavaScript objects containing different data pieces as shown below:- Object {id: 1, shopcounty: "cornwall", shopaddress: "the cycle centre,<br />1 ...

Updating Variables Declared in Parent Component from a Child Component in React using NextJS - A Comprehensive Guide

After reviewing the tutorial on React: Reverse Data Flow to update the variables foodObj, input, and buttonClicked declared in the Parent Component file Main.js, using the child component <SearchAndSuggestion>, I encountered an issue. Here is a snipp ...

Adjusting the width of innerHtml within a React router link to match the parent element's width

My current challenge involves a table where a cell is represented as a link. Within this setup, I am incorporating html content into the text of the link: <TableCell align="left" classes={{root: classes.cellPadding}}> <Link className={classes.l ...

Experiencing browser crashes following the incorporation of asynchronous functions into a JavaScript file. Seeking solutions to resolve this

In my recent project, I developed a basic online store application using vanilla javascript and ES6 classes. The shop items are stored in a JSON file which I used to populate the user interface. To implement functions like "addToCart", "quantityChange", a ...

Lagging speeds in client-side template rendering using Rivets.js

I have a function that renders an array of around 1000 objects, but the html bindings are causing significant performance issues. It currently takes about 5 seconds to complete rivets.bind(). Does anyone have any recommendations for improving performance? ...

Is there a way to retrieve the ID of an input field dynamically using jQuery when a button is clicked, and then store it in

I am relatively new to JavaScript and jQuery, so I could use some help or suggestions on how to tackle this task. My task involves retrieving the dynamic IDs of input fields upon button click. I have a total of 100 dynamic input fields. <input id="Pro ...

What is the best way to switch back and forth from allowing to prohibiting a form submission?

Let me break it down for you: In the code snippet below, the element with an ID of #new-org-btn is actually an input that triggers a form submission when clicked. However, I only want it to submit the form if certain conditions are met within the click fun ...

Mastering TypeScript in Router Configuration

I am currently working with a standard router setup. type Routes = '/' | '/achievements' | ... ; This helps in identifying the routers present in the project. However, I am faced with a new challenge of creating an array that includes ...

Challenges encountered when attempting to send an array in res.json with the MERN stack

I am facing a challenge while trying to make two separate model calls using the MERN stack. The issue arises when I try to send an array in res.json; extracting the data seems to be problematic. On examining the console log: {data: "[]", status: ...

Tips for converting this ajax code to long polling

I am currently using this ajax code and I was wondering if anyone knows how to change it to long polling. Here is the code I am using: var chat = {} chat.fetchMessages = function () { $.ajax({ url: 'ajax/ajax/chat.php', type: 'PO ...

Google Maps JavaScript API failing to load due to a 403 error after the tab has been open for an extended period

Our website utilizes Angular and includes tabs with Google Maps that load lazily when needed. Everything works fine when the page is first opened, but after spending some time on a tab without a map, switching to a new tab with a map results in the map not ...