정보실

웹학교

정보실

javascript Javascript 140 문자로 3D 터널 효과를 구현하는 방법

본문

오늘 우리는 이 놀라운 3D 터널 효과 뒤에 있는 JavaScript 코드를 살펴볼 것입니다. 

이 코드에는 흥미로운 계보가 있으므로 그 뒤에 숨겨진 일부 역사에 대해서도 이야기하겠습니다.


http://frankforce.com/?p=7160#shattered 


for(c.width|=k=i=960;z=--i;x.fillStyle=`hsl(0 99%${i/9}%`)x.fillRect(k-z*C(j=i/k+t/4)+S(m=k*j)*(r=1e5/z),540+C(m)*r-z*S(j),s=3e4/z*S(j*9),s)

작동 방식에 대한 전체 설명을 계속 읽으십시오!


이 트윗의 이야기는 Philippe Deschaseaux의“Strange Crystals”라는 제목의 JS1k 2013에 대한 1021 바이트 데모로 시작됩니다. 그는 그 대회에서 승리했다! 그의 블로그에서 자세한 내용을 읽을 수 있습니다. 다음은 그의 데모에서 나온 짧은 클립입니다. 정식 버전이 더 좋습니다.


몇 년 후 2018 년 BalintCsala의“Strange Crystals v0.140”이 Dwitter에 출판되었습니다. 몇 가지 주요 단순화를 통해 원본 1k 데모를 136 개의 유니 코드 문자에 맞게 만들어진 175 바이트로 줄였습니다!


또 다른 해가 지나자 Keith Clark는 이 제목 없는 트윗을 게시하여 137 바이트로 축소하기 위해 더 많은 양보를 만들었습니다.


https://www.dwitter.net/d/15961


이것은 Keith의 리믹스 버전으로 연결됩니다. 다음은 iframe에서 실시간으로 실행되는 실제 트윗입니다. 코드에 대해 이야기하는 동안 놀 수 있습니다!


 


function u(t) {

  for(c.width|=k=i=960;z=--i;x.fillStyle=`hsl(0 99%${i/9}%`)x.fillRect(k-z*C(j=i/k+t/4)+S(m=k*j)*(r=1e5/z),540+C(m)*r-z*S(j),s=3e4/z*S(j*9),s)

}// 140/140


항상 그렇듯이 첫 번째 단계는 코드를 보다 쉽게 ​​읽을 수 있도록 형식을 다시 지정하는 것입니다. 

여기에 공백을 추가하고 몇 가지를 움직여서 그렇게 했습니다. 

또한 X 축과 Y 축 사이의 대칭을 표시하기 위해 추가 공간을 추가했습니다.


그렇게 하는 동안 z 변수가 완전히 흔적이 있고 i로 안전하게 대체 할 수 있음을 알았으므로 다른 2 바이트를 단순화하고 저장했습니다.


for( c.width|= k=i=960; --i; )               // clear & loop
x.fillStyle = `hsl(0 99%${ i/9 }%`, // color
x.fillRect( // draw rect
k + S(j=i/k+t/4)*i + S(m=k*j)*(r=1e5/i), // X axis
540 + C(j )*i + C(m )* r, // Y axis
s = 3e4/i * S(j*9), s) // width, height

코드의 구조가 이해하기 쉽게 되었으므로 상호 작동에 대해 이야기 할 수 있습니다. 맞춤 자바 스크립트 편집기 CapJS에서이 코드를 열 수 있는 링크가 있습니다. 위의 iframe에서 코드를 편집 한 다음 조금 더 사용자 친화적입니다.


한 번에 한 줄씩 나누어 봅시다…


for( c.width|= k=i=960; --i; )  // clear & loop

먼저 터널의 각 사각형 그리기를 처리하는 for 루프를 설정해야 합니다. 우리는 루프 변수 i를 사용할 것입니다.이 변수는 각 사각형으로부터의 거리가 카메라와 같다고 생각할 수 있습니다.


c.width | = 문은 dwitter에 의해 생성 된 캔버스 c를 지 웁니다. 해상도를 1920에서 1984 픽셀로 변경하면 비교적 무해한 부작용이 있는 960으로 비트 단위 또는 할당을 수행하여 이를 수행합니다. 

Dwitter는 가로 세로 비율이 고정 된 상태로 높이를 자동으로 조정합니다.


