Three.js实现z=f(x,y)函数绘图器的着色异常问题咨询
问题原因分析
- 着色逻辑适配的是Three.js已废弃的旧版
Geometry类,你使用的v0.133版本中ParametricGeometry默认返回BufferGeometry,不存在faces、vertices属性,原着色函数循环完全不执行,颜色没有写入几何体。 - 原着色函数循环条件错误,即使使用旧版
Geometry,循环条件应为i < geometry.faces.length,缺少.length属性导致循环不触发。 OrbitControls导入不完整、轨道更新逻辑被注释,会导致鼠标控制功能失效。- 多处语法疏漏:
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
相关产品推荐
相关产品推荐

