首页 > 解决方案 > THREE.js vertexShader 基于高度的颜色混合

问题描述

仅当高度为零时如何将颜色设置为网格?

至于现在,我只是混合颜色:

在此处输入图像描述

问题是这种混合不精确。我只在高度为零时才想要蓝色(所以只在我用油漆制作的红色路径内)。

我为网格创建了一个自定义材质,如下所示:

material = new THREE.ShaderMaterial({
                
                      uniforms: THREE.UniformsUtils.merge([
                      THREE.UniformsLib['lights'],
                      {
                    lightIntensity: {type: 'f', value: 1.0},
                    diffuse: {type: 'c', value: new THREE.Color(0x0000ff)},
                        color0: {
                          value: new THREE.Color("blue")
                        },
                        color1: {
                          value: new THREE.Color("green")
                        },
                        color2: {
                          value: new THREE.Color("brown")
                        },
                        color3: {
                          value: new THREE.Color("black")
                        },
                        bboxMin: {
                          value: geom.boundingBox.min
                        },
                        bboxMax: {
                          value: geom.boundingBox.max
                        }
                
                          }
                        ]),
                      vertexShader: `
                        uniform vec3 bboxMin;
                        uniform vec3 bboxMax;
                        varying vec2 vUv;
                            varying vec3 vPos;
                varying vec3 vNormal;
                        void main() {
                          vPos = (modelMatrix * vec4(position, 1.0 )).xyz;
                          vNormal = normalMatrix * normal;
                          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;
                        uniform vec3 color3;
                        uniform vec3 color0;
                        varying vec2 vUv;
                    
                        uniform vec3 diffuse;
                        varying vec3 vPos;
                        varying vec3 vNormal;

                        struct PointLight {
                          vec3 position;
                          vec3 color;
                        };
                        uniform PointLight pointLights[ NUM_POINT_LIGHTS ];
                        
                        void main() {
                    vec4 addedLights = vec4(0.1, 0.1, 0.1, 1.0);
                      for(int l = 0; l < NUM_POINT_LIGHTS; l++) {
                        vec3 adjustedLight = pointLights[l].position + cameraPosition;
                        vec3 lightDirection = normalize(vPos - adjustedLight);
                        addedLights.rgb += clamp(dot(-lightDirection, vNormal), 0.0, 1.0) * pointLights[l].color;
                      }
                
                                  
                                            gl_FragColor = mix(vec4(mix(mix(mix(color0, color1, vUv.y), color1, vUv.y), mix(color1, color2, vUv.y), vUv.y), 1.0),addedLights, addedLights);
                                            }
                                          `,
                                        lights: true
                                        });

标签: javascriptcolorsthree.jsglsl

解决方案


尝试使用该step()功能。这里有一个定义来帮助你理解它。以下是它的工作原理:

float step(float edge, float x)

  • 它接受一个常量来声明edge, 和x,这是你的变量。
  • 如果 x 低于边缘,则得到0,如果 x 高于边缘,则得到1

这是它的简化用法。当高度低于 0.2 时,你会得到蓝色,当高度高于 0.2 时,你会得到绿色。

vec3 green = vec3(0.0, 1.0, 0.0);
vec3 blue  = vec3(0.0, 0.0, 1.0);

float edge = 0.2;

float colorMix = step(edge, height);
vec3 finalColor = mix(blue, green, colorMix);

我选择了 0.2 给蓝色带一些厚度,否则它不会可见。


推荐阅读