ted0505
Computational Art & Study
ted0505
전체 방문자
오늘
어제
  • 분류 전체보기 (79)
    • Computer Science ( CS ) (0)
    • Computational Thinking (6)
    • 프로젝트 개발일지 (1)
    • Coding (52)
      • C++ (39)
      • JavaScript (2)
      • P5.JS (7)
      • Python (0)
      • HTML5 (1)
      • CSS (0)
    • Game Engine (18)
      • Unreal Engine 4 (18)
      • Unity (0)
    • Physically Based Rendering (0)
    • FilmMaking (0)
    • 잡다 (0)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
ted0505

Computational Art & Study

< P5.js > Kadenze_Session2_Vector / Forces
Coding/P5.JS

< P5.js > Kadenze_Session2_Vector / Forces

2022. 2. 9. 12:34

Kadenze_Session2_Vector / Forces

 

#01 : Newton's Laws of Motion_뉴턴의 운동법칙

 

  • Force(힘) 은 질량을 지닌 물체를 가속하는 벡터 물리량이다.

 

  1. 제 1의 법칙 ( 관성의 법칙 )
  • 날아가는 화살이 공기저항을 받지않는다면, 같은 방향으로 속도가 변하지 않고 계속 날아갈 수 있듯이, 정지하고 있는 물체는 항상 정지, 운동하는 물체는 항상 같은 속력과 방향으로 운동하려는 것.


  • 힘이 없거나, 물체에 가해지는 힘이 서로 상쇄된다면 즉, 알짜 힘이 0이되면 물체의 속도는 일정하게 유지된다는 것을 ‘평형(epuilibrium)’ 이라고 함

 

*알짜힘은 물체에 가해지는 모든 힘들의 벡터(속력,방향)를 합하여 계산한 것.




 

  • F = MA / 힘은 질량 곱하기 가속.
  • A = F/M /  가속도는 힘과 비례하고, 질량에 반비례함.

즉, 세게 밀면 밀수록 더 빨리 움직이고, 질량이 크면 클수록 더 느리게 움직임. 

 

지난시간에서 Vector를 배운 것에 따르면, 프로그래밍에서의 가속도는 객체의 움직임을 제어하는 핵심적인 요소다.

 

그렇다면, 프로그래밍에서 질량은 어떻게 표현할 수 있을까? 

 

다니엘 쉬프만의 말에 따르면, 픽셀로 처리 할 수 있다고 한다.. 아직까지는 질량을 픽셀로 처리한다는 것이 이해는 되지않지만 어쨌든, 프로그래밍에서 모든 물체들의 질량을 1이라고 생각하면, 

다음과 같은 식이 성립된다. 

가속도는 힘과 같다는 것이다. 즉, 이 힘이라는 것이 모든 객체를 움직인다고 볼 수 있다.

#02 : Adding Forces

 

위에서 볼 수 있듯이, 가속도 = 힘이다. 

이번에는 가장 간단하게 구현 할 수 있는 힘 중에 중력을 프로그래밍에서 구현하여, 마치 지구의 중력과 같이 객체가 중력의 영향을 받아 바닥으로 움직이게 해보자.

 

let ball;

function setup() {
  createCanvas(400, 400);
  ball = new Ball();
}

function draw() {
  background(51);
  
  let gravity = createVector(0, 0.1);
  ball.applyForce(gravity);
  
  ball.update();
  ball.display();
}



function Ball() {
  this.pos = createVector(width/2, height/2);
  this.vel = createVector(0, 0);
  this.acc = createVector(0, 0);
  
  this.applyForce = function(force) {
    this.acc = force;
  }
  
  this.update = function() {
    this.vel.add(this.acc);
    this.pos.add(this.vel);
  }
  
  this.display = function() {
    noStroke();
    ellipse(this.pos.x, this.pos.y, 16, 16);
  }
}

 

  • 질량은 고려하지 않았고, 중력 이외에 다른 힘의 작용은 없다.

 

  • 소스코드에서는 new 생성자와 function 함수를 사용하여 클래스를 만들었는데, 이 방법과 클래스를 이용해 만드는 방법의 차이가 있는지 ? 효율성 ?  이 있는지 궁금함.

 


#03 : Force Accumulation_힘의 축적

 

this.chkEdge = function() {
    if(this.pos.y > height) {
      this.vel.y *= -1;
      this.pos.y = height;
    }
  }

 

