如何在 3d 中投影 2d 着色器 object

How can I project a 2d shader in a 3d object

标题让它看起来很简单,但我很难在我的 3d 模型上获得 this pie chart shader。为此,我使用了三个 js。到目前为止,这是我的代码:

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>

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();

vertex.glsl.js:

const vertexShader = /* glsl */`
void main()
{
    gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}
`
// uniform vec3 iResolution;
// uniform int SEGMENTCOUNT;
export { vertexShader };

fragment.glsl.js:

const fragmentShader = /* glsl */`
void main() {
    gl_FragColor = vec4(0, 1, 0, 1);
    gl_Position
}
`

export { fragmentShader };

这是我的 roulette.gbl model

预期的结果是拥有一个我选择颜色的着色器,所有部分都相等,颜色可以重复,着色器应该覆盖整个网格,而不是底部。 intended result

PS。我看到我的 object 在图像上看起来很平坦,我想只需要添加一些适当的光线,这是我的 object 几何图形,只是出于好奇:my mesh geometry

PSS。非常欢迎饼图着色器上的一些抗锯齿

你可以这样做,将 material 修改为 .onBeforeCompile():

body{
  overflow: hidden;
  margin: 0;
}
<script type="module">
import * as THREE from "https://cdn.skypack.dev/three@0.136.0";
import {
  OrbitControls
} from "https://cdn.skypack.dev/three@0.136.0/examples/jsm/controls/OrbitControls";

let scene = new THREE.Scene();
let camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 1, 2000);
camera.position.set(0, 1, 1).setLength(12);
let renderer = new THREE.WebGLRenderer({
  antialias: true
});
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);

window.addEventListener("resize", onWindowResize);

let controls = new OrbitControls(camera, renderer.domElement);

scene.add(new THREE.GridHelper());

let light = new THREE.DirectionalLight(0xffffff, 0.5);
light.position.setScalar(1);
scene.add(light, new THREE.AmbientLight(0xffffff, 0.5));

let path = new THREE.Path();
path.moveTo(0, -1);
path.lineTo(4, -1);
path.absarc(4, -0.5, 0.5, Math.PI * 1.5, 0);
path.absarc(4, 0.5, 0.5, 0, Math.PI * 0.5);
path.lineTo(0, -0.5);

let g = new THREE.LatheGeometry(path.getPoints(50), 72);
let m = new THREE.MeshLambertMaterial({
  color: 0x00ff7f,
  //wireframe: true,
  onBeforeCompile: shader => {
    shader.vertexShader = `
        varying vec3 vPos;
      ${shader.vertexShader}
    `.replace(
      `#include <begin_vertex>`,
      `#include <begin_vertex>
        vPos = position;
      `
    );
    //console.log(shader.vertexShader);
    shader.fragmentShader = `
        #define ss(a, b, c) smoothstep(a, b, c)
        varying vec3 vPos;
      ${shader.fragmentShader}
    `.replace(
      `vec4 diffuseColor = vec4( diffuse, opacity );`,
      `
      vec3 col = diffuse;
      int N = 37;
      float a = atan(vPos.x,-vPos.z)+PI;
      float r = PI2/float(N);
      float cId = floor(a/r);
      
      vec3 br = mod(cId, 2.) == 0. ? vec3(0) : vec3(1, 0, 0); // black / red
      br = cId == 0. ? vec3(0, 0.75, 0) : br; // green
      
      float d = length(vPos.xz);
      float fw = length(fwidth(vPos.xz));
      
      col = mix(col, br, ss(3. - fw, 3., d) - ss(4., 4. + fw, d));
      col = mix(diffuse, col, clamp(sign(vPos.y), 0., 1.));
      
      vec4 diffuseColor = vec4( col, opacity );
      `
    );
    //console.log(shader.fragmentShader);
  }
})
let o = new THREE.Mesh(g, m);
o.position.y = 0.5;
o.rotation.y = Math.PI;
scene.add(o);

renderer.setAnimationLoop(() => {
  renderer.render(scene, camera);
});

function onWindowResize() {

  camera.aspect = innerWidth / innerHeight;
  camera.updateProjectionMatrix();

  renderer.setSize(innerWidth, innerHeight);

}

</script>