You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为@react-three/drei的MeshLine宽线应用顶点着色器?

解决方案:基于@react-three/drei 实现逐像素Y阈值变色宽线

核心思路是利用onBeforeCompile钩子在MeshLine的内置着色器中注入自定义逻辑,将世界空间坐标传递到片段着色器,实现逐像素的颜色判断,同时保留原有宽线的渲染能力。

实现代码

import { Line } from '@react-three/drei';
import { useRef } from 'react';

export default function ColoredWideLine() {
  const lineRef = useRef(null);

  return (
    <Line
      ref={lineRef}
      // 自定义线的顶点数据
      points={[[-1.5, -1, 0], [0, 1.2, 0], [1.5, -1, 0]]}
      lineWidth={0.12}
      // 基础颜色(会被片段着色器逻辑覆盖)
      color="#ff0000"
      onBeforeCompile={(shader) => {
        // 1. 在顶点着色器头部声明varying变量,用于传递世界坐标到片段着色器
        shader.vertexShader = `
          varying vec3 vWorldPosition;
          ${shader.vertexShader}
        `;

        // 2. 在顶点着色器中计算世界坐标,插入到原有位置变换逻辑之后
        // 匹配MeshLine内置顶点着色器中的位置投影代码段
        shader.vertexShader = shader.vertexShader.replace(
          '#include <project_vertex>',
          `#include <project_vertex>
          // 计算当前顶点的世界空间坐标
          vWorldPosition = (modelMatrix * vec4(position, 1.0)).xyz;`
        );

        // 3. 在片段着色器头部声明对应的varying变量
        shader.fragmentShader = `
          varying vec3 vWorldPosition;
          ${shader.fragmentShader}
        `;

        // 4. 替换原有颜色输出逻辑,添加Y阈值判断
        shader.fragmentShader = shader.fragmentShader.replace(
          'gl_FragColor = vec4( vColor, opacity );',
          `
          // 根据世界空间Y值切换颜色
          vec3 finalColor = vColor;
          if (vWorldPosition.y >= 0.5) {
            finalColor = vec3(0.0, 1.0, 0.0); // 绿色
          }
          gl_FragColor = vec4(finalColor, opacity);
          `
        );

        // 可选:添加可动态调整的阈值uniform
        shader.uniforms.yThreshold = { value: 0.5 };
        // 如果用uniform,上面的判断改成:if (vWorldPosition.y >= yThreshold)
      }}
    />
  );
}

关键细节说明

  • 不破坏原有宽线逻辑:通过onBeforeCompile扩展内置着色器,而非完全替换,保留MeshLine处理宽线的核心算法。
  • 逐像素判断:将世界坐标传递到片段着色器后,每个像素都会独立判断Y值,避免顶点着色方式导致的色块过渡问题。
  • 灵活扩展:可以将阈值设为uniform,后续通过lineRef.current.material.uniforms.yThreshold.value动态修改阈值,无需重新渲染组件。

可能的适配调整

如果MeshLine的内置顶点着色器没有#include <project_vertex>片段,可以直接匹配gl_Position赋值语句进行替换:

shader.vertexShader = shader.vertexShader.replace(
  'gl_Position = projectionMatrix * modelViewMatrix * vec4( transformed, 1.0 );',
  `gl_Position = projectionMatrix * modelViewMatrix * vec4( transformed, 1.0 );
  vWorldPosition = (modelMatrix * vec4(position, 1.0)).xyz;`
);

内容的提问来源于stack exchange,提问作者Paul M.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 12:01:17