如何在Three.js中修改自定义Shader的Uniform变量值?
Custom Shader for Vertex Value Contour Mapping in Three.js
Hey there! I've built a custom shader that visualizes vertex-assigned values using contour mapping—great for showcasing elevation data, heatmaps, or any per-vertex attribute you want to highlight with clear contour lines. Here's a complete, functional example (I filled in the truncated parts of your original code to make it work end-to-end):
<html lang="en"> <head> <title>Face Contour Example</title> <style> body { margin: 0; } canvas { display: block; } </style> </head> <body> <script src="three.min.js"></script> <script src="OrbitControls.js"></script> <script src="SubdivisionModifier.js"></script> <script> // Basic scene setup const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000); const renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); // Add orbit controls for easy interaction const controls = new THREE.OrbitControls(camera, renderer.domElement); camera.position.z = 5; // Create a sample geometry (sphere works well for testing contours) const geometry = new THREE.SphereGeometry(2, 32, 32); // Assign random per-vertex values (replace this with your actual dataset) geometry.setAttribute('customValue', new THREE.Float32BufferAttribute( geometry.attributes.position.array.map(() => Math.random()), 1 )); // Custom Shader Material with contour logic const shaderMaterial = new THREE.ShaderMaterial({ vertexShader: ` attribute float customValue; varying float vCustomValue; void main() { vCustomValue = customValue; gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); } `, fragmentShader: ` varying float vCustomValue; uniform float contourStep; void main() { // Calculate contour bands and detect line positions float band = floor(vCustomValue / contourStep); float isContour = step(0.95, fract(vCustomValue / contourStep)); // Create a color gradient + dark contour lines vec3 baseColor = mix(vec3(0.2, 0.6, 1.0), vec3(1.0, 0.8, 0.2), vCustomValue); vec3 finalColor = mix(baseColor, vec3(0.0), isContour); gl_FragColor = vec4(finalColor, 1.0); } `, uniforms: { contourStep: { value: 0.1 } // Adjust this to control how dense contours are } }); // Apply subdivision to make contours smoother on low-poly geometry const subdivider = new THREE.SubdivisionModifier(2); subdivider.modify(geometry); // Create mesh and add to scene const mesh = new THREE.Mesh(geometry, shaderMaterial); scene.add(mesh); // Animation loop function animate() { requestAnimationFrame(animate); controls.update(); renderer.render(scene, camera); } animate(); // Handle window resize window.addEventListener('resize', () => { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); }); </script> </body> </html>
Core Features to Note:
- Per-Vertex Data Integration: The shader uses a custom
customValueattribute—swap out the random values with your own dataset (like elevation, temperature, or simulation data). - Adjustable Contour Density: Tweak the
contourStepuniform to make contour lines more or less frequent. - Smooth Contours: The
SubdivisionModifierrefines geometry to avoid jagged lines on low-poly meshes. - Color Gradient: The base color transitions based on vertex values, making it easy to see value ranges at a glance.
Quick Breakdown of the Shader Logic:
- Vertex Shader: Simply passes the per-vertex
customValueto the fragment shader as a varying variable. - Fragment Shader:
- Splits vertex values into bands using
contourStep. - Uses
fract()andstep()to detect fragments that fall on contour line edges. - Mixes a gradient base color with black to draw sharp contour lines.
- Splits vertex values into bands using
Feel free to tweak color palettes, contour line thickness, or step size to fit your specific use case!
内容的提问来源于stack exchange,提问作者Three Percent Games