바운싱 하는 볼을 표현하는데 왜 위치, 속도, 가속도 중에 속도를 -1 곱하는가? 

  • 볼을 공처럼 튕기기 위해서는 힘이 가해진만큼, 같은 힘으로 튕겨져야 자연스러운 공의 운동을 표현할 수 있기 때문이다.

 

공이 바닥에 닿으면, 현재 속도 5.XX에 -1을 곱하여 -5.XX로 만든다.

그러면 코드에서는 매프레임마다, 중력이라는 힘이 계속 더해지고 있기 때문에, -5에서 0.1이라는 실수가 계속 더해지는 것을 볼 수 있다. 

그렇다면, 이 부분에서의 중력이라는 힘은 물리적 현상이 아닌 것인가..?

현실세계의 물리를 구현하기 위해(그렇게 보이게 하기 위해), 계산한 것뿐인가?

 

update() {
    this.checkEdge(); // 영역인식.
    this.vel.add(this.acc);
    this.pos.add(this.vel);

    this.acc.set(0, 0); // 가속도 초기화.
  }
  • 가속도를 초기화 시키는 이유 : 초기화시키지 않으면 가속도가 계속 증가하며 축적되어, 공이 튕기는 의도를 구현하지 못함.

 

let wind = createVector(0.5, 0);
 let gravity = createVector(0, 0.1);
 ball.applyForce(gravity);
 ball.applyForce(wind);

 

지금까지는 중력이라는 하나의 힘만 적용시켜봤다. 좀 더 현실적으로 만들기 위해, 다른 힘은 어떻게 넣을까? 두 가지 힘을 적용시키기 위해 위와 applyForce() 메소드를 두번 넣어보면, 이상하게도 중력 벡터는 무시하고 새로만든 wind 벡터만 실행된다.

 

왜 마지막 applyForce() 만 호출되고 이전 호출은 무시하고 실행되는가?

그렇다면, 두가지 힘을 함께 적용시키기 위해서는 어떻게 해야하는가?

  • 찾아본바로 F = M*A를 정확하게 말하자면, 알짜 힘은 질량 곱하기 가속도와 같다.
  • 알짜힘은 물체에 가해지는 모든 힘들의 벡터(속력,방향)를 합하여 계산한 것.
  • 즉, 모든 힘들의 벡터를 더해야한다는 것이다.
this.applyForce = function(force) {
    //this.acc = force;
    this.acc.add(force);
  }

두 가지 힘을 적용시키기 위해 가속도 벡터에 gravity 벡터와 wind 벡터의 합을 계산한다.

 


#04 : Adding Mass_질량 더하기

 

지금까지는 객체의 질량을 상관하지 않고 힘을 구현했다. 

각 개별적인 객체에 질량을 더하자면,

위와 같이 가속도 벡터에 힘 / 질량을 해주어야한다.

예로 들자면, this.acc = (force/mass); 이다.

  • 질량은 스칼라 값이다.
this.applyForce = function(force) {
    force.div(this.mass);
    this.acc.add(force);
  }

 

힘을 나누는 메소드가 추가되었다. 하지만 여기서 문제가 있다. 중력이라는 힘은 매프레임마다 0.1씩 이동해야하지만, 힘은 나누어지는 메소드의 반환 값으로 영구적으로 바뀌기 때문에 물리를 구현하기에 문제가 발생한다. / 즉, 기존 힘 벡터에 영향을 주기 때문에 문제 발생.

 

이 같이 기존 힘 벡터에 영향을 주지 않는 방법은 객체를 복사하는 방법.

this.applyForce = function(force) {
    let f = force.copy();
    f.div(this.mass);
    this.acc.add(f);
  }
ellipse(this.pos.x, this.pos.y, this.mass*10, this.mass*10);

질량을 시각화 시키기위해 객체의 부피를 질량 값으로 표현.

 

  • 소스코드 예제
let ball, ball_2;

function setup() {
  createCanvas(400, 400);
  ball = new Ball(300, height/2, 1);
  ball_2 = new Ball(100, height/2, 10);
}

