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

Three.js实现z=f(x,y)函数绘图器的着色异常问题咨询

问题原因分析
  1. 着色逻辑适配的是Three.js已废弃的旧版Geometry类,你使用的v0.133版本中ParametricGeometry默认返回BufferGeometry,不存在faces、vertices属性,原着色函数循环完全不执行,颜色没有写入几何体。
  2. 原着色函数循环条件错误,即使使用旧版Geometry,循环条件应为i < geometry.faces.length,缺少.length属性导致循环不触发。
  3. OrbitControls导入不完整、轨道更新逻辑被注释,会导致鼠标控制功能失效。
  4. 多处语法疏漏:Scene、AxesHelper实例化缺少括号,ComputeZ函数中x、y变量未声明污染全局作用域。
修复方案

改用BufferGeometry兼容的顶点着色方案,直接生成颜色属性写入几何体,同时修复所有语法问题和功能缺陷:

<script type="module">
import * as THREE from "https://cdn.skypack.dev/three@0.133.1";
import { OrbitControls } from "https://cdn.skypack.dev/three@0.133.1/examples/jsm/controls/OrbitControls.js";

// 全局变量声明
let scene, camera, cameraControls, renderer, axisHelper;

function init() {
    scene = new THREE.Scene();

    camera = new THREE.PerspectiveCamera(25, window.innerWidth / window.innerHeight, 1, 1000);
    camera.position.set(-30, 50, -7);

    const canvas = document.querySelector('#canvasElem');

    renderer = new THREE.WebGLRenderer({
        canvas: canvas,
        antialias: true,
        transparent: true,
        alpha: true
    });
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.shadowMap.enabled = true;
    renderer.shadowMap.type = THREE.PCFSoftShadowMap;

    cameraControls = new OrbitControls(camera, renderer.domElement);
    cameraControls.enablePan = false;

    axisHelper = new THREE.AxesHelper(5);
    scene.add(axisHelper);

    window.addEventListener("resize", () => {
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix()
    });

    // 双曲抛物面参数
    const a = 1.0;
    const b = 1.0;

    // 计算z值生成顶点
    function ComputeZ(u, v, w) {
        const x = u * 2 - 1;
        const y = v * 2 - 1;
        w.set(x, y, (x * x) / (a * a) - (y * y) / (b * b));
    }

    // 生成xy平面网格
    function createPlaneGrid(size, steps) {
        const group = new THREE.Group();
        const material = new THREE.LineBasicMaterial({
            color: 0x000000,
            transparent: true,
            opacity: 0.25
        });

        // x轴方向网格线
        for (let i = 0; i <= steps; i += 1) {
            const f = (i / steps) - 0.5;
            const geometry = new THREE.BufferGeometry();
            const points = [
                new THREE.Vector3(f * size, -size * 0.5, 0),
                new THREE.Vector3(f * size, size * 0.5, 0)
            ]
            geometry.setFromPoints(points);
            group.add(new THREE.Line(geometry, material));
        }

        // y轴方向网格线
        for (let i = 0; i <= steps; i += 1) {
            const f = (i / steps) - 0.5;
            const geometry = new THREE.BufferGeometry();
            const points = [
                new THREE.Vector3(-size * 0.5, f * size, 0),
                new THREE.Vector3(size * 0.5, f * size, 0),
            ]
            geometry.setFromPoints(points);
            group.add(new THREE.Line(geometry, material));
        }
        return group;
    }

    // 生成参数几何体
    const ParamGeometry = new THREE.ParametricGeometry(ComputeZ, 20, 20);
    // 适配BufferGeometry的顶点着色逻辑
    const positions = ParamGeometry.attributes.position.array;
    const colors = new Float32Array(positions.length);
    for (let i = 0; i < positions.length; i += 3) {
        const x = positions[i];
        const y = positions[i + 1];
        const z = positions[i + 2];
        // 坐标映射到0-1的RGB值
        colors[i] = x * 0.5 + 0.5;
        colors[i + 1] = y * 0.5 + 0.5;
        colors[i + 2] = z * 0.5 + 0.5;
    }
    ParamGeometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));

    // 材质启用顶点颜色
    const ParaMaterial = new THREE.MeshBasicMaterial({
        side: THREE.DoubleSide,
        vertexColors: true
    });

    const ParaMesh = new THREE.Mesh(ParamGeometry, ParaMaterial);
    scene.add(ParaMesh);

    const plane = createPlaneGrid(4, 12);
    scene.add(plane);

    // 方向光
    const directionalLight = new THREE.DirectionalLight(0xffffff, 1.0);
    directionalLight.position.set(100, 100, 100);
    directionalLight.castShadow = true;
    directionalLight.shadow.camera.left = -100;
    directionalLight.shadow.camera.bottom = -100;
    directionalLight.shadow.camera.right = 100;
    directionalLight.shadow.camera.top = 100;
    directionalLight.shadow.camera.far = 1000;
    scene.add(directionalLight);
}

function animate() {
    requestAnimationFrame(animate);
    cameraControls.update();
    renderer.render(scene, camera);
}

init();
animate();
</script>
修复后效果
  • 顶点颜色正常显示,按xyz坐标映射为渐变RGB色彩
  • 鼠标旋转、缩放功能正常可用
  • 轴辅助器、平面网格正常显示作为坐标参考
  • 顶点生成范围为-1到1,步长0.1符合需求

内容的提问来源于stack exchange,提问作者RuleOfLaw

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 10:06:03