Это сцена, на которой я тестирую свой код glsl. Белая линия - это лазерный луч, который я нарисовал на основе некоторого масштабирования и преобразования базовой CylinderGeometry в three.js.,Серый шар - это «зеркальный шар».Я могу перемещаться вокруг зеркального шара в любом направлении, и я хочу, чтобы лазер отражался от шара, если мяч и лазер пересекаются.Однако, это никогда не происходит в соответствии с моим кодом glsl.
Прежде всего, так я формирую геометрию шара и лазера.
var mirrorBallPosition = { type: 'v3', value: new THREE.Vector3(0.0, 3.0, -2.0)};
var laserMaterial = new THREE.ShaderMaterial({
uniforms: {
offset: {type: 'v3', value: new THREE.Vector3(-0.15, 2.42, -0.64)},
mirrorBallPosition: mirrorBallPosition
}
})
var mirrorBallMaterial = new THREE.ShaderMaterial({
uniforms:{
mirrorBallPosition: mirrorBallPosition
}
});
// LOAD SHADERS
var shaderFiles = [
'glsl/laser.vs.glsl',
'glsl/laser.fs.glsl',
'glsl/mirrorBall.vs.glsl',
'glsl/mirrorBall.fs.glsl'
];
new THREE.SourceLoader().load(shaderFiles, function(shaders) {
laserMaterial.vertexShader = shaders['glsl/laser.vs.glsl'];
laserMaterial.fragmentShader = shaders['glsl/laser.fs.glsl'];
mirrorBallMaterial.vertexShader = shaders['glsl/mirrorBall.vs.glsl'];
mirrorBallMaterial.fragmentShader = shaders['glsl/mirrorBall.fs.glsl'];
})
laser = {}
//Laser geometry
laser.laserGeometry = new THREE.CylinderGeometry(0.02, 0.02, 1, 16);
for (let i = 0; i < laser.laserGeometry.vertices.length; ++i)
laser.laserGeometry.vertices[i].y += 0.5;
laser.leftLaser = new THREE.Mesh(laser.laserGeometry, leftLaserMaterial);
laser.rightLaser = new THREE.Mesh(laser.laserGeometry, rightLaserMaterial);
scenes[Part.LASERS].add(laser.leftLaser);
scenes[Part.LASERS].add(laser.rightLaser);
laser.mirrorBallGeometry = new THREE.SphereGeometry(1,32,32);
laser.mirrorBall = new THREE.Mesh(laser.mirrorBallGeometry, mirrorBallMaterial);
scenes[Part.LASERS].add(laser.mirrorBall);
...
// SETUP UPDATE CALL-BACK
function update() {
checkKeyboard();
requestAnimationFrame(update);
renderer.render(scenes[Part.LASERS], cameras[Part.LASERS]);
}
update();
И это вершинный шейдеркод для моего лазера.
#version 300 es
uniform vec3 offset;
uniform vec3 mirrorBallPosition;
void main(){
vec3 targetPosition = vec3(0.0, 0.3, -5.0);
vec3 laserStart = offset + vec3(0.0,1.0,0.0);
laserStart.y = offset.y;
mat4 T = mat4(1.0);
T[3].xyz = laserStart;
mat4 S = mat4(1.0);
S[1][1] = length(laserStart-targetPosition);
// Roll the laser horizontally
mat4 Rx = mat4(1.0);
Rx[1][1] = 0.0;
Rx[1][2] = -1.0;
Rx[2][1] = 1.0;
Rx[2][2] = 0.0;
vec3 laserDirection = targetPosition - laserStart;
vec3 laserDirectionZX = laserDirection;
laserDirectionZX.y = 0.0;
laserDirection = normalize(laserDirection);
laserDirectionZX = normalize(laserDirectionZX);
mat4 Rz = mat4(1.0);
vec3 minusZ = vec3(0.0,0.0,-1.0);
float cosBeta = dot(minusZ, laserDirectionZX);
float sinBeta = sqrt(1.0-(cosBeta * cosBeta));
float flag = 1.0;
float relativeXCoordinate = laserStart.x-targetPosition.x;
if(relativeXCoordinate < 0.0){
flag = -1.0;
}
Rz[0][0] = cosBeta;
Rz[1][0] = -sinBeta * flag;
Rz[0][1] = sinBeta * flag;
Rz[1][1] = cosBeta;
// Roll the laser vertically
mat4 Rx_2 = mat4(1.0);
float cosAlpha = dot(laserDirection, laserDirectionZX);
float sinAlpha = sqrt(1.0-(cosAlpha * cosAlpha));
Rx_2[1][1] = cosAlpha;
Rx_2[2][1] = sinAlpha;
Rx_2[1][2] = -sinAlpha;
Rx_2[2][2] = cosAlpha;
//Now this is the reflection part.
//Got all of these equations here(URL below)
//https://en.wikipedia.org/wiki/Line%E2%80%93sphere_intersection
float r = 0.3; //sphere size
float temp = dot(laserDirection,laserStart-mirrorBallPosition);
float temp2 = length(laserStart-mirrorBallPosition);
float insideSQRT = (temp * temp) - (temp2*temp2-r*r);
// I calculate the world position with this transformation.
vec3 fragmentWorldPos = vec3(T * Rx * Rz * Rx_2 * S * vec4(position, 1.0));
if(length(fragmentWorldPos-mirrorBallPosition)<r){ //This is when the laser should reflect.
float d = -temp - sqrt(insideSQRT);
vec3 closestIntersect = (laserStart+(d*laserDirection));
vec3 fromCenterToIntersect = closestIntersect - mirrorBallPosition;
fromCenterToIntersect = normalize(fromCenterToIntersect);
vec3 lightComingIn = closestIntersect-laserStart;
vec3 reflectDir = reflect(lightComingIn, fromCenterToIntersect);
reflectDir = normalize(reflectDir);
float distance = length(fragmentWorldPos-closestIntersect);
vec3 updatedWorldPosition = closestIntersect + (reflectDir * distance);
gl_Position = projectionMatrix * viewMatrix * vec4(updatedWorldPosition,1.0);
}
else{ // This is when the laser should not reflect.
gl_Position = projectionMatrix * viewMatrix * vec4(fragmentWorldPos, 1.0);
}
}
Это довольно длинный код, но единственной важной частью должна быть инструкция if-else в последней части.
float r = 0.3; //sphere size
float temp = dot(laserDirection,laserStart-mirrorBallPosition);
float temp2 = length(laserStart-mirrorBallPosition);
float insideSQRT = (temp * temp) - (temp2*temp2-r*r);
vec3 fragmentWorldPos = vec3(T * Rx * Rz * Rx_2 * S * vec4(position, 1.0));
if(length(fragmentWorldPos-mirrorBallPosition)<r){ //This is when the laser should reflect.
float d = -temp - sqrt(insideSQRT);
vec3 closestIntersect = (laserStart+(d*laserDirection));
vec3 fromCenterToIntersect = closestIntersect - mirrorBallPosition;
fromCenterToIntersect = normalize(fromCenterToIntersect);
vec3 lightComingIn = closestIntersect-laserStart;
vec3 reflectDir = reflect(lightComingIn, fromCenterToIntersect);
reflectDir = normalize(reflectDir);
float distance = length(fragmentWorldPos-closestIntersect);
vec3 updatedWorldPosition = closestIntersect + (reflectDir * distance);
gl_Position = projectionMatrix * viewMatrix * vec4(updatedWorldPosition,1.0);
}
else{ // This is when the laser should not reflect.
gl_Position = projectionMatrix * viewMatrix * vec4(fragmentWorldPos, 1.0);
}
Кажется, что часть if {} никогда не выполняется, а выполняется только часть else {}, что означает, что линия и сфера никогда не считаются пересекающимися.Если я переместлю сферу, чтобы пересечь линию, результат будет следующим:
Доля лазера внутри сферы все еще там, еслиЯ перемещаю камеру, чтобы посмотреть внутрь сферы, что означает, что оператор if работает неправильно.
Я получил все свои уравнения отсюда "https://en.wikipedia.org/wiki/Line%E2%80%93sphere_intersection",, и я дважды проверил свой кодесли они правильно реализовали уравнения. Есть ли причина, по которой это происходит?