How to make diamond looks real?

try throwing the above texture at it, let’s see what it looks like :sweat_smile:


The example in the repo I shared works differently than OP’s links, that’s why I didn’t mention it. Don’t use this code guys, it was just an experiment :sweat_smile: As @mjurczyk explained there are lots of assumptions that make the technic unsuable in real life use cases.

1 Like

i will totally use this :smile:

getting close: Diamond refraction - CodeSandbox this is from a post on twitter i’ve stumbled over and trying to abstract diamonds/main.js at 2dfb1ba5c938f213b8ecd0e2d7289cba1f299a72 · N8python/diamonds · GitHub into something more re-usable.

it’s missing the rgb color shift, does anyone have an idea how to implement that?


do three rays for r, g and b with slightly different ior

physically incorrect, but more performant: count the length the ray traveled, shift proportionally.


Something like this, I guess… I found this code in an old repo online



1 Like

updated the sandbox with the solution from n8programms:

could you guys check if that’s good or is your version faster? here’s the sandboxbox again

it looks pretty damn good :smile:


Yeah, the effect looks very good. I must spend a lot of time learning these. Thank you very much! :smile:

if anyone needs it, i published the raw shader: UNPKG - @react-three/drei (npm: import { MeshRefractionMaterial } from '@react-three/drei/materials/MeshRefractionMaterial'). it will not pull anything from react, it’s just the namespace.

to use it you need to give it a couple of defines without which it can’t work, and a bvh index, you can see how to add both here: drei/MeshRefractionMaterial.tsx at 66750d85d3c3ed5d1289d779acf9377eee159bb1 · pmndrs/drei · GitHub


Any luck making it look more white?

Not sure if this is relivant to the later provided resources but on android the diamond seems to be not rendered at all in the earlier sandbox…

Try adding glare to the diamond, check diamond project, it looks so real

Do we have the source code for the diamond project?

I also cannot render the diamond on the sandbox… any update on this?

any errors you can catch in the console?

Jus this:

THREE.WebGLProgram: Shader Error 0 - VALIDATE_STATUS false
Program Info Log: Could not pack varying viewDirection

there is a post from 2011 that says this means too many varyings. sounds like you will need to ask @drcmda to optimize his shaders :sweat_smile:

i think it’s fixed now, cody made it a few varyings less.

1 Like

@drcmda : I have been trying to incorporate the mesh refraction material in a react project, but we are not using react-three or react-fibre or drei. I just wanted to use the raw shader from unpkg in my typescript project to replace a material for diamonds on a mesh.
I tried to add it to the DOM with useEffect hook, but I am getting an error -

Refused to execute as script because "X-Content-Type-Options: nosniff" was given and its Content-Type is not a script MIME type.

Any idea how I can use this properly and where do I add the defines (I understood how I can pass the bvh)? The example you have mentioned is for react-three/react-fibre. I am using typescript.

this is about unpkg serving it, it’s not a drei thing. i would suggest you copy this material into your own project. then you still need the glue code drei/src/core/MeshRefractionMaterial.tsx at aa2dd0f99fcb33562eff69b57fcb51dbe1d65ff3 · pmndrs/drei · GitHub

first you set the material up, keep in mind that drei uses a shaderMaterial helper that creates auto setter/getters for uniforms. best copy drei/shaderMaterial into your project as well drei/src/core/shaderMaterial.tsx at aa2dd0f99fcb33562eff69b57fcb51dbe1d65ff3 · pmndrs/drei · GitHub.

const material = new MeshRefractionMaterial()
material.resolution = new THREE.Vector2(size.width, size.height)
material.aberrationStrength = aberrationStrength

the useMemo creates the defines, just copy the contents of it into your code and apply them:

    const temp = {}
    // Sampler2D and SamplerCube need different defines
    const isCubeMap = isCubeTexture(envMap)
    const w = (isCubeMap ? envMap.image[0]?.width : envMap.image.width) ?? 1024
    const cubeSize = w / 4
    const _lodMax = Math.floor(Math.log2(cubeSize))
    const _cubeSize = Math.pow(2, _lodMax)
    const width = 3 * Math.max(_cubeSize, 16 * 7)
    const height = 4 * _cubeSize
    if (isCubeMap) temp.ENVMAP_TYPE_CUBEM = ''
    temp.CUBEUV_TEXEL_WIDTH = `${1.0 / width}`
    temp.CUBEUV_TEXEL_HEIGHT = `${1.0 / height}`
    temp.CUBEUV_MAX_MIP = `${_lodMax}.0`
    // Add defines from chromatic aberration
    if (aberrationStrength > 0) temp.CHROMATIC_ABERRATIONS = ''
    if (fastChroma) temp.FAST_CHROMA = ''
    materal.defines = themp

the useLayoutEffect is about applying the geometry

      material.bvh = new MeshBVHUniformStruct()
        new MeshBVH(geometry.clone().toNonIndexed(), { lazyGeneration: false, strategy: SAH })

then the material needs a ticker, these are uniforms as well

function yourFrameLoop() {
    material.viewMatrixInverse = camera.matrixWorld
    material.projectionMatrixInverse = camera.projectionMatrixInverse

this is the reason we haven’t included it into drei-vanilla GitHub - pmndrs/drei-vanilla: 🍦 drei-inspired helpers for threejs it’s way too complex for a simple class and without the component paradigm there would be all this extra glue code the user would have to manage.