어떻게 threejs 로 실시 간 다각형 굴절 을 실현 합 니까?

머리말
본 튜 토리 얼 에서 Three.js 를 사용 하여 세 단계 에서 대상 을 유리 처럼 보이 게 하 는 방법 을 배 울 것 입 니 다.
3D 대상 을 렌 더 링 할 때 특정한 3D 소프트웨어 를 사용 하 든 WebGL 을 사용 하여 실시 간 으로 표시 하 든 항상 재 료 를 분배 하여 보이 고 필요 한 외관 을 가 져 야 합 니 다.
Three.js 와 같은 라 이브 러 리 에 있 는 기 존 프로그램 을 사용 하여 여러 종류의 재 료 를 모방 할 수 있 습 니 다.그러나 본 튜 토리 얼 에서 저 는 세 개의 대상(세 단계)을 어떻게 사용 하여 대상 을 유리 처럼 보이 게 하 는 지 보 여 드 리 겠 습 니 다.
STEP 1:설정 과 정면 굴절
이 프레젠테이션 에서 저 는 마름모꼴 기하학 적 도형 을 사용 할 것 입 니 다.그러나 간단 한 상자 나 다른 기하학 적 도형 을 따라 갈 수 있 습 니 다.
우리 의 프로젝트 를 세 웁 시다.우 리 는 렌 더러,장면,투시 카메라 와 우리 의 기하학 적 도형 이 필요 하 다.우리 의 기하학 적 도형 을 과장 하기 위해 서 우 리 는 그것 을 위해 소 재 를 분배 해 야 한다.이 재 료 를 만 드 는 것 이 본 튜 토리 얼 의 주요 중점 입 니 다.따라서 기본 정점 과 세 션 착색 기 를 가 진 새 Shader Material 을 계속 만 듭 니 다.
당신 이 기대 하 는 것 과 반대로 우리 의 재 료 는 투명 하지 않 을 것 입 니 다.실제로 우 리 는 다이아몬드 뒤의 모든 것 을 샘플링 하고 변형 시 킬 것 입 니 다.이 를 위해 서 는 장면(마름모꼴 없 음)을 무늬 로 과장 해 야 한다.나 는 단지 정교 한 카 메 라 를 사용 하여 전체 화면의 평면 을 과장 할 뿐 이지 만 이것 은 다른 대상 이 가득 한 장면 일 수도 있다.Three.js 에서 마름모꼴 에서 배경 기하학 적 도형 을 분할 하 는 가장 간단 한 방법 은'그림 층'을 사용 하 는 것 이다.

this.orthoCamera = new THREE.OrthographicCamera( width / - 2,width / 2, height / 2, height / - 2, 1, 1000 );
// assign the camera to layer 1 (layer 0 is default)
this.orthoCamera.layers.set(1);

const tex = await loadTexture('texture.jpg');
this.quad = new THREE.Mesh(new THREE.PlaneBufferGeometry(), new THREE.MeshBasicMaterial({map: tex}));

this.quad.scale.set(width, height, 1);
// also move the plane to layer 1
this.quad.layers.set(1);
this.scene.add(this.quad);
우리 의 렌 더 링 순환 은 다음 과 같다.

this.envFBO = new THREE.WebGLRenderTarget(width, height);

this.renderer.autoClear = false;

render() {
    requestAnimationFrame( this.render );

    this.renderer.clear();

    // render background to fbo
    this.renderer.setRenderTarget(this.envFbo);
    this.renderer.render( this.scene, this.orthoCamera );

    // render background to screen
    this.renderer.setRenderTarget(null);
    this.renderer.render( this.scene, this.orthoCamera );
    this.renderer.clearDepth();

    // render geometry to screen
    this.renderer.render( this.scene, this.camera );
};
좋아,이제 이론 을 좀 써 야 겠 어.투명 재료(예 를 들 어 유리)는 구 부 릴 수 있 기 때문에 볼 수 있다.그것 은 빛 이 유리 에서 전파 되 는 것 이 공기 중의 전파 보다 느 리 기 때문에 광파 가 일정한 각도 로 유리 물체 에 부 딪 힐 때 이런 속도 변 화 는 광파 의 방향 을 바 꿀 수 있다.파도 방향의 이런 변 화 는 굴절 현상 을 묘사 하 였 다.

코드 에서 이 점 을 복사 하기 위해 서 는 우리 의 눈 벡터 와 세계 공간 에서 다이아몬드 표면(법 선)벡터 간 의 각 도 를 알 아야 할 것 이다.이 벡터 들 을 계산 하기 위해 정점 착색 기 를 업데이트 합 시다.

