将颜色渐变应用于网格上的材质 - Three.js [英] Apply color gradient to material on mesh - three.js

查看:16
本文介绍了将颜色渐变应用于网格上的材质 - Three.js的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 STL 文件加载到我的场景中,其中一种颜色应用于 phong 材质

我想要一种将两种颜色应用到此网格材料的方法,并在 Z 轴上应用渐变效果,如下例所示.渐变花瓶]1

我有一种感觉,我可能需要引入着色器,但我还没有使用 Three.js 做到这一点.

解决方案

简单的渐变着色器,基于uvs:

var scene = new THREE.Scene();var camera = new THREE.PerspectiveCamera(60, 1, 1, 1000);相机位置设置(13、25、38);相机.看(场景.位置);var renderer = new THREE.WebGLRenderer({抗锯齿:真});var canvas = renderer.domElementdocument.body.appendChild(canvas);var controls = new THREE.OrbitControls(camera, renderer.domElement);var geometry = new THREE.CylinderBufferGeometry(2, 5, 20, 32, 1, true);var material = new THREE.ShaderMaterial({制服:{颜色 1:{值:新三色(红色")},颜色 2:{值:新三色(紫色")}},顶点着色器:`不同的 vec2 vUv;无效主(){vUv = uv;gl_Position = 投影矩阵 * 模型视图矩阵 * vec4(position,1.0);}`,片段着色器:`统一 vec3 color1;统一的 vec3 color2;不同的 vec2 vUv;无效主(){gl_FragColor = vec4(mix(color1, color2, vUv.y), 1.0);}`,线框:真实});var mesh = new THREE.Mesh(geometry, material);场景.添加(网格);使成为();功能调整大小(渲染器){const canvas = renderer.domElement;const width = canvas.clientWidth;常量高度 = canvas.clientHeight;const needResize = canvas.width !== width ||canvas.height !== 高度;如果(需要调整大小){renderer.setSize(width, height, false);}返回需要调整大小;}函数渲染(){如果(调整大小(渲染器)){camera.aspect = canvas.clientWidth/canvas.clientHeight;相机.updateProjectionMatrix();}renderer.render(场景,相机);请求动画帧(渲染);}

html,身体 {高度:100%;边距:0;溢出:隐藏;}帆布 {宽度:100%;高度:100%;展示;堵塞;}

<script src="https://cdn.jsdelivr.net/npm/three@0.115.0/build/three.min.js"></script><script src="https://cdn.jsdelivr.net/npm/three@0.115.0/examples/js/controls/OrbitControls.js"></script>

简单的渐变着色器,基于坐标:

var scene = new THREE.Scene();var camera = new THREE.PerspectiveCamera(60, 1, 1, 1000);相机位置设置(13、25、38);相机.看(场景.位置);var renderer = new THREE.WebGLRenderer({抗锯齿:真});var canvas = renderer.domElementdocument.body.appendChild(canvas);var controls = new THREE.OrbitControls(camera, renderer.domElement);var geometry = new THREE.CylinderBufferGeometry(2, 5, 20, 16, 4, true);geometry.computeBoundingBox();var material = new THREE.ShaderMaterial({制服:{颜色 1:{值:新三色(红色")},颜色 2:{值:新三色(紫色")},bboxMin:{值:geometry.boundingBox.min},bboxMax:{值:geometry.boundingBox.max}},顶点着色器:`统一 vec3 bboxMin;统一 vec3 bboxMax;不同的 vec2 vUv;无效主(){vUv.y = (position.y - bboxMin.y)/(bboxMax.y - bboxMin.y);gl_Position = 投影矩阵 * 模型视图矩阵 * vec4(position,1.0);}`,片段着色器:`统一 vec3 color1;统一的 vec3 color2;不同的 vec2 vUv;无效主(){gl_FragColor = vec4(mix(color1, color2, vUv.y), 1.0);}`,线框:真实});var mesh = new THREE.Mesh(geometry, material);场景.添加(网格);使成为();功能调整大小(渲染器){const canvas = renderer.domElement;const width = canvas.clientWidth;常量高度 = canvas.clientHeight;const needResize = canvas.width !== width ||canvas.height !== 高度;如果(需要调整大小){renderer.setSize(width, height, false);}返回需要调整大小;}函数渲染(){如果(调整大小(渲染器)){camera.aspect = canvas.clientWidth/canvas.clientHeight;相机.updateProjectionMatrix();}renderer.render(场景,相机);请求动画帧(渲染);}

html,身体 {高度:100%;边距:0;溢出:隐藏;}帆布 {宽度:100%;高度:100%;显示:块;}

<script src="https://cdn.jsdelivr.net/npm/three@0.115.0/build/three.min.js"></script><script src="https://cdn.jsdelivr.net/npm/three@0.115.0/examples/js/controls/OrbitControls.js"></script>

具有顶点颜色的渐变:

var scene = new THREE.Scene();var camera = new THREE.PerspectiveCamera(60, 1, 1, 1000);相机位置设置(0, 0, 10);var renderer = new THREE.WebGLRenderer({抗锯齿:真});var canvas = renderer.domElementdocument.body.appendChild(canvas);var geom = new THREE.TorusKnotGeometry(2.5, .5, 100, 16);var rev = true;var cols = [{停止:0,颜色:新三色(0xf7b000)}, {停止:.25,颜色:新三色(0xdd0080)}, {停止:.5,颜色:新三色(0x622b85)}, {停止:.75,颜色:新三色(0x007dae)}, {停止:1,颜色:新三色(0x77c8db)}];setGradient(geom, cols, 'z', rev);函数 setGradient(几何,颜色,轴,反向){geometry.computeBoundingBox();var bbox = geometry.boundingBox;var size = new THREE.Vector3().subVectors(bbox.max, bbox.min);var vertexIndices = ['a', 'b', 'c'];var face, vertex, normalized = new THREE.Vector3(),标准化轴 = 0;for (var c = 0; c 

html,身体 {高度:100%;边距:0;溢出:隐藏;}帆布 {宽度:100%;高度:100%;展示;堵塞;}

<script src="https://cdn.jsdelivr.net/npm/three@0.115.0/build/three.min.js"></script>

实际上,使用哪种方法取决于您:着色器、顶点颜色、纹理等.

I have an STL file loaded into my scene with a single colour applied to a phong material

I'd like a way of applying two colours to this mesh's material with a gradient effect applied on the Z axis a like the example below.Gradient Vase]1

I have a feeling I may have to introduce shaders but I've not gotten this far with three.js.

解决方案

Simple gradient shader, based on uvs:

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, 1, 1, 1000);
camera.position.set(13, 25, 38);
camera.lookAt(scene.position);
var renderer = new THREE.WebGLRenderer({
  antialias: true
});
var canvas = renderer.domElement
document.body.appendChild(canvas);

var controls = new THREE.OrbitControls(camera, renderer.domElement);

var geometry = new THREE.CylinderBufferGeometry(2, 5, 20, 32, 1, true);
var material = new THREE.ShaderMaterial({
  uniforms: {
    color1: {
      value: new THREE.Color("red")
    },
    color2: {
      value: new THREE.Color("purple")
    }
  },
  vertexShader: `
    varying vec2 vUv;

    void main() {
      vUv = uv;
      gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
    }
  `,
  fragmentShader: `
    uniform vec3 color1;
    uniform vec3 color2;
  
    varying vec2 vUv;
    
    void main() {
      
      gl_FragColor = vec4(mix(color1, color2, vUv.y), 1.0);
    }
  `,
  wireframe: true
});
var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);



render();

function resize(renderer) {
  const canvas = renderer.domElement;
  const width = canvas.clientWidth;
  const height = canvas.clientHeight;
  const needResize = canvas.width !== width || canvas.height !== height;
  if (needResize) {
    renderer.setSize(width, height, false);
  }
  return needResize;
}

function render() {
  if (resize(renderer)) {
    camera.aspect = canvas.clientWidth / canvas.clientHeight;
    camera.updateProjectionMatrix();
  }
  renderer.render(scene, camera);
  requestAnimationFrame(render);
}

html,
body {
  height: 100%;
  margin: 0;
  overflow: hidden;
}

canvas {
  width: 100%;
  height: 100%;
  display;
  block;
}

<script src="https://cdn.jsdelivr.net/npm/three@0.115.0/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.115.0/examples/js/controls/OrbitControls.js"></script>

Simple gradient shader, based on coordinates:

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, 1, 1, 1000);
camera.position.set(13, 25, 38);
camera.lookAt(scene.position);
var renderer = new THREE.WebGLRenderer({
  antialias: true
});
var canvas = renderer.domElement
document.body.appendChild(canvas);

var controls = new THREE.OrbitControls(camera, renderer.domElement);

