상세 컨텐츠

본문 제목

시베리안 허숙희의 자바스크립트 비기닝 31 (3D 움직임 맛보깅...)

자바스크립트

by e7e 2023. 6. 28. 17:05

본문

오늘은 한 템포 쉬어가는 느낌으로 잠시 3D 맛을 보고 가려한당.

괘니 뭔가 있어보이게  지식있게 보이려고 정리한 노력이 아래 결과이다.~~

그래픽 카드 비용이 조금 비싸긴 하지만  일상적으로  3D게임을 즐기는 사람도 많고,
유투브 영상 중에도 가상현실(VR)을 담고 있는 영상이 지속적으로 올라올 정도로 IT기술의 흐름은
사용자 인터페이스를 점점 3D쪽으로 몰아가고 있는 듯 보인당.

웹에서도 환경상 성능의 문제가 있었지만 오래전 부터 페이지에 3D를 담는 기술이 있어 왔당.

일찍이 Apple사의 제안으로 표준기술로 웹페이지에서 3D를 표현하려는 노력이 있어왔공, 
CSS의 3D 설정 속성과 자바스크립트를 이용하면 3D를 표현 하고 여기에 움직임까지 더 할 수 있땅.
참고로 웹페이지에서 3D를 표현하기 위한  three.js 3D전용 자바스크립트 라이브러리도 있따앙.

 

사실 우리는 3D 세상에 살고 있지만, 물건을 돌려보지 않고 머릿속으로 X축으로 30도, Z축으로 45도

돌리면 어떤 모양이 됩니까? 라는 질문에 바로 답하기가 아주 어려울 거시당.

머릿속에 그려진다 해도 표현이 만만치 않당!  당신앞의 그녀는 그냥 고개만 끄덕일 수도 있당.
직접 물건을 손에 들고 회전시켜 보여주는 것이 유리하당.

곧 3D는 직접 보면서 하는 게 결국 가장 편하다는 이야기인 거시당. 


3D를 이해하려면 먼저 3D 좌표계를 이해 해야 하는데 아래 한번 그냥 읽는당.

웹페이지에서 X축은 왼쪽에서 오른쪽으로 쯩가.
웹페이지에서 Y축은 위에서 아래로 쯩가. 학교에서 배운거랑 반대죠!
웹페이지에서 Z축은 모니터 뒷면에서 전면으로(곧 튀어나오는 방향)으로 증가.

3D관련 용어도 필요한 몇개만 억지로 알아보장.(이상하다 억지로 한게 잘 기억된당!)

상황은 아주 이렇다할 게 없디만 이렇타 할만하당. 

내가 좋아하는 예쁘고 더 더 더 예쁜 블랙핑크 로제가 공연을 한당.
난  3000픽셀 떨어진 곳에서 스마트폰 카메라로 욜씨미 로제를 담고 또 담는당.

1. 로제와 내가 있는 공간 전체를 Stage라고 부르라 한당.(3D용어)
2. 로제가 공연하고 있는 모습을 Scene라고 부르라 한당.(3D용어)
3. 난 카메라를 들고 있으니 Camera라고 불린당.(3D용어)
4. Scene과 Camera가 떨어져 있는 거리를 perspective라고 불린당.(CSS속성)
5. 공간(Stage)안에서 내가 있는 위치(곧 바라보는 위치)를 perspective-origin이라고 한당.(CSS속성)
6. 기본 2D 속성을 가지는 컨텐츠에 3D 속성을 줄 때
     CSS 속성값 transform-style: preserve-3d; 를 사용한당.(CSS속성)

WEB에서 3D의 시작은 정육면체(CUBE) 만들기가 프로그램 시작의 Hello Worl출력에 해당