varying vec3 eyeVector;
varying vec3 worldNormal;

void main() {
    vec4 worldPosition = modelMatrix * vec4( position, 1.0);
    eyeVector = normalize(worldPos.xyz - cameraPosition);
    worldNormal = normalize( modelViewMatrix * vec4(normal, 0.0)).xyz;
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
세 션 착색 기 에서 eyeVector 와 WorldNormal 을 glsl 내 장 된 굴절 함수 의 앞 두 매개 변수 로 사용 할 수 있 습 니 다.세 번 째 매개 변 수 는 굴 절 률 의 비율,즉 우리 의 빠 른 매체(공기)의 굴 절 률(IOR)을 우리 의 느 린 매체(유리)의 IOR 로 나 누 는 것 이다.이 경우 이 값 은 1.0/1.5 이지 만 필요 한 결 과 를 얻 기 위해 이 값 을 조정 할 수 있 습 니 다.예 를 들 어 물의 IOR 은 1.33 이 고 다이아몬드 의 IOR 은 2.42 이다.

uniform sampler2D envMap;
uniform vec2 resolution;

varying vec3 worldNormal;
varying vec3 viewDirection;

void main() {
    // get screen coordinates
    vec2 uv = gl_FragCoord.xy / resolution;

    vec3 normal = worldNormal;
    // calculate refraction and add to the screen coordinates
    vec3 refracted = refract(eyeVector, normal, 1.0/ior);
    uv += refracted.xy;
    
    // sample the background texture
    vec4 tex = texture2D(envMap, uv);

    vec4 output = tex;
    gl_FragColor = vec4(output.rgb, 1.0);
}

정말 좋다!우 리 는 굴절 착색 기 를 성공 적 으로 만 들 었 다.그러나 우리 의 다이 아몬드 는 거의 보이 지 않 는 다.일부 원인 은 우리 가 유리의 시각 적 특성 만 처 리 했 기 때문이다.모든 빛 이 굴절 할 재 료 를 통과 하 는 것 은 아니 지만,실제로 일부 빛 은 반사 된다.그것 을 어떻게 실현 하 는 지 보 여 주세요!
STEP 2:반사 와 프 레이 넬 방정식
간단하게 보기 위해 서 본 튜 토리 얼 에서 우 리 는 적당 한 반 사 를 계산 하지 않 고 흰색 만 반사광 으로 사용 할 것 이다.지금 우 리 는 언제 반성 해 야 할 지,언제 굴절 해 야 할 지 어떻게 압 니까?이론 적 으로 이것 은 재료 의 굴 절 률 에 달 려 있다.입사 벡터 와 표면 법 선 간 의 각도 가 임계 각 보다 크 면 광 파 는 반사 된다.

세 션 착색 기 에서 우 리 는 피 넬 방정식 을 사용 하여 반사 광선 과 굴절 광선 간 의 비율 을 계산 할 것 이다.불 행 히 도 glsl 에 도 이 방정식 이 내장 되 어 있 지 않 지만 여기에서 복사 할 수 있 습 니 다.

float Fresnel(vec3 eyeVector, vec3 worldNormal) {
    return pow( 1.0 + dot( eyeVector, worldNormal), 3.0 );
}
이제 우 리 는 방금 계 산 된 프 레이 넬 비 에 따라 굴절 무늬 의 색깔 과 흰색 반사 색 을 간단하게 혼합 할 수 있다.

uniform sampler2D envMap;
uniform vec2 resolution;

varying vec3 worldNormal;
varying vec3 viewDirection;

float Fresnel(vec3 eyeVector, vec3 worldNormal) {
    return pow( 1.0 + dot( eyeVector, worldNormal), 3.0 );
}

void main() {
    // get screen coordinates
    vec2 uv = gl_FragCoord.xy / resolution;

    vec3 normal = worldNormal;
    // calculate refraction and add to the screen coordinates
    vec3 refracted = refract(eyeVector, normal, 1.0/ior);
    uv += refracted.xy;

    // sample the background texture
    vec4 tex = texture2D(envMap, uv);

    vec4 output = tex;

    // calculate the Fresnel ratio
    float f = Fresnel(eyeVector, normal);

    // mix the refraction color and reflection color
    output.rgb = mix(output.rgb, vec3(1.0), f);

    gl_FragColor = vec4(output.rgb, 1.0);
}

많이 좋아 진 것 같 지만 아직 부족 한 점 이 있 습 니 다............................................................이 문 제 를 해결 합 시다!
STEP 3:다 중 굴절
지금까지 우 리 는 반사 와 굴절 에 관 한 지식 을 알 게 되 었 다.우 리 는 대상 을 떠 나 기 전에 대상 내 부 를 몇 번 씩 반등 할 수 있다 는 것 을 이해 할 수 있다.
물리 적 으로 정확 한 결 과 를 얻 기 위해 서 는 모든 빛 을 추적 해 야 하지만 불행 하 게 도 이런 계 산 량 이 너무 많아 서 실시 간 으로 렌 더 링 할 수 없다.그래서 저 는 당신 에 게 간단 한 유사 치 를 보 여 드 리 겠 습 니 다.적어도 우리 다이아몬드 의 뒷면 을 직관 적 으로 볼 수 있 습 니 다.
세 션 착색 기 에서 우 리 는 기하학 적 도형 의 정면 과 뒷면 의 세계 법 선 이 필요 하 다.우 리 는 양쪽 을 동시에 렌 더 링 할 수 없 기 때문에 먼저 뒷면 의 법 선 을 무늬 로 렌 더 링 해 야 한다.

1 단계 에서 처럼 새로운 Shader Material 을 만 듭 시다.하지만 이번 에는 세계 법 선 을 gl 로 과장 합 니 다.FragColor。

varying vec3 worldNormal;

void main() {
    gl_FragColor = vec4(worldNormal, 1.0);
}
다음 에 우 리 는 뒷면 통 로 를 포함 하여 렌 더 링 순환 을 업데이트 할 것 이다.

this.backfaceFbo = new THREE.WebGLRenderTarget(width, height);

...

render() {
    requestAnimationFrame( this.render );

    this.renderer.clear();

    // render background to fbo
    this.renderer.setRenderTarget(this.envFbo);
    this.renderer.render( this.scene, this.orthoCamera );

    // render diamond back faces to fbo
    this.mesh.material = this.backfaceMaterial;
    this.renderer.setRenderTarget(this.backfaceFbo);
    this.renderer.clearDepth();
    this.renderer.render( this.scene, this.camera );

    // render background to screen
    this.renderer.setRenderTarget(null);
    this.renderer.render( this.scene, this.orthoCamera );
    this.renderer.clearDepth();

    // render diamond with refraction material to screen
    this.mesh.material = this.refractionMaterial;
    this.renderer.render( this.scene, this.camera );
};
지금 우 리 는 굴절 재료 에서 뒷면 의 법 선 무늬 를 채취 하고 있다.

vec3 backfaceNormal = texture2D(backfaceMap, uv).rgb;
마지막 으로 우 리 는 정면 과 뒷면 의 법 선 을 결합 시 켰 다.

float a = 0.33;
vec3 normal = worldNormal * (1.0 - a) - backfaceNormal * a;
이 등식 에서 a 는 하나의 스칼라 값 일 뿐 뒷면 법 선 을 사용 해 야 하 는 수량 을 가리킨다.

우리 해 냈어!우 리 는 다이아몬드 의 모든 측면 을 볼 수 있다.단지 우리 가 다이아몬드 의 재질 에 대해 굴절 과 반 사 를 했 기 때문이다.
제한성
내 가 이미 설명 한 바 와 같이 이런 방법 으로 물리 적 으로 정확 한 투명 재 료 를 실시 간 으로 과장 하 는 것 은 불가능 하 다.서로 앞 에 여러 개의 유리 대상 을 과장 할 때 또 다른 문제 가 발생 한다.우 리 는 환경 을 한 번 만 샘플링 하기 때문에 일련의 대상 을 꿰 뚫 어 볼 수 없다.마지막 으로 제 가 여기 서 보 여 드 린 화면 공간 은 캔버스 의 가장자리 근처에 굴절 되 어 효과 가 좋 지 않 습 니 다.빛 이 경계 밖의 값 으로 굴절 되 고 배경 장면 을 렌 더 링 목표 에 렌 더 링 할 때 이 데 이 터 를 포착 하지 못 했 기 때 문 입 니 다.
물론 이러한 제한 을 극복 할 수 있 는 여러 가지 방법 이 있 지만 WebGL 에서 실시 간 으로 렌 더 링 을 하 는 것 이 모두 좋 은 해결 방안 이 아 닐 수도 있 습 니 다.
이상 은 어떻게 threejs 로 실시 간 다각형 굴절 을 실현 하 는 지 에 대한 상세 한 내용 입 니 다.JS 라 이브 러 리 에 관 한 자 료 는 저희 의 다른 관련 글 에 관심 을 가 져 주 십시오!

좋은 웹페이지 즐겨찾기