광선 추적 3D 엔진 처음부터 3부분: 평면 및 반사
25368 단어 raytracingvanillajswebcomponents
깨끗이 정리하다
우리는 이전에
createMeshes
방법이 있었는데, 그것은 WebGL 엔진의 보존이다.광선 추적기의 기능이 격자에 그치지 않기 때문에 나는 이 속성과 상응하는 this.meshes
속성을 각각 createObjects
과 this.objects
으로 바꾸었다.내가 한 또 다른 일은
multiplyVector
을 scaleVector
으로 바꾸는 것이다.이것은 곱셈 연산을 더욱 잘 묘사했다. 왜냐하면 곱셈은 여러 가지 의미를 가질 수 있기 때문이다.그 밖에 모든 대상은 현재
type
속성을 가지고 있으며, 우리가 정확한 알고리즘을 실행할 수 있도록 정확한 의미를 정의할 것이다.교차 평면
다음 단계는 평면과 교차하는 것입니다.수학적으로 말하자면, 이것은 우리가 원에 대해 한 것과 같지만, 사실상 이것은 좀 더 쉽다.우리는 광선
origin + t * direction
의 방정식을 평면 dot(position, normal) - constant
의 방정식에 삽입하여 position
의 값을 얻을 것이다.몇 가지 재조정 조항은 우리로 하여금intersectPlane(ray, plane){
return (plane.offset - dotVector(ray.origin, plane.normal)) / dotVector(ray.direction, plane.normal);
}
객체가 평면인 경우 새로운 메서드를 사용하려면 intersectObjects
을 업데이트해야 합니다.intersectObjects(ray) {
let closest = { distance: Infinity, object: null };
for (let object of Object.values(this.objects)) {
let distance;
switch(object.type){
case "sphere": {
distance = this.intersectSphere(ray, object);
break;
}
case "plane": {
distance = this.intersectPlane(ray, object);
break;
}
}
if (distance != undefined && distance < closest.distance && distance > 0.001) {
closest = { distance, object };
}
}
return closest;
}
주의,if조건 distance > 0.001
에 새로운 용어를 추가했습니다.이것은 어떤 물건이 원점과 교차할 때 약간의 문제가 발생하는 것을 방지할 수 있다.만약 우리가 평면을 놓아서 카메라의 위치와 교차시키면, 우리는 기본적으로 검은 스크린을 얻을 수 있다. 왜냐하면 충돌은 카메라의 위치에서 발생하기 때문이다.강제 충돌을 통해 너무 가까워지지 않도록 함으로써 우리는 이런 상황을 방지할 수 있다.다음에 우리는 비행기의 법선을 얻어야 한다.이것은 사실상 평면 방정식에 의해 제시된 것이지만, 우리는 그것이 표준화되었는지 확인해야 한다. 그렇지 않으면 그것이 정상적으로 작동하지 못할 것이다.나는 또 그것을 구면법향 논리와 결합시켜서, 이렇게 하면 우리는 임의의 법향을 얻을 수 있다.
getNormal(collisionPosition, object){
switch(object.type){
case "sphere": {
return normalizeVector(subtractVector(collisionPosition, object.position));
}
case "plane": {
return normalizeVector(object.normal);
}
}
}
마지막으로 getSurfaceInfo
에서 우리는 하드코딩 구체법선이 아닌 새로운 방법을 사용했다.getSurfaceInfo(collisionPosition, object, ray){
let color = [0,0,0];
for(const light of Object.values(this.lights)){
if(this.isVisible(collisionPosition, light.position)){
const normal = this.getNormal(collisionPosition, object);
const toLight = subtractVector(light.position, collisionPosition);
const lightAmount = multiplyVector(light.color, dotVector(toLight, normal));
color = addVector(color, componentwiseMultiplyVector(object.color, lightAmount));
if(object.specularity){
const toCamera = normalizeVector(subtractVector(ray.origin, collisionPosition));
const halfVector = normalizeVector(addVector(toLight, toCamera));
const baseSpecular = clamp(dotVector(halfVector, normal), 0.0, 1.0);
const specularMagnitude = baseSpecular ** object.gloss;
const specularLight = componentwiseMultiplyVector(light.color, [specularMagnitude, specularMagnitude, specularMagnitude, 1.0]);
color = addVector(color, specularLight);)
}
}
}
return [...color, 1];
}
장면에 면 하나를 추가합니다.plane: {
type: "plane",
normal: [0,1,-1],
offset: 0,
color: [0.3,0.3,0.3,1]
}
봐라!이 모든 것은 단지 약간의 그림자 같은 것일 뿐이다.반성하다
광선 추적의 장점 중 하나는 실제 반사를 할 수 있다는 것이다.이를 위해서는 반사물체에 대한 빛의 반등을 계산해야 한다.
이것은 우리의 거울 반사 실현을 대체할 것이다. 왜냐하면 이것은 사실상 거울 반사가 어떻게 작동해야 하는지이기 때문이다.이것은 phong의 최초의 작업 원리와 같다. 단지 우리가 빛의 방향을 다음 곡면으로 반사한 다음에 다시 색을 계산할 뿐이다. (그리고 계속 추적하여 반사한다.)최종 색상은 서피스 반사율을 제어하는 미러 반사량으로 배율이 조정됩니다.즉, 거울의 반사도 1은 순수한 거울로 예상한 방식대로 작동하지 못할 수도 있다. (특히 만반사가 존재한다면 들어오는 빛보다 반사된 빛이 더 많다는 뜻이다.)
수직 주위의 반사는 다음과 같습니다.
//vector.js
export function reflectVector(vec, normal) {
return [
vec[0] - 2 * dotVector(vec, normal) * normal[0],
vec[1] - 2 * dotVector(vec, normal) * normal[1],
vec[2] - 2 * dotVector(vec, normal) * normal[2],
];
}
getSurfaceInfo(collisionPosition, object, ray, bounceCounter){
let color = [0,0,0];
for(const light of Object.values(this.lights)){
if(this.isVisible(collisionPosition, light.position)){
const normal = this.getNormal(collisionPosition, object);
const toLight = normalizeVector(subtractVector(light.position, collisionPosition));
const lightAmount = scaleVector(light.color, dotVector(toLight, normal));
color = addVector(color, componentwiseMultiplyVector(object.color, lightAmount));
if(object.specularity){
const reflectionDirection = reflectVector(ray.direction, normal);
const reflectionColor = this.raytrace({ origin: collisionPosition, direction: reflectionDirection }, bounceCounter - 1);
const specularLight = clamp(scaleVector(reflectionColor, object.specularity), 0.0, 1.0);
color = addVector(color, specularLight);
}
}
}
return [...color, 1];
}
제가 bounceCounter
의 추가 매개 변수를 추가한 것을 알 수 있습니다.귀속 검색은 무한에 가까울 수 있기 때문에, 우리는 어느 점에서 그것을 차단해야 한다.Dell은 raytrace
에 대해 다음과 같이 수정했습니다.raytrace(ray, bounceCounter = MAX_BOUNCES){
if(bounceCounter <= 0){
return BACKGROUND_COLOR;
}
const intersection = this.intersectObjects(ray);
if (intersection.distance === Infinity || intersection.distance === -Infinity) {
return BACKGROUND_COLOR;
}
const collisionPoint = addVector(ray.origin, scaleVector(ray.direction, intersection.distance));
return this.getSurfaceInfo(collisionPoint, intersection.object, ray, bounceCounter);
}
우리는 MAX_BOUNCES
부터 카운트다운을 시작합니다. 만약 우리가 0에 도달한다면 기본 색만 되돌려줍니다.MAX_BOUNCES
부터 3까지 정의했습니다.또한 배경색을 추출해서 쉽게 바꿀 수 있도록 했습니다. 반사 테스트를 할 때 흰색은 나쁜 선택입니다.나는 배경을 파란색으로 만들어 카메라를 조정했다.구체(0,0,0)는 y=-1을 가리키는 평면 위에 있다.이 평면은 회색이고 거울의 반사도는 0.7이다.
우리는 비행기 위의 그림자를 볼 수 있다.
환경 조명
이 점에서 우리는 물체의 색깔을 제어하기 어렵다. 왜냐하면 우리는 어떠한 에너지도 사용하지 않았기 때문에 빛이 너무 밝은 곳까지 계속 불린다.나는 정말 그 벌레 항아리를 열고 싶지 않아서, 우리로 하여금 약간의 추가 작업 공간을 가지게 했다.우리는'환경'빛의 개념을 도입할 수 있다.이것은 사방팔방에서 온 빛이기 때문에, 그것은 단지 모든 것에 첨가되었을 뿐이다.이것은 그늘이 이렇게 눈부시게 변하는 것을 방지하는 데 도움이 된다.
getSurfaceInfo
에서 우리는 불빛을 처음의 색깔에 추가하기만 하면 된다. let color = componentwiseMultiplyVector(BACKGROUND_LIGHT, object.color);
일반적으로 객체 재질 자체는 환경 광색과 만반사, 미러 반사를 지정하지만 그럴 필요는 없다고 생각합니다.이렇게 하면 우리는 불빛을 방해하지 않는 상황에서 전체 장면을 밝게 비출 수 있다.
그것을 극도로 발휘하다
라이트와 구를 추가하고 배경을 더 선명한 색상으로 변경합니다.
반사, 반사의 반사, 음영, 음영의 반사, 만반사와 환경광.코드가 많지 않은 상황에서 우리가 얻은 결과는 여전히 매우 만족스럽다.
여기서 코드를 찾을 수 있습니다: https://github.com/ndesmic/geort/tree/V3
Reference
이 문제에 관하여(광선 추적 3D 엔진 처음부터 3부분: 평면 및 반사), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/ndesmic/raytracing-3d-engine-from-scratch-part-3-planes-and-reflection-5h84텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)