너비를 변경하지 않으려면 별도의 줄에서 c.width | = 0을 수행 할 수 있지만 더 많은 공간이 필요합니다. 

이것은 가능한 최소 바이트를 사용하여 캔버스를 지우는 일반적인 코드 골프 기술입니다.


k와 루프 인덱스 i는 모두 960으로 초기화됩니다. 값 960은 여러 번 사용되므로 공간을 절약하기 위해 변수 k에 저장됩니다. 

반복이 반복 될 때마다 루프 변수 i를 감소 시키고 루프가 0이 되면 루프를 멈추고 싶기 때문에 이것을 루프 조건으로 사용합니다. 


x.fillStyle = `hsl(0 99%${ i/9 }%`,

여기는 dwitter가 만든 캔버스 컨텍스트 x에서 fillStyle을 설정하여 각 사각형의 색상을 제어하는 ​​곳입니다.


루프 변수 i를 완전히 포화 된 붉은 색조를 가진 hsl 색상의 밝기 매개 변수에 연결하면 흰색에서 빨간색에서 검은 색으로 멋진 그라데이션이 생성됩니다. 우리가 9로 나누면 960에서 시작하고 960/9는 약 100이며 완전히 흰색입니다.


흰색에서 페이드를 시작하면 기본 흰색 캔버스로 안개 효과가 발생하여 터널이 멀리서 부드럽게 페이드 인됩니다.


hsl 색상 문자열은 쉼표 나 닫는 괄호가 필요하지 않도록 몇 가지 축소 트릭과 함께 악센트 부호 문자를 사용하여 문자열 템플릿 리터럴로 작성됩니다. 일부 브라우저에서는 이 기술이 작동하지 않을 수 있습니다.


x.fillRect(

이 장면의 기본 구성 요소는 x.fillRect이며 방금 설정 한 색상으로 캔버스 컨텍스트 x에 사각형을 그리는 데 사용할 것입니다.


k + S(j=i/k+t/4) * i + S(m=k*j) * (r=1e5/i),  // X axis

이 코드는 가장 까다로운 코드이므로 더 자세히 설명하겠습니다.


k // center on X axis

k (960으로 설정)를 사용하여 1920 픽셀 너비 캔버스 중앙에 배치합니다. 글쎄, 앞에서 언급 했듯이 기술적으로 캔버스의 너비는 1984 픽셀이지만 정확한 중심에 있을 필요는 없습니다. 내가 아무 말도 하지 않았다면 눈치 채지 못할 것입니다!


+ S(j=i/k+t/4) * i // tunnel curve

이 문장은 시간이 지남에 따라 터널 곡선을 직진하는 대신 계속 만듭니다. 사인 함수 S를 사용하면 터널에 나선형의 곡선이 생깁니다.


먼저 i를 k로 나눠 0과 1 사이에서 정규화 합니다. 시간이 지남에 따라 변경되도록 하려면 함수에 전달되는 시간 변수 t를 추가 할 수 있습니다. 움직임을 늦추기 위해 t를 4로 나눕니다.

tunnel-5.gif 


사인 함수의 결과는 -1과 1 사이에 있으므로 더 크게 만들고 더 많이 곡선을 만들려면 i로 스케일링 해야 합니다. 오른쪽의 애니메이션은 곡선이 없는 모습을 보여줍니다.


이 값은 사인으로 전달되어 임시 변수 j에 저장되므로 다음 부분과 Y 축에 재사용 할 수 있습니다.


+ S(m=k*j) // tunnel wall

이 부분은 약간의 수학 마법으로 터널의 원형 벽을 만드는 것입니다. 이해를 돕기 위해 960 * (i / 960 + t / 4)를 얻기 위해 초기부터 k와 j를 대입하여 기본 대수를 문 k * j에 적용해야 합니다. 960을 배포하면 i + 240 * t로 줄어 듭니다. 이것은 i + 4 * 60 * t로도 쓸 수 있습니다. 이는 여전히 우리가 시작한 k * j와 같습니다.


tunnel-4-4.gif 


전체 퍼즐의 열쇠이기 때문에 60 * t에 주의 하십시오! 프레임 속도는 60fps이므로 터널이 회전하지 않도록 60을 곱해야 합니다. 오른쪽의 애니메이션은 이 값이 60에서 61로 조금 변경 될 때 효과가 완전히 다르게 보이는 방식을 보여줍니다. 여기에 1을 추가하면 왜 프레임 당 4/60 라디안이 반을 넘게 회전하는지 이해할 수 있는지 확인하십시오 초당 돌리십시오.


다시 결과는 Y 축에 대한 임시 변수 m에 저장됩니다.


* (r=1e5/i), // tunnel wall radius

여기에 원근감 효과를 적용하여 카메라에서 튜브가 확장 될 때 1e5 / i를 곱하여 튜브가 작게 보이도록 합니다. 걱정하지 마십시오. 루프가 0에 도달하기 전에 종료되므로 0으로 나누지 않습니다! 이 부분을 스크린에 투사 할 때 튜브의 겉보기 반경으로 생각할 수 있습니다.


tunnel-13.gif 


이 값 1e5 (100000)를 늘리면 오른쪽의 애니메이션에서 처럼 튜브가 더 넓어집니다. e5는 과학적 표기법으로 10에서 5의 거듭 제곱을 곱하여 매우 크거나 작은 코드로 표현하는 방법입니다.


세 번째이자 마지막으로 결과를 Y 축에 대한 임시 변수 r에 저장합니다.


540 + C(j)*i + C(m)*r,  // Y axis

X 축을 완성 했으므로 Y 축이 쉽습니다. 캔버스는 키가 1080 픽셀이므로 상수 540을 사용하여 중심에 두고 사인 S를 코사인 C로 바꾸는 동안 모든 임시 변수 j, m 및 r을 연결합니다.


X와 Y 축에 사인과 코사인을 사용하면 다른 모든 것과 동일하게 이 터널과 같은 원과 나선형 모양을 만들 수 있습니다.


s = 3e4/i * S(j*9), s) // width, height