한가지 주의 및 기억해야 할 것이 있당. 3D로 표현 된 것을 회전 시키면 그 축도 회전하게 된다는 거시당.
곧 좌표계도 같이 회전한당. 좀 머리 아픈 부분이지만 시간을 가지고 실제 결과를 보면서 조정하면
갸꾸로 오히령 뇌의 공간능력을 키울 수 있는 좋은 기회가 될 지도 모른당(나만의 생각!).

justCube.html을 아래 코드로 맹글공 결과를 보장. (아래 처럼 보일 거시당 - 잘했당!!)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Just 큐브</title>
    <style>
        * { box-sizing: border-box; } /* 사이즈에 border를 포함하라는 지정 */
 
 .scene {
   width: 200px;
   height: 200px;
   margin: 180px;
   perspective: 400px;
 }
  
 .cube {
   width: 200px;
   height: 200px;
   position: relative;
   transform-style: preserve-3d;
   transform: translateZ(-100px) rotate3d(1,1,1,45deg);
 }
  
  
 .cube__face {
   position: absolute;
   width: 200px;
   height: 200px;
   border: 2px solid black;
   line-height: 200px;
   font-size: 40px;
   font-weight: bold;
   color: white;
   text-align: center;
   backface-visibility: hidden;
 }
  
 .cube__face--front  { background: rgba(  0, 255, 130, 0.7); }
 .cube__face--right  { background: rgba( 60, 200, 100, 0.5); }
 .cube__face--back   { background: rgba(120, 180, 170, 0.6); }
 .cube__face--left   { background: rgba(180, 200, 200,0.7); }
 .cube__face--top    { background: rgba(240, 250, 150, 0.5); }
 .cube__face--bottom { background: rgba(200, 190, 50, 0.6); }
  
 .cube__face--front  { transform: rotateY(  0deg) translateZ(100px); }
 .cube__face--right  { transform: rotateY( 90deg) translateZ(100px); }  /* y축이 돌아서 z 축도 돔!*/
 .cube__face--back   { transform: rotateY(180deg) translateZ(100px); }
 .cube__face--left   { transform: rotateY(-90deg) translateZ(100px); }
 .cube__face--top    { transform: rotateX( 90deg) translateZ(100px); }
 .cube__face--bottom { transform: rotateX(-90deg) translateZ(100px); }
</style>
</head>
<body>
    <div class="scene">
        <div class="cube">
          <div class="cube__face cube__face--front">전</div>
          <div class="cube__face cube__face--back">후</div>
          <div class="cube__face cube__face--right">우</div>
          <div class="cube__face cube__face--left">좌</div>
          <div class="cube__face cube__face--top">상</div>
          <div class="cube__face cube__face--bottom">하</div>
        </div>
    </div>
</body>
</html>

위에서 설명한 거 외에 transform:rotate와 transform:translate도 알아야  소스가 이해된당.

모르겠다면 질문을 남겨 다알랑!,  위 소스가 이해되었다면 이제 남은 건 재미 재미 뿐이당.

필요한 속성값을 JS로 동적으로 변화를 주면 절로 재미와 관심이 생긴당.

아래 소스는 위 CUBE  소스에, Youtube영상과 이미지를 추가하고, 단지 뺑뺑 돌렸당

 

cube.html (자바스크립트 3d 회전 제어 추가)