function draw() {
  background(51);
  
  let wind = createVector(0.1, 0);
  
  let gravity1 = createVector(0, 0.2*ball.mass);
  ball.applyForce(gravity1);
  let gravity2 = createVector(0, 0.2*ball_2.mass);
  ball_2.applyForce(gravity2);
  
  if(mouseIsPressed) {
    ball.applyForce(wind);
    ball_2.applyForce(wind);
  }
  
  ball.chkEdge();
  ball.update();
  ball.display();
  
  ball_2.chkEdge();
  ball_2.update();
  ball_2.display();
}
function Ball(x, y, m) {
  this.pos = createVector(x, y);
  this.vel = createVector(0, 0);
  this.acc = createVector(0, 0);
  this.mass = m;
  
  this.applyForce = function(force) {
    let f = force.copy();
    f.div(this.mass);
    this.acc.add(f);
  }
  
  this.chkEdge = function() {
    if(this.pos.y > height) {
      this.vel.y *= -1;
      this.pos.y = height;
    }
    if(this.pos.x > width) {
      this.vel.x *= -1;
      this.pos.x = width;
    }else if(this.pos.x < 0) {
      this.vel.x *= -1;
      this.pos.x = 0;
    }
  }
  
  this.update = function() {
    this.vel.add(this.acc);
    this.pos.add(this.vel);
    
    this.acc.set(0,0);
  }
  
  this.display = function() {
    noStroke();
    ellipse(this.pos.x, this.pos.y, this.mass*10, this.mass*10);
  }
}

 

지금까지 객체에 힘을 구현했고, 질량의 값에 따른 힘도 구현했다.

하지만, 모든 객체를 선언하기에는 소스코드의 줄이 길어지기 때문에 코드의 가독성에 비효율적이다. 그래서, 다음 내용에서는 배열을 활용해 효율적으로 만들어 본다.

 


#05 : Arrays of Particles_배열로 만들기

 

let ball = [];

function setup() {
  createCanvas(400, 400); 
  for(let i=0; i<10; i++) {
    ball[i] = new Ball(random(width), height/2, random(0, 5));
  }
}

function draw() {
  background(51);
  
  let wind = createVector(0.1, 0);
  
  for(let i=0; i<ball.length; i++) {
    let gravity = createVector(0, 0.2*ball[i].mass);
    ball[i].applyForce(gravity);
  
    if(mouseIsPressed) {
      ball[i].applyForce(wind);
    }
  
    ball[i].chkEdge();
    ball[i].update();
    ball[i].display();
  }
}
let ball = [];

function setup() {
  createCanvas(400, 400); 
  for(let i=0; i<10; i++) {
    ball[i] = new Ball(random(width), height/2, random(0, 5));
  }
}

function draw() {
  background(51);
  
  let wind = createVector(0.1, 0);
  
  for(let i=0; i<ball.length; i++) {
    let gravity = createVector(0, 0.2*ball[i].mass);
    ball[i].applyForce(gravity);
  
    if(mouseIsPressed) {
      ball[i].applyForce(wind);
    }
  
    ball[i].chkEdge();
    ball[i].update();
    ball[i].display();
  }
}
function setup() {
  createCanvas(400, 400); 
}

function mousePressed() {
  let b = new Ball(random(width), height/2, random(0, 5));
  ball.push(b);
}

function keyPressed() {
  if(key == ' ') {
    ball.splice(0,1);
  }  
}
  • push(); 함수는 배열 시퀀스에 요소를 추가하는 기능.
  • splice(); 함수는 배열 시퀀스의 가장 처음 생성된 요소부터 삭제하는 기능. 

수업시간에 학습한 것 토대로 수정.

 

자바스크립트는 함수의 인자 값 타입에 민감하지 않음. 때문에 오류가 나지 않더라도, 타입을 잘 생각해서 작성하도록 ~

 

'Coding > P5.JS' 카테고리의 다른 글

< P5.JS > Particle system  (0) 2022.02.09
< P5.JS > 중간창작  (0) 2022.02.09
< P5.JS > The Nature of Code_Vector  (0) 2021.10.04
< P5.JS > 1. P5.JS의 OOP ( Object - Oriented Programming )  (0) 2021.09.14
< P5.JS > 10 print_코드 분석으로 작동 원리 이해와 재해석  (0) 2021.09.11
    'Coding/P5.JS' 카테고리의 다른 글
    • < P5.JS > Particle system
    • < P5.JS > 중간창작
    • < P5.JS > The Nature of Code_Vector
    • < P5.JS > 1. P5.JS의 OOP ( Object - Oriented Programming )
    ted0505
    ted0505

    티스토리툴바