여기에서 사각형의 크기를 제어합니다. 첫 번째 부분 3e4 / i는 위치와 유사한 원근 변환을 적용하므로 i가 증가함에 따라 사각형이 작아집니다.


마침내 우리는 터널의“산산이 부서진”부분에 도착했습니다. 오른쪽의 애니메이션은 산산조각이 나지 않은 모습을 보여 주며 사각형의 크기가 줄어들어 터널의 형태가 더 잘 보입니다.


tunnel-10.gif 


S (j * 9)를 적용하면 시간이 지남에 따라 정사각형의 크기가 사인 곡선에 따라 달라 지므로 앞으로 앞부분까지 볼 수 있는 흥미로운 간격이 생깁니다. 간격을 더 좁히기 위해 j를 9로 조정합니다. 모양을 변경하기 위해 다른 값을 선택할 수 있습니다. 이 결과는 변수에 저장되므로 너비와 높이 모두로 사용하고 사각형을 그릴 수 있습니다.


마지막으로 트윗에 대한 전체 코드를 살펴 보겠습니다. 이전보다 개선 된 기능은 총 138 바이트에 불과합니다.

for(c.width|=k=i=960;--i;x.fillRect(k+S(j=i/k+t/4)*i+S(m=k*j)*(r=1e5/i),540+C(j)*i+C(m)*r,s=3e4/i*S(j*9),s))x.fillStyle=`hsl(0 99%${i/9}%`

그것은 우리를 다른 해부의 끝으로 데려갑니다! 계속해서 코드를 가지고 놀고 자신만의 창작물을 만드십시오. 당신이 이것을 읽는 것을 즐겼다면, 당신의 지원을 보여주는 가장 좋은 방법은 트위터 @KilledByAPixel에서 나를 따라 오는 것입니다. 항상 새로운 멋진 창의적인 코드를 게시합니다!


더 작은 리믹스로 105 바이트 만 남겨 두겠습니다. 폭발적인 초신성처럼 보이는 것을 만들고 싶었습니다. 당신은 매우 기쁘다. 내가 어떻게 1 초 루프를 만들었는지 궁금 할 것이다. 좋은 질문이지만 비밀을 유지해야 한다. 다음에 또 만나요!



  • 트위터로 보내기
  • 페이스북으로 보내기
  • 구글플러스로 보내기
  • 카카오톡으로 보내기

페이지 정보

조회 31회 ]  작성일19-11-10 12:56

웹학교