[ 분명 자바스크립트 소스만 넣으면, 이거 어디에 넣어야 해요? 질문이 올 것 같아서 

  Full 소스를 자진 납세한단당. 참고로 괘니 백그라운드 영상도 유투브로 넣었당!- 활용? ]

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * { box-sizing: border-box; } /* 사이즈에 border를 포함하라는 지정 */
 
 .scene {
   width: 200px;
   height: 200px;
   margin: 180px;
   perspective: 400px;
 }
  
 .cube {
   width: 200px;
   height: 200px;
   position: relative;
   transform-style: preserve-3d;
   transform: translateZ(-100px);
 }
  
  
 .cube__face {
   position: absolute;
   width: 200px;
   height: 200px;
   border: 2px solid black;
   line-height: 200px;
   font-size: 40px;
   font-weight: bold;
   color: white;
   text-align: center;
   backface-visibility: hidden;
 }
  
 .cube__face--front  { background: rgba(  0, 255, 130, 0.7); }
 .cube__face--right  { background: rgba( 60, 200, 100, 0.5); }
 .cube__face--back   { background: rgba(120, 180, 170, 0.6); }
 .cube__face--left   { background: rgba(180, 200, 200,0.7); }
 .cube__face--top    { background: rgba(240, 250, 150, 0.5); }
 .cube__face--bottom { background: rgba(200, 190, 50, 0.6); }
  
 .cube__face--front  { transform: rotateY(  0deg) translateZ(100px); }
 .cube__face--right  { transform: rotateY( 90deg) translateZ(100px); }  /* y축이 돌아서 z 축도 돔!*/
 .cube__face--back   { transform: rotateY(180deg) translateZ(100px); }
 .cube__face--left   { transform: rotateY(-90deg) translateZ(100px); }
 .cube__face--top    { transform: rotateX( 90deg) translateZ(100px); }
 .cube__face--bottom { transform: rotateX(-90deg) translateZ(100px); }
 #backMovie {
    position: fixed;
    left:0px; top:0px;
    width:100%; height: 100%;
 }
</style>
</head>
<body>
    <!-- 밑바닥에 유투브 동영상 깔깅! -->
    <div id="backMovie">
    </div>
    <div class="scene">
        <div class="cube">
          <div class="cube__face cube__face--front">전</div>
          <div class="cube__face cube__face--back">후</div>
          <div class="cube__face cube__face--right">우</div>
          <div class="cube__face cube__face--left">좌</div>
          <div class="cube__face cube__face--top">상</div>
          <div class="cube__face cube__face--bottom">하</div>
        </div>
    </div>
<script>
    const signals = ["c6rP-YP4c5I","VQtonf1fv_s","J3VZ78hWhQw","wH1KLiYD8vE","ko2Dub0-TzU","8YnCCsrrBXE","DhD7ddGQJzE"];
    const movies = [];
    const bpImgs = [
        "https://pbs.twimg.com/media/E1zDSoQUUAIA5Z2.jpg",
        "https://zzbang.dcinside.com/blackpink_temp.jpg",
        "https://dimg.donga.com/wps/SPORTS/IMAGE/2021/05/24/107079720.1.jpg",
        "https://thumb.mt.co.kr/06/2020/12/2020122822404367240_1.jpg/dims/optimize/",
        "https://thumb.mtstarnews.com/06/2023/01/2023012910372689374_1.jpg/dims/optimize",
        "https://image.ytn.co.kr/general/jpg/2022/0228/202202281325208959_d.jpg"
    ] 

    for(let i=0; i < signals.length; i++){
        let uIfr ="";
        if(i== (signals.length-1)){
            uIfr = `
                <iframe width="100%" height="100%" 
                    src="https://www.youtube.com/embed/${signals[i]}?autoplay=1&mute=1" 
                    title="Who are you? batman?" 
                    frameborder="0" allow="accelerometer; autoplay; 
                    clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen>
                </iframe>
            `;
        }else {
            uIfr = `
                <iframe width="200" height="200" 
                    src="https://www.youtube.com/embed/${signals[i]}?autoplay=1&mute=1" 
                    title="Shakira - Try Everything (Official Video)" 
                    frameborder="0" allow="accelerometer; autoplay; 
                    clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen>
                </iframe>
            `;
        }
        movies.push(uIfr);
    }

    // 백그라운드 동영상 돌리깅 - 그냥 재미!
    const myBackMovie = document.querySelector("#backMovie")
    function fBackLoop(){
        myBackMovie.innerHTML = movies[movies.length-1];
        setTimeout(fBackLoop, (3*60+33)*1000); 
    }
    fBackLoop();
    // 


    const v_scene = document.querySelector(".scene");
    const v_cube = document.querySelector(".cube");
    const v_cube1 = v_cube.cloneNode(true);
    for(let i=0; i<v_cube1.children.length; i++){
        v_cube1.children[i].innerHTML = movies[i];
    }

    const v_cube2 = v_cube.cloneNode(true);
    for(let i=0; i<v_cube2.children.length; i++){
        v_cube2.children[i].innerHTML = "";
        let vImg = document.createElement("img");
        vImg.src = bpImgs[i];
        vImg.width = 195; vImg.height=195;
        v_cube2.children[i].appendChild(vImg);
    }


    v_scene.appendChild(v_cube1);
    v_scene.appendChild(v_cube2);
    v_cube1.setAttribute("style","left:350px;top:-150px");
    v_cube2.setAttribute("style","left:900px;top:-350px");
    let v_gak=0;
  
    function f_rot(){
        const v_cubes = document.querySelectorAll(".cube");
        v_gak = (v_gak % 360) + 3;
        v_cubes[0].style.transform = "rotate3d(1,1,1,"+ v_gak + "deg)";
        v_cubes[1].style.transform = "rotate3d(1,1,0,"+ v_gak + "deg)";
        v_cubes[2].style.transform = "rotate3d(1,0,1,"+ v_gak + "deg)";
        setTimeout(f_rot,100);
    }
 
    window.onload = function(){
        f_rot();
    }
