번역 Three.js는 WebGL을 통해 JavaScript가 GPU를 작동하고 브라우저 측에서 진정한 3D를 구현할 수 있게 해주는 훌륭한 오픈 소스 WebGL 라이브러리입니다. 하지만 이 기술은 아직 개발 단계이고 정보가 극히 부족합니다. 매니아들은 기본적으로 Demo 소스 코드와 Three.js 자체의 소스 코드를 통해 배워야 합니다.
소개 이전 튜토리얼을 읽지 않았다면 이 튜토리얼을 읽어보는 것이 좋습니다. 이전 튜토리얼.
이전 글 말미에 화면 중앙에 아름다운 핑크색 구체를 그렸습니다. 이제 좀 더 흥미로운 것을 만들기 시작하겠습니다.
이 튜토리얼에서는 잠시 애니메이션 루프를 추가한 다음 정점 속성 변수와 균일 변수를 추가하겠습니다. 또한 정점 셰이더가 조각 셰이더에 정보를 전달할 수 있도록 다양한 변수를 추가해야 합니다. 최종 결과는 위에서 옆으로 "점화"된 다음 규칙적인 패턴으로 움직이는 분홍색 구체입니다. 이것은 약간 환각적이지만 셰이더의 세 가지 변수를 더 잘 이해하는 데 도움이 됩니다. 이 세 변수는 서로 관련되어 있으며 전체 어셈블리를 구현합니다. 물론 우리는 Three.js 프레임워크에서 이 작업을 수행할 것입니다.
1. 조명 시뮬레이션 구가 평평하고 어두운 원처럼 보이지 않도록 색상을 업데이트해 보겠습니다. Three.js가 조명을 처리하는 방법을 알고 싶다면 필요한 것보다 훨씬 더 복잡하다는 것을 알게 될 것이므로 먼저 조명을 시뮬레이션해 보겠습니다. Three.js의 환상적인 셰이더뿐만 아니라 Chris Milk와 Google, Rome의 최근 WebGL 프로젝트도 살펴보세요.
셰이더로 돌아가서 정점 법선 벡터를 프래그먼트 셰이더에 전달하려면 정점 셰이더를 업데이트해야 합니다. 다양한 변수 사용:
// 가변 변수 vNormal, 정점 셰이더와 프래그먼트 셰이더 모두 이 변수를 포함합니다.
varying vec3 vNormal;
void main() {
// vNormal을 Normal로 설정합니다. 이는 Three.js에서 생성되어 전달됩니다. 셰이더의 속성 변수
vNormal = Normal;
gl_Position =projectionMatrix *
modelViewMatrix *
vec4(position, 1.0);
조각 셰이더에서 같은 이름의 변수를 만든 다음 법선 벡터에 오른쪽 상단의 광선을 나타내는 다른 벡터를 점곱하고 그 결과를 색상에 적용합니다. 최종 결과는 방향성 조명과 약간 비슷해 보입니다.
// 정점 셰이더
varying vec3 vNormal;
void main() {
// 조명 벡터 정의
vec3 light = vec3(0.5,0.2,1.0)// Normalized
light = Normalize(light);
// 빛 벡터와 법선 벡터의 내적을 계산합니다. 내적이 0보다 작으면(즉, 빛이 도달할 수 없음) 설정합니다. to 0
float dProd = max(0.0, dot(vNormal, light));
// 조각 색상 채우기
gl_FragColor = vec4(dProd, // R
dProd, // G
dProd, // B
1.0) ; // A
}
내적을 사용하는 이유는 두 벡터의 내적을 통해 두 벡터가 얼마나 "유사"한지를 보여주기 때문입니다. 두 벡터가 정규화되고 방향이 정확히 같으면 내적 값은 1입니다. 두 벡터의 방향이 정확히 반대이면 내적 값은 -1입니다. 우리가 하는 일은 섬유에 내적 값을 적용하는 것입니다. 따라서 이 점이 구의 오른쪽 상단에 있으면 내적 값은 1입니다. 이는 완전히 조명된다는 의미이며, 반대쪽 점의 경우에는 다음과 같습니다. 우리는 내적 값이 0 또는 심지어 -1에 가깝다는 것을 얻습니다. 우리가 얻는 음수 값은 0으로 설정됩니다. 데이터를 전달하면 가장 기본적인 조명 효과를 볼 수 있습니다.
아래는 무엇인가요? 정점의 좌표를 통합하겠습니다.
2. 속성 변수
다음으로 Attribute 변수를 통해 각 정점에 난수를 전달해야 합니다. 이 난수는 정점을 법선 벡터를 따라 특정 거리만큼 밀어내는 데 사용됩니다. 새로운 결과는 페이지를 새로 고칠 때마다 무작위로 변경되는 이상하고 불규칙한 개체와 비슷합니다. 지금은 그는 움직이지 않을 것입니다(나중에 움직이게 할 것입니다). 몇 번 새로 고침을 하고 나면 그의 모양이 임의적이라는 것을 잘 알 수 있습니다. 버텍스 셰이더에 속성 변수를 추가해 보겠습니다.
코드 복사 코드는 다음과 같습니다.
속성 부동 변위;
varying vec3 vNormal;
void main() {
vNormal = Normal;// 임의의 숫자 변위를 3차원 벡터로 변환합니다. 법선은 곱해진다
vec3 newPosition = position
normal * vec3(displacement);
gl_Position =projectionMatrix *
modelViewMatrix *
vec4(newPosition, 1.0); 🎜>}
속성 변수 변위가 아직 설정되지 않았으므로 셰이더가 기본값으로 0을 사용하므로 변경된 사항이 없습니다. 현재 Displacement는 아직 적용되지 않았지만 곧 셰이더 머티리얼에 속성 변수를 추가할 예정이며 그러면 Three.js가 자동으로 이들을 묶어 실행합니다.
모든 속성 변수와 마찬가지로 원래 위치 변수도 읽기 전용이기 때문에 업데이트된 위치를 새로운 3차원 벡터 변수에 할당했다는 사실도 참고하세요.
3. 셰이더 재질 업데이트
이제 셰이더 재질을 업데이트하고 속성 객체 변위에 무언가를 전달합니다. 속성 개체는 정점에 일대일로 대응하므로 다음과 같이 구의 각 정점에 대한 값을 갖습니다.
var attribute = { displacement: {
type: 'f', // 부동 소수점 숫자
value: [] // 빈 배열
}
};
var vShader = $('#vertexshader')
var fShader = $('#fragmentsshader')// 다음을 포함하는 속성을 생성합니다. 셰이더 재질
var ShaderMaterial =
new THREE.MeshShaderMaterial({
attributes: attribute,
vertexShader: vShader.text(),
fragmentShader: fShader.text()
} ) ;
// 임의의 숫자로 변위 채우기
var verts =sphere.geometry.vertices;
var 값 = attribute.displacement.value
for(var v = 0; v < verts.length; v ) {
values.push(Math.random() * 30);
}
이렇게 하면 변형된 구를 볼 수 있습니다. 가장 멋진 점은 이러한 모든 변환이 GPU에서 수행된다는 것입니다.
4. 움직여 보세요
이걸 움직이게 하려면 어떻게 해야 하나요? 음, 이 두 가지를 해야 합니다. 균일한 가변 진폭은 각 프레임의 변위에 의해 발생하는 실제 변위를 제어합니다. 사인 또는 코사인 함수를 사용하여 각 프레임에서 이를 생성할 수 있습니다. 이 두 함수는 -1에서 1까지의 값을 취하기 때문입니다. 프레임 루프.
이 균일 변수를 셰이더 머티리얼에 추가해야 하고, 버텍스 셰이더에도 추가해야 합니다. 먼저 Vertex Shader를 살펴보겠습니다.
속성 부동 변위 vec3 vNormal;
void main() {
vNormal = 정상
// 각 프레임에서 진폭을 부드럽게 변경합니다. , 화면 이동
vec3 newPosition =
position
normal *
vec3(displacement *
amplitude)
gl_Position =projectionMatrix *
modelViewMatrix *
vec4(newPosition , 1.0)
}
그런 다음 셰이더 재질을 업데이트합니다.
amplitude: { type: 'f', // a float
value: 0
}
} ;
var vShader = $('#vertexshader');
var fShader = $('#fragmentshader')
// 최종 셰이더 재료 생성
varshaderMaterial =
new THREE.MeshShaderMaterial({
uniforms: 유니폼,
속성: attribute,
vertexShader: vShader.text(),
fragmentShader: fShader.text()
}); 🎜>
셰이더도 준비되어 있습니다. 하지만 우리는 한걸음 더 뒤로 물러난 것 같고, 화면에는 매끈한 공들만 남았습니다. 걱정하지 마세요. 진폭 값이 0으로 설정되어 있고 진폭에 변위를 곱했으므로 지금은 아무런 변화도 볼 수 없습니다. 아직 루프를 설정하지 않았으므로 진폭은 0만 될 수 있습니다.
자바스크립트에서는 렌더링 프로세스를 함수로 패키징한 다음 requestAnimationFrame을 사용하여 함수를 호출해야 합니다. 이 함수에서는 균일(번역자 주: 진폭) 값을 업데이트합니다.
코드 복사