我已经创建了一个自定义着色器,它显示了带轮廓贴图的顶点的指定值。这是我的着色器的fiddle示例。
<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 src="http://threejs.org/examples/js/modifiers/SubdivisionModifier.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/dat-gui/0.5/dat.gui.min.js"></script>
<script type="x-shader/x-vertex" id="vertexShader">
varying vec3 vColor;
void main(){
vColor = color;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
</script>
<script type="x-shader/x-fragment" id="fragmentShader">
varying vec3 vColor;
uniform vec3 uVec3Array[ 6 ];
void main(){
float r=vColor.r;
int numberOfColor=6;
float step=1.0/float(numberOfColor);
int index = int(r/step);
for(int i=0;i<6;i++){
if(i==index){
vec3 fragColor= uVec3Array[i];
gl_FragColor=vec4(fragColor,1.0);
}
}
// gl_FragColor=vec4(vColor,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 = 3;
// Create scene.
scene = new THREE.Scene();
var palette1={
"uVec3Array" : {
type: "v3v",
value: [
new THREE.Vector3( 0,0,1.0),
new THREE.Vector3( 66/255, 238/255, 244/255 ),
new THREE.Vector3( 0,1,0 ),
new THREE.Vector3( 1,1,0 ),
new THREE.Vector3( 1,0.4,0.2),
new THREE.Vector3( 1,0,0 )
] }
}
var palette2={
"uVec3Array" : {
type: "v3v",
value: [
new THREE.Vector3( 1,0,0 ),
new THREE.Vector3( 1,0.4,0.2),
new THREE.Vector3( 1,1,0 ),
new THREE.Vector3( 0,1,0 ),
new THREE.Vector3( 66/255, 238/255, 244/255 ),
new THREE.Vector3( 0,0,1.0)
] }
}
var selectedPalette=palette1;
// var fShader = document.getElementById('smoothPlotFShader').text;
// var vShader = document.getElementById('vertexShader').text;
var material;
var vertexShader=document.getElementById('vertexShader').textContent;
var fragmentShader= document.getElementById('fragmentShader').textContent ;
var material = new THREE.ShaderMaterial({
vertexShader: vertexShader,
fragmentShader: fragmentShader,
vertexColors: THREE.VertexColors,
uniforms:selectedPalette,
side:2
});
// var wireframe = new THREE.MeshLambertMaterial({color: 0x7777ff,wireframe:true});
var cubeGeometry = new THREE.CubeGeometry( 1,1,1 );
var modifier = new THREE.SubdivisionModifier( 3 );
modifier.modify( cubeGeometry );
var cube = new THREE.Mesh( cubeGeometry, material );
scene.add( cube );
//Create value array linearyly
var numberOfValues=cubeGeometry.vertices.length;
var maxValue=30;
var minValue=-30;
var values=[]
for(var i=0;i<numberOfValues;i++){
values.push(minValue+(maxValue-minValue)*i/numberOfValues);
}
applyValuesToMesh(values,cube);
//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 switchPlatte(){
if(selectedPalette===palette1){
selectedPalette=palette2;
}else{
selectedPalette=palette1;
}
material.uniforms=selectedPalette;
material.needsUpdate=true;
cube.geometry.elementsNeedUpdate = true;
console.log("Material colors are changed");
}
//This button switches plattes of material
var gui = new dat.GUI();
var obj = { changeColors:switchPlatte}
gui.add(obj,'changeColors');
}
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);
}
var mesh;
function applyValuesToMesh(result,mesh){
var max=findMax(result);
var min=findMin(result);
function normalizeValue(value){
var range=max-min;
return (value-min)/range;
}
var normalizedResult=[];
for (r in result){
normalizedResult.push(normalizeValue(result[r]));
}
var numberOfNodes=mesh.geometry.vertices.length;
var faces=mesh.geometry.faces;
// debugger
for(f in faces){
faces[f].vertexColors[0]=new THREE.Color(normalizedResult[faces[f].a],0.5,0.5);
faces[f].vertexColors[1]=new THREE.Color(normalizedResult[faces[f].b],0.5,0.5);
faces[f].vertexColors[2]=new THREE.Color(normalizedResult[faces[f].c],0.5,0.5);
}
mesh.geometry.elementsNeedUpdate = true;
}
function findMax(array){
var max=-Infinity;
for (v in array){
if(array[v]>max) max=array[v];
}
return max;
}
function findMin(array){
var min=Infinity;
for (v in array){
if(array[v]<min) min=array[v];
}
return min;
}
</script>
</body>
代码可能看起来很复杂。基本上,我正在创建一个细分的立方体,并为每个面添加顶点颜色。但是,顶点颜色表示值(值可以是任何值,不需要依赖几何),而不是颜色。如果你看我的着色器,它会提取顶点颜色的.r值,并从输入制服中获取该值的相应颜色。因此,基本上物质制服是在绘制顶点值时将使用的颜色。
我的问题是如果我在创建材料后更改颜色(制服);变化不会影响材料。
在代码的底部,我添加了一个gui按钮,可以在按下时切换材料的颜色(制服)。我已经尝试过材料需求更新,元素需要更新以及文档提供的所有其他更新,但未应用更改。
那么如何在创建材料后更改这些制服。
答案 0 :(得分:1)
你正在以错误的方式更新制服。只需设置一次制服并仅使用新向量更新value
属性。以下小提琴演示了这种方法:http://jsfiddle.net/50u0rwb4/18/
BTW:更新制服时不需要以下声明。
material.needsUpdate = true;
cube.geometry.elementsNeedUpdate = true;