如何防止 THREE.js 着色器中的顶点颜色插值?
How to prevent interpolation of vertex colors in THREE.js shader?
我正在尝试编写一个在网格上绘制等高线图的着色器。
这里是 contour plot 的例子。
我的第一个目标是用不同的颜色想象一个三角形的脸。
您可以在 here 中找到我正在使用的代码。
<html lang="en">
<head>
<title>Face Contour Example</title>
</head>
<body>
<script src="http://threejs.org/build/three.min.js"></script>
<script src="http://threejs.org/examples/js/controls/OrbitControls.js"></script>
<script id="vertexShader" type="x-shader/x-vertex">
varying vec3 vColor;
void main(){
vColor = color;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
varying vec3 vColor;
void main(){
gl_FragColor = vec4( vColor.rgb, 1.0 );
}
</script>
<script type="text/javascript">
var camera, scene, renderer, mesh, material, controls;
init();
animate();
function init() {
// Renderer.
renderer = new THREE.WebGLRenderer();
//renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
// Add renderer to page
document.body.appendChild(renderer.domElement);
// Create camera.
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.z = -400;
// Create scene.
scene = new THREE.Scene();
var colors = {
"color1" : {
type : "c",
value : new THREE.Color(0xff0000) //r
},
"color2" : {
type : "c",
value : new THREE.Color(0x00ff00) //b
},
"color3" : {
type : "c",
value : new THREE.Color(0x0000ff) //g
},
};
var fShader = document.getElementById('fragmentShader').text;
var vShader = document.getElementById('vertexShader').text;
// Create material
var material = new THREE.ShaderMaterial({
vertexShader: vShader,
fragmentShader: fShader,
vertexColors: THREE.VertexColors,
});
// var material = new THREE.MeshBasicMaterial( { vertexColors: THREE.VertexColors } );
// Create cube and add to scene.
var geometry = new THREE.Geometry();
geometry.vertices=[
new THREE.Vector3(100,0,0),
new THREE.Vector3(-100,0,0),
new THREE.Vector3(50,100,0)
]
var face=new THREE.Face3();
face.a=0;
face.b=1;
face.c=2;
face.vertexColors[ 0 ] = colors["color1"].value;
face.vertexColors[ 1 ] = colors["color2"].value;
face.vertexColors[ 2 ] = colors["color3"].value;
geometry.faces=[face]
mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
function addWireFrame(){
//Create wireframe helper for mesh with same geometry
var wireframeMesh=new THREE.WireframeGeometry(geometry);
var line = new THREE.LineSegments( wireframeMesh );
line.material.depthTest = false;
line.material.opacity = 0.75;
line.material.transparent = true;
mesh.add( line );
}
addWireFrame();
//Orbit controls
controls = new THREE.OrbitControls( camera );
// Create ambient light and add to scene.
var light = new THREE.AmbientLight(0x404040); // soft white light
scene.add(light);
// Create directional light and add to scene.
var directionalLight = new THREE.DirectionalLight(0xffffff);
directionalLight.position.set(1, 1, 1).normalize();
scene.add(directionalLight);
// Add listener for window resize.
window.addEventListener('resize', onWindowResize, false);
}
function animate() {
requestAnimationFrame(animate);
controls.update();
renderer.render(scene, camera);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
</script>
</body>
</html>
在代码中,我为面的每个顶点分配了红色、绿色和蓝色。
在顶点着色器中,我将这些颜色重定向到片段着色器。在片段着色器中,我计划使用我自己的公式来决定片段实例使用哪种颜色。 (我的公式会根据脸上的位置而定。)
但是,我无法阻止顶点颜色的插值。 three.js?
此外,我很欣赏可能适合我的问题的替代解决方案。
您不想禁用插值。相反,您想要使用插值坐标作为索引。插值颜色值告诉您您与每个顶点的距离。然后,您可以将此插值量化为范围,或将索引量化为颜色数组,以生成最终颜色。
我修改了你的 fiddle 以使用以下像素着色器显示最近顶点的颜色:
void main(){
vec3 c = vColor;
gl_FragColor = vec4(c.r > c.g && c.r > c.b ? 1.0 : 0.0,
c.g > c.r && c.g > c.b ? 1.0 : 0.0,
c.b > c.r && c.b > c.g ? 1.0 : 0.0,
1.0 );
}
结果如下所示:
您将需要更复杂的量化方法来显示等高线图,但我希望这种方法能给您一个好的开始。
我正在尝试编写一个在网格上绘制等高线图的着色器。
这里是 contour plot 的例子。
我的第一个目标是用不同的颜色想象一个三角形的脸。 您可以在 here 中找到我正在使用的代码。
<html lang="en">
<head>
<title>Face Contour Example</title>
</head>
<body>
<script src="http://threejs.org/build/three.min.js"></script>
<script src="http://threejs.org/examples/js/controls/OrbitControls.js"></script>
<script id="vertexShader" type="x-shader/x-vertex">
varying vec3 vColor;
void main(){
vColor = color;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
varying vec3 vColor;
void main(){
gl_FragColor = vec4( vColor.rgb, 1.0 );
}
</script>
<script type="text/javascript">
var camera, scene, renderer, mesh, material, controls;
init();
animate();
function init() {
// Renderer.
renderer = new THREE.WebGLRenderer();
//renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
// Add renderer to page
document.body.appendChild(renderer.domElement);
// Create camera.
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.z = -400;
// Create scene.
scene = new THREE.Scene();
var colors = {
"color1" : {
type : "c",
value : new THREE.Color(0xff0000) //r
},
"color2" : {
type : "c",
value : new THREE.Color(0x00ff00) //b
},
"color3" : {
type : "c",
value : new THREE.Color(0x0000ff) //g
},
};
var fShader = document.getElementById('fragmentShader').text;
var vShader = document.getElementById('vertexShader').text;
// Create material
var material = new THREE.ShaderMaterial({
vertexShader: vShader,
fragmentShader: fShader,
vertexColors: THREE.VertexColors,
});
// var material = new THREE.MeshBasicMaterial( { vertexColors: THREE.VertexColors } );
// Create cube and add to scene.
var geometry = new THREE.Geometry();
geometry.vertices=[
new THREE.Vector3(100,0,0),
new THREE.Vector3(-100,0,0),
new THREE.Vector3(50,100,0)
]
var face=new THREE.Face3();
face.a=0;
face.b=1;
face.c=2;
face.vertexColors[ 0 ] = colors["color1"].value;
face.vertexColors[ 1 ] = colors["color2"].value;
face.vertexColors[ 2 ] = colors["color3"].value;
geometry.faces=[face]
mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
function addWireFrame(){
//Create wireframe helper for mesh with same geometry
var wireframeMesh=new THREE.WireframeGeometry(geometry);
var line = new THREE.LineSegments( wireframeMesh );
line.material.depthTest = false;
line.material.opacity = 0.75;
line.material.transparent = true;
mesh.add( line );
}
addWireFrame();
//Orbit controls
controls = new THREE.OrbitControls( camera );
// Create ambient light and add to scene.
var light = new THREE.AmbientLight(0x404040); // soft white light
scene.add(light);
// Create directional light and add to scene.
var directionalLight = new THREE.DirectionalLight(0xffffff);
directionalLight.position.set(1, 1, 1).normalize();
scene.add(directionalLight);
// Add listener for window resize.
window.addEventListener('resize', onWindowResize, false);
}
function animate() {
requestAnimationFrame(animate);
controls.update();
renderer.render(scene, camera);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
</script>
</body>
</html>
在代码中,我为面的每个顶点分配了红色、绿色和蓝色。
在顶点着色器中,我将这些颜色重定向到片段着色器。在片段着色器中,我计划使用我自己的公式来决定片段实例使用哪种颜色。 (我的公式会根据脸上的位置而定。)
但是,我无法阻止顶点颜色的插值。 three.js?
此外,我很欣赏可能适合我的问题的替代解决方案。
您不想禁用插值。相反,您想要使用插值坐标作为索引。插值颜色值告诉您您与每个顶点的距离。然后,您可以将此插值量化为范围,或将索引量化为颜色数组,以生成最终颜色。
我修改了你的 fiddle 以使用以下像素着色器显示最近顶点的颜色:
void main(){
vec3 c = vColor;
gl_FragColor = vec4(c.r > c.g && c.r > c.b ? 1.0 : 0.0,
c.g > c.r && c.g > c.b ? 1.0 : 0.0,
c.b > c.r && c.b > c.g ? 1.0 : 0.0,
1.0 );
}
结果如下所示:
您将需要更复杂的量化方法来显示等高线图,但我希望这种方法能给您一个好的开始。