</script>
</body>
</html>

 

나의 경우 아래와 같은 결과를 얻고 말았당. 쪼메 손보고 싶지만, 오늘은 아니당!

실행결과 캡쳐(동영상은 무거워용~~)

 

소스에서 집고 넘어갈 필요가 있는 부분은 유투브 iframe 소스에 보면 

src=" https://www.youtube.com/embed/$ {signals[i]}?autoplay=1&mute=1"  부분이 있는데,

autoplay=1&mute=1을 붙이면 음소거가 되는 대신 영상 자동 스타트가 된당.

Google은 사용자가  원치 않는 소리에 놀라는 걸 원하지 않아서 정책화했다고 한당.

 

cloneNode 메소드도 찝고 넘어갈 필요가 있당. cloneNode() 처럼 사용하면 얕은 복사

(shallow copy)라해서 껍데기(부모)만 복사되고, 자식은 복사 안된당.

cloneNode(true)로 사용하면 깊은 복사(deep copy)라 해서 자식까지 모두 복사된당.

아마 잘 생각해 보면, 유용하게 쓰일 곳이 꽤 많을 거시당. (당신의 창의성이 기대된당!) 

 

 

내가 존재하는 이유를 내 안에서 찾을 수 있을까? 아닌 것 같다.

게임속 캐릭터가 스스로 존재 이유를  알 수 있을까?  ....

산이 산의, 바다가 바다의 존재 이유를 알 수 있을까? ....

 

그냥 밖에서 못 찾으니 안에서 찾으라 하는 것 같다.

안에서도 못 찾겠다 하니 스스로 정하면 어떨까 한당!~~ ㅠㅠ

결국 존재의 이유는 찾는 것이 아니라 결정하는 것일까? 아닌 것 같다.

 

내가 게임속 캐릭터라면, 나의 플레이어는 어디서 보고 있을까?

그는 내 존재의 이유를 부여했을까? 처음엔 했을 것 같당.

시야에서 날 잃어버렸다면, 나의 운명은? 

 

아무래도 존재의 이유는 밖에서 찾는 게 맞는 것 같당!

나이 들어간당. 또 도돌이표 생각에 휘말린당.

이럴 땐 듀엣으로 휘말리면 그나마 덜 서러울 거시당.~~ (^-^)

 

 

https://www.youtube.com/watch?v=Ua3aNDJE_Cg 

 

 

 

 

 

관련글 더보기