Help me to port a shadertoy shader to three js

the shader I want to port is this one: Shader - Shadertoy BETA

and it should look like something like this in my object:


I also should be able to choose the colors, the number of colors and the numbers of segments just like in the shadertoy shader. Here is my object if it may be useful:
https://github.com/Guto-tw14/pie_shader/raw/main/roulette.glb

Thanks in advance! :slight_smile:

PS. some antialiasing on the shader would be very welcome
PSS. here is my code till now
main.js:

import * as THREE from 'https://cdn.skypack.dev/three'
import { OrbitControls } from 'https://cdn.skypack.dev/three-stdlib/controls/OrbitControls'
import { GLTFLoader } from 'https://cdn.skypack.dev/three-stdlib/loaders/GLTFLoader'
import { vertexShader } from '../shaders/vertex.glsl.js'
import { fragmentShader } from '../shaders/fragment.glsl.js'

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const loader = new GLTFLoader();
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setClearColor(0x002653, 0.5)
renderer.setSize(window.innerWidth, window.innerHeight);

document.body.appendChild(renderer.domElement);
renderer.setPixelRatio(window.devicePixelRatio);

const r_material = new THREE.ShaderMaterial({ //Roulette material
    uniforms: {
        iTime: { value: 1.0 },
        resolution: { value: new THREE.Vector2 }
    },
    vertexShader,
    fragmentShader
})
loader.load(
    '../roulette.glb',
    function (gltf) {
        gltf.scene.traverse((o) => {
            if (o.isMesh) o.material = r_material;
        });
        scene.add(gltf.scene);

    },
    function () { },
    function (err) {
        console.log('error: ' + err);
    }

)
camera.position.z = 5;

const controls = new OrbitControls(camera, renderer.domElement);
controls.enableZoom = true;
controls.enableDamping = true;

function animate() {
    requestAnimationFrame(animate);

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

animate();

index.html:

<!DOCTYPE html>
<html>

<head>
    <meta charset='utf-8'>
    <meta http-equiv='X-UA-Compatible' content='IE=edge'>
    <title>Site Prof Matheus</title>
    <meta name='viewport' content='width=device-width, initial-scale=1'>
    <link rel='stylesheet' type='text/css' media='screen' href='./styles/main.css'>
    <script type='module' src='./src/main.js'></script>

</head>

<body>

</body>

</html>

my vertex and fragment shader are just the docs example

This is a fairly simple example. See Shader - Shadertoy BETA .

Try it according to the templates from the collection.

Shader 1 - ShaderExamples_C … _G , takeovers from Shadertoy

Pay attention to the notes: Little Shader Book

i got this:


here is my shader:

vertex.glsl.js:

const vertexShader = /* glsl */`
varying vec2 vUv;
void main() {
    vUv = uv;
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`
export { vertexShader };

fragment.glsl.js:

const fragmentShader = /* glsl */`
varying vec2 vUv;

#define SEGMENTCOUNT 8
#define PI 3.14159265359

vec3 hsv2rgb(vec3 c)
{
    vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
    vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
    return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}

vec4 colors[8] = vec4[](
    vec4(1.0, 0.0, 0.0, 1.0), 
    vec4(0.0, 1.0, 0.0, 1.0),
    vec4(0.0, 0.0, 1.0, 1.0), 
    vec4(1.0, 1.0, 0.0, 1.0), 
    vec4(0.0, 1.0, 1.0, 1.0), 
    vec4(1.0, 0.0, 1.0, 1.0), 
    vec4(1.0, 1.0, 1.0, 1.0), 
    vec4(1.0, 0.5, 0.5, 1.0)
);

void main()
{
    vec2 nodePosition = vUv / 2.0;
    
    vec2 fragPos = vUv.xy - nodePosition;
    vec2 normalFragPos = normalize(vUv.xy - nodePosition);
    
    float angleSegment = 2.0 * PI;
    angleSegment /= float(SEGMENTCOUNT);
    
    float angle = atan(normalFragPos.y, normalFragPos.x) + PI;
    
    int segmentId = int(angle / angleSegment);
    
    float hueShift = (float(segmentId) + (mod(float(segmentId),2.0) * 0.5 * float(segmentId))) / float(SEGMENTCOUNT);
    
    //vec4 segmentColor = colors[segmentId];
    vec4 segmentColor = vec4(hsv2rgb(vec3(hueShift, 1.0, 1.0)),1.0);
    
    float circle = step(length(fragPos), 10.0);
    gl_FragColor = circle * segmentColor;
}
`

export { fragmentShader };

I tried using the links you send me as reference but it didnt work at all, I am really bad in glsl at the moment, apologize for my inconvenience. I set the segment count to 8 but there are just 2 colors on each half of the mesh. and the bevels are all one color, not corresponding to the top of the mesh. please help me to achieve this result


:pray: :slight_smile:

EDIT: it doesnt need to be this shader toy shader, any shader that split my mesh in X equal parts using Y different colors looking like a pie chart/roullete/pizza and also paint the bevels, like the image above is perfect. X being a number i can change in the js code throughout the runtime. Y will be static.

@Augusto What’s wrong with this approach, provided some time ago?

It’s based on The Book of Shaders: Shapes in the part about triangle.

1 Like

actually there is nothing wrong, I just couldnt understand it. Thank you so much for your help! :grinning: :grin:

As something related, I wrote this example, kind of a pie-chart. Not dynamic, as shader builds with hardcoded values from an array:

1 Like