three.js - 如何在三个js中的自定义着色器上创建带有镜面反射贴图的镜面反射?

标签 three.js webgl shader specular

我正在使用 Three.JS 在 WebGL 中创建一个地球,到目前为止我已经有了一个具有昼夜纹理和大气的地球。现在为了完成它,我想在我的地球上添加一个仅在水部分显示的镜面反射。现在,我已经为此准备了一张高光贴图,但我似乎无法将它们组合在一起。

由于地球/夜晚/大气等因素,我在自定义着色器中完成所有操作,并且我读到我还必须在这个方程中包含镜面反射计算,因为 Three.JS 无法堆叠多个着色器。

这是我的着色器,我只停留在镜面反射部分:

<script id="earthFragmentShader" type="x-shader/x-fragment">
    uniform sampler2D dayTexture;
    uniform sampler2D nightTexture;
    uniform sampler2D specularTexture;
    uniform vec3 sunDirection;
    varying vec3 vNormal;
    varying vec2 vUv;
    void main() {
        // Textures for day and night:
        vec3 dayColor       = texture2D( dayTexture, vUv ).xyz;
        vec3 nightColor     = texture2D( nightTexture, vUv ).xyz;

        // compute cosine sun to normal so -1 is away from sun and +1 is toward sun.
        float cosineAngleSunToNormal = dot(normalize(vNormal), sunDirection);

        // sharpen the edge beween the transition
        cosineAngleSunToNormal = clamp( cosineAngleSunToNormal * 3.0, -1.0, 1.0);

        // convert to 0 to 1 for mixing
        float mixAmount = cosineAngleSunToNormal * 0.5 + 0.5;

        // Atmosphere:
        float intensity = 1.09 - dot( vNormal, vec3( 0.0,0.0, 1.0 ) );
        vec3 atmosphere = vec3( 1,1,1) * pow( intensity, 2.0 );

        // Select day or night texture based on mixAmount.
        vec3 color = mix( nightColor, dayColor + atmosphere, mixAmount );

        // Specular:
        vec3 specularAmount = texture2D( specularTexture, vUv ).xyz;
        vec3 specularColor  = vec3(1,1,1) * specularAmount;

        color = mix(color, specularColor, mixAmount);

        // Set the color
        gl_FragColor = vec4(color, 1.0);
    }
</script>

到目前为止,它只是将镜面反射贴图添加为地球上的纹理,但正如我提到的,我想使用此黑白图像来显示某种镜面反射。有人能指出我正确的方向吗?

编辑:

好吧,我用以下代码实现了整个映射:

// Specular:
vec3 specularAmount = texture2D( specularTexture, vUv ).xyz;
vec3 specularColor  = vec3(1,1,1);

float c = 0.35;
float p = 3.0;

float mixAmountSpecular = pow(c * dot(normalize(vNormal), sunDirection), p) * specularAmount.z;

// Select day or night texture based on mixAmount.
vec3 color = mix(dayColor, specularColor, mixAmountSpecular);
color = mix( nightColor, color + atmosphere, mixAmount );

现在唯一剩下的事情是如何让镜面反射点变小......对此有什么想法吗?

编辑2:

好吧,我终于通过调整一些参数实现了它:

float c = 0.035;
float p = 30.0;
float mixAmountSpecular = pow(c * dot(normalize(vNormal), specularDirection), p) * (specularAmount.z * 0.5);

作为引用,我的 sunDirection 是 -2, 0.8, 1,我的 specularDirection 是 -15, 10, 22.5。

最佳答案

我的 2 次编辑总结了要使用的最终着色器:

<script id="earthFragmentShader" type="x-shader/x-fragment">
    uniform sampler2D dayTexture;
    uniform sampler2D nightTexture;
    uniform sampler2D specularTexture;
    uniform vec3 sunDirection;
    uniform vec3 specularDirection;
    varying vec3 vNormal;
    varying vec2 vUv;
    void main() {
        // Textures for day and night:
        vec3 dayColor       = texture2D( dayTexture, vUv ).xyz;
        vec3 nightColor     = texture2D( nightTexture, vUv ).xyz;

        // compute cosine sun to normal so -1 is away from sun and +1 is toward sun.
        float cosineAngleSunToNormal = dot(normalize(vNormal), sunDirection);

        // sharpen the edge beween the transition
        cosineAngleSunToNormal = clamp( cosineAngleSunToNormal * 3.0, -1.0, 1.0);

        // convert to 0 to 1 for mixing
        float mixAmount = cosineAngleSunToNormal * 0.5 + 0.5;

        // Atmosphere:
        float intensity = 1.09 - dot( vNormal, vec3( 0.0,0.0, 1.0 ) );
        vec3 atmosphere = vec3( 1,1,1) * pow( intensity, 2.0 );

        // Specular:
        vec3 specularAmount = texture2D( specularTexture, vUv ).xyz;
        vec3 specularColor  = vec3(1,1,1);

        // Play with these parameters to adjust the specular:
        float c = 0.035;    // Size, I guess...
        float p = 30.0;     // Blur
        float mixAmountSpecular = pow(c * dot(normalize(vNormal), specularDirection), p) * (specularAmount.z * 0.5);

        // Select day or night texture based on mixAmount.
        vec3 color = mix(dayColor, specularColor, mixAmountSpecular);
        color = mix( nightColor, color + atmosphere, mixAmount );

        // Set the color
        gl_FragColor = vec4(color, 1.0);
    }
</script>

关于three.js - 如何在三个js中的自定义着色器上创建带有镜面反射贴图的镜面反射?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17973692/

相关文章:

javascript - 将 WebGL 非连续线渲染为单个对象

javascript - 如何计算二十面体的法线?

c++ - OpenGL - OBJ 中的顶点法线

opengl - 在 Ubuntu 中与未编译的着色器链接

android - 自定义着色器不适用于手机(Unity)

javascript - 如何优化 three.js 中多个 sphereGeometry 的渲染?

javascript - Three.js 纹理模型未正确应用于对象

javascript - Three.js 多边形/多面体名称或标题

webgl - 将夜灯添加到 WebGL/Three.js 地球

javascript - 如何在 Three.js 中用 ShaderMaterial 替换 Collada 导入的纹理?