由于您使用自定义着色器,因此您需要在着色器中自己进行光照计算。这可以帮助你:Using lights in three.js shader
这里是定制照明(online demo)全样本:
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/85/three.min.js"> </script>
<script id="vertShader" type="shader">
varying vec2 vUv;
varying vec3 vecPos;
varying vec3 vecNormal;
void main() {
vUv = uv;
// Since the light is in camera coordinates,
// I'll need the vertex position in camera coords too
vecPos = (modelViewMatrix * vec4(position, 1.0)).xyz;
// That's NOT exacly how you should transform your
// normals but this will work fine, since my model
// matrix is pretty basic
vecNormal = (modelViewMatrix * vec4(normal, 0.0)).xyz;
gl_Position = projectionMatrix *
vec4(vecPos, 1.0);
}
</script>
<script id="fragShader" type="shader">
precision highp float;
varying vec2 vUv;
varying vec3 vecPos;
varying vec3 vecNormal;
uniform float lightIntensity;
uniform sampler2D textureSampler;
struct PointLight {
vec3 color;
vec3 position; // light position, in camera coordinates
float distance; // used for attenuation purposes. Since
// we're writing our own shader, it can
// really be anything we want (as long as
// we assign it to our light in its
// "distance" field
};
uniform PointLight pointLights[NUM_POINT_LIGHTS];
void main(void) {
// Pretty basic lambertian lighting...
vec4 addedLights = vec4(0.0,
0.0,
0.0,
1.0);
for(int l = 0; l < NUM_POINT_LIGHTS; l++) {
vec3 lightDirection = normalize(vecPos
- pointLights[l].position);
addedLights.rgb += clamp(dot(-lightDirection,
vecNormal), 0.0, 1.0)
* pointLights[l].color
* lightIntensity;
}
gl_FragColor = texture2D(textureSampler, vUv)
* addedLights;
}
</script>
</head>
<body style="margin: 0px;" onload="init()">
<script>
// standard global variables
var scene, camera, renderer, textureLoader, light;
// Character 3d object
var character = null;
// FUNCTIONS
function init() {
// SCENE
scene = new THREE.Scene();
textureLoader = new THREE.TextureLoader();
// CAMERA
var SCREEN_WIDTH = window.innerWidth;
var SCREEN_HEIGHT = window.innerHeight;
var VIEW_ANGLE = 45;
var ASPECT = SCREEN_WIDTH/SCREEN_HEIGHT;
var NEAR = 0.1;
var FAR = 1000;
camera = new THREE.PerspectiveCamera(VIEW_ANGLE, ASPECT,
NEAR, FAR);
scene.add(camera);
camera.position.set(0,0,5);
camera.lookAt(scene.position);
// RENDERER
renderer = new THREE.WebGLRenderer({
antialias:true,
alpha: true
});
renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
var container = document.body;
container.appendChild(renderer.domElement);
// Create light
light = new THREE.PointLight(0xffffff, 1.0);
// We want it to be very close to our character
light.position.set(0.0, 0.0, 0.1);
scene.add(light);
// Create character
character = buildCharacter();
scene.add(character);
// Start animation
animate();
}
var buildCharacter = (function() {
var _geo = null;
// Share the same geometry across all planar objects
function getPlaneGeometry() {
if(_geo == null) {
_geo = new THREE.PlaneGeometry(1.0, 1.0);
}
return _geo;
};
return function() {
var g = getPlaneGeometry();
var creatureImage = textureLoader.load('g.png');
creatureImage.magFilter = THREE.NearestFilter;
var mat = new THREE.ShaderMaterial({
uniforms: THREE.UniformsUtils.merge([
THREE.UniformsLib['lights'],
{
lightIntensity: {type: 'f', value: 1.0},
textureSampler: {type: 't', value: null}
}
]),
vertexShader: document.getElementById('vertShader').text,
fragmentShader: document.getElementById('fragShader').text,
transparent: true,
lights: true
});
// THREE.UniformsUtils.merge() call THREE.clone() on
// each uniform. We don't want our texture to be
// duplicated, so I assign it to the uniform value
// right here.
mat.uniforms.textureSampler.value = creatureImage;
var obj = new THREE.Mesh(g, mat);
return obj;
}
})();
function animate() {
// Update light profile
var timestampNow = new Date().getTime()/1000.0;
var lightIntensity = 0.75 +
0.25 * Math.cos(timestampNow *
Math.PI);
character.material.uniforms
.lightIntensity.value = lightIntensity;
light.color.setHSL(lightIntensity, 1.0, 0.5);
// Render scene
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
</script>
</body>
</html>
谢谢,但我还是不明白这一点。我周围发现并发现了一大堆相互矛盾的信息。我更新了我的小提琴[这里](http://jsfiddle.net/richardylewright/7nwpob4y/32/)与另一个尝试在创建shaderMaterial和包括灯。生成的shaderMaterial(在调试器中)看起来没问题。所有合适的制服人员都在那里(从灯光库)以及我的定制制服(lut等)。它没有错误地运行,但飞机没有得到高度信息,它是黑色的。猜测,顶点着色器中止了?任何人都可以指出我缺少的东西吗? TIA。 – rkwright
感谢您的帮助!我复制它并运行它(伪造一个g.png后)。有用。所以我现在正在研究代码。然而,我已经阅读了一些关于SO的文章,建议可以“简单地”将场景灯光传递给着色器,而不必在着色器中重新创建灯光。看[这里](http://stackoverflow.com/questions/35596705/using-lights-in-three-js-shader),但也许我误解了。 – rkwright