【问题标题】:Three.js shapes with more than one color具有多种颜色的三个.js 形状
【发布时间】:2021-10-03 16:58:47
【问题描述】:

我对 Three.js 和 webGL 编程很陌生。我的场景中有一个圆锥体和一个圆柱体,根据以下脚本创建:

var scene;
var camera;
var renderer;

var createACone = function() {
    const geometry = new THREE.ConeGeometry( 3.5, 0.5, 100, 100, true, 0, 2*Math.PI);
    const material = new THREE.MeshBasicMaterial( {color: 'blue', opacity: 0.8, transparent: true} );
    const cone = new THREE.Mesh( geometry, material );
    cone.rotation.z +=3.1416;
    cone.position.x = 0.5;
    cone.position.y = 0.25;
    cone.position.z = 0;
    cone.castShadow = true;
    scene.add( cone );
}

var createACylinder = function(radiusTop, radiusBottom, height, x, y, z, opacity=0.5, z_rotate = 0, transparent=true, thetaStart=0, thetaLength=2*Math.PI) {
     const geometry = new THREE.CylinderGeometry(radiusTop, radiusBottom, height, 100, 100, true, thetaStart, thetaLength);
    const material = new THREE.MeshBasicMaterial( {color: 'blue', opacity: opacity, transparent: transparent} );
    const cylinder = new THREE.Mesh( geometry, material );
    cylinder.position.x = x;
    cylinder.position.y = y;
    cylinder.position.z = z;
    cylinder.rotation.z = z_rotate;
    scene.add( cylinder );
}

var createLight = function () {
    var spotLight1 = new THREE.DirectionalLight(0xffffff);
    var spotLight2 = new THREE.DirectionalLight(0xffffff, 0.3);
    var spotLight3 = new THREE.DirectionalLight(0xffffff, 0.3);
    var spotLight4 = new THREE.DirectionalLight(0xffffff, 0.3);
    spotLight1.position.set(20, 20, 50);
    spotLight2.position.set(0, 1, 0);
    spotLight3.position.set(-50, 20, 2);
    spotLight4.position.set(50, 20, 2);
    spotLight1.castShadow = true;
    spotLight2.castShadow = false;
    scene.add(spotLight1);
    scene.add(spotLight2);
    scene.add(spotLight3);
    scene.add(spotLight4);
};

var init = function(){
    scene = new THREE.Scene();
    camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 2000 );
    renderer = new THREE.WebGLRenderer({antialias: true});
    renderer.setSize( window.innerWidth, window.innerHeight );
    document.body.appendChild( renderer.domElement );

    camera.position.z = 6;
    camera.position.y = 0.5;
    camera.position.x= 0.5;
    this.createLight();
    this.createACone();
    this.createACylinder(3.5, 3.5, 1, 0.5, 1, 0, 0.8, 0, true,0, 2*Math.PI);

    this.render();
}

window.onload = this.init;

现在,我希望圆锥体和圆柱体根据它们的高度水平划分为两种颜色(例如,从底部底部到圆柱体高度的一半,我希望它为红色,其余部分为蓝色;对于锥体顶点到其高度的一半,我希望它是红色的,锥体的其余部分应该是蓝色的)。我在材料和几何的来源中寻找解决方案,但找不到任何可以帮助我实现这一目标的方法。我考虑过将每个几何图形一分为二,但这很麻烦,因为我想动态更改这个颜色大小比。有没有更好的方法在 Three.js 中实现这一点?

提前感谢您的帮助。

【问题讨论】:

标签: javascript three.js webgl


【解决方案1】:

使用ShaderMaterial 中的 UV 坐标,您可以选择两种颜色:

body {
  overflow: hidden;
  margin: 0;
}
<script type="module">
console.clear();
import * as THREE from "https://threejs.org/build/three.module.js";
import {OrbitControls} from "https://threejs.org/examples/jsm/controls/OrbitControls.js";
import {BufferGeometryUtils} from "https://threejs.org/examples/jsm/utils/BufferGeometryUtils.js";
import {GUI} from "https://threejs.org/examples/jsm/libs/dat.gui.module.js";

let scene = new THREE.Scene();
let camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 1, 100);
camera.position.set(0, -5, 8);
let renderer = new THREE.WebGLRenderer();
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);

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

let gCyl = new THREE.CylinderGeometry(5, 5, 1, 32, 1, true);
let gCon = new THREE.ConeGeometry(5, 1, 32, 1, true);
for(let i = 0; i < gCon.attributes.uv.count; i++){
  gCon.attributes.uv.setY(i, 1 - gCon.attributes.uv.getY(i));
}
gCon.rotateX(Math.PI);
gCon.translate(0, -1, 0);
let g = BufferGeometryUtils.mergeBufferGeometries([gCyl, gCon]);

let m = new THREE.ShaderMaterial({
  uniforms: {
    color1: {value: new THREE.Color("red")},
    color2: {value: new THREE.Color("blue")},
    colorRatio: {value: 0.5}
  },
  vertexShader:`
    varying vec2 vUv;
    void main() {
      vUv = uv;
      gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
    }
`,
  fragmentShader: `
    uniform vec3 color1;
    uniform vec3 color2;
    uniform float colorRatio;
    varying vec2 vUv;
    void main() {
      vec3 col = mix(color1, color2, step(colorRatio, vUv.y)); 
      gl_FragColor = vec4( col, 1.0);
    }
  `
});

let o = new THREE.Mesh(g, m);
scene.add(o);

let gui = new GUI();
gui.add(m.uniforms.colorRatio, "value", 0., 1.).name("colorRatio");

renderer.setAnimationLoop( _ => {
  renderer.render(scene, camera);
});
</script>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-07-17
    • 1970-01-01
    • 1970-01-01
    • 2021-07-31
    • 1970-01-01
    • 1970-01-01
    • 2017-02-07
    • 1970-01-01
    相关资源
    最近更新 更多