var geometry = new THREE.CylinderBufferGeometry(2, 5, 20, 16, 4, true);
geometry.computeBoundingBox();
var material = new THREE.ShaderMaterial({
  uniforms: {
    color1: {
      value: new THREE.Color("red")
    },
    color2: {
      value: new THREE.Color("purple")
    },
    bboxMin: {
      value: geometry.boundingBox.min
    },
    bboxMax: {
      value: geometry.boundingBox.max
    }
  },
  vertexShader: `
    uniform vec3 bboxMin;
    uniform vec3 bboxMax;
  
    varying vec2 vUv;

    void main() {
      vUv.y = (position.y - bboxMin.y) / (bboxMax.y - bboxMin.y);
      gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
    }
  `,
  fragmentShader: `
    uniform vec3 color1;
    uniform vec3 color2;
  
    varying vec2 vUv;
    
    void main() {
      
      gl_FragColor = vec4(mix(color1, color2, vUv.y), 1.0);
    }
  `,
  wireframe: true
});
var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);



render();

function resize(renderer) {
  const canvas = renderer.domElement;
  const width = canvas.clientWidth;
  const height = canvas.clientHeight;
  const needResize = canvas.width !== width || canvas.height !== height;
  if (needResize) {
    renderer.setSize(width, height, false);
  }
  return needResize;
}

function render() {
  if (resize(renderer)) {
    camera.aspect = canvas.clientWidth / canvas.clientHeight;
    camera.updateProjectionMatrix();
  }
  renderer.render(scene, camera);
  requestAnimationFrame(render);
}

html,
body {
  height: 100%;
  margin: 0;
  overflow: hidden;
}

canvas {
  width: 100%;
  height: 100%;
  display: block;
}

<script src="https://cdn.jsdelivr.net/npm/three@0.115.0/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.115.0/examples/js/controls/OrbitControls.js"></script>

Gradient with vertex colours:

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, 1, 1, 1000);
camera.position.set(0, 0, 10);
var renderer = new THREE.WebGLRenderer({
  antialias: true
});
var canvas = renderer.domElement
document.body.appendChild(canvas);


var geom = new THREE.TorusKnotGeometry(2.5, .5, 100, 16);

var rev = true;

var cols = [{
  stop: 0,
  color: new THREE.Color(0xf7b000)
}, {
  stop: .25,
  color: new THREE.Color(0xdd0080)
}, {
  stop: .5,
  color: new THREE.Color(0x622b85)
}, {
  stop: .75,
  color: new THREE.Color(0x007dae)
}, {
  stop: 1,
  color: new THREE.Color(0x77c8db)
}];

setGradient(geom, cols, 'z', rev);

function setGradient(geometry, colors, axis, reverse) {

  geometry.computeBoundingBox();

  var bbox = geometry.boundingBox;
  var size = new THREE.Vector3().subVectors(bbox.max, bbox.min);

  var vertexIndices = ['a', 'b', 'c'];
  var face, vertex, normalized = new THREE.Vector3(),
    normalizedAxis = 0;

  for (var c = 0; c < colors.length - 1; c++) {

    var colorDiff = colors[c + 1].stop - colors[c].stop;

    for (var i = 0; i < geometry.faces.length; i++) {
      face = geometry.faces[i];
      for (var v = 0; v < 3; v++) {
        vertex = geometry.vertices[face[vertexIndices[v]]];
        normalizedAxis = normalized.subVectors(vertex, bbox.min).divide(size)[axis];
        if (reverse) {
          normalizedAxis = 1 - normalizedAxis;
        }
        if (normalizedAxis >= colors[c].stop && normalizedAxis <= colors[c + 1].stop) {
          var localNormalizedAxis = (normalizedAxis - colors[c].stop) / colorDiff;
          face.vertexColors[v] = colors[c].color.clone().lerp(colors[c + 1].color, localNormalizedAxis);
        }
      }
    }
  }
}

var mat = new THREE.MeshBasicMaterial({
  vertexColors: THREE.VertexColors,
  wireframe: true
});
var obj = new THREE.Mesh(geom, mat);
scene.add(obj);



render();

function resize(renderer) {
  const canvas = renderer.domElement;
  const width = canvas.clientWidth;
  const height = canvas.clientHeight;
  const needResize = canvas.width !== width || canvas.height !== height;
  if (needResize) {
    renderer.setSize(width, height, false);
  }
  return needResize;
}

function render() {
  if (resize(renderer)) {
    camera.aspect = canvas.clientWidth / canvas.clientHeight;
    camera.updateProjectionMatrix();
  }
  renderer.render(scene, camera);
  obj.rotation.y += .01;
  requestAnimationFrame(render);
}

html,
body {
  height: 100%;
  margin: 0;
  overflow: hidden;
}

canvas {
  width: 100%;
  height: 100%;
  display;
  block;
}

<script src="https://cdn.jsdelivr.net/npm/three@0.115.0/build/three.min.js"></script>

Actually, it's up to you which approach to use: shaders, vertex colours, textures etc.

这篇关于将颜色渐变应用于网格上的材质 - Three.js的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