목공책 하나 들이셔요~

2014년 4월 14일 월요일

[JavaFX]따라하기#5 - 시각효과와 애니메이션

이 글은 Getting Started with JavaFX 시리즈 중에서 "Animation and Visual Effects in JavaFX"를 번역한 것입니다.
http://docs.oracle.com/javafx/2/get_started/animation.htm


JavaFX를 이용하면 풍부한 사용자 경험을 제공하는 어플리케이션을 빠르고 쉽게 개발할 수 있습니다. 이 튜토리얼에서는 몇 줄 안되는 코드로 움직이는 객체와 복잡한 시각효과들을 어떻게 만드는지 보여 드리겠습니다.

이 튜토리얼을 따라 하면 아래와 같이 멋진 어플리케이션을 만들 수 있습니다.



아래 그림은 이 튜토리얼에서 만들 ColorfulCircles 어플리케이션의 Scene Graph 입니다. 보시면 자식을 가지는 부모 노드는 모두 Group 클래스으 인스턴스임을 알 수 있습니다. 반면 말단 노드(leaf node) 들은 실제 그림을 그리는 Rectangle과 Circle 클래스 들입니다.


어플리케이션 설정하기

NetBeans IDE를 사용하여 다음과 같이 어플리케이션을 만듭니다.

  1. File 메뉴에서 New Project를 선택합니다.
  2. JavaFX 어플리케이션 카테고리에서 JavaFX Application을 선택하고 Next를 클릭합니다.
  3. 프로젝트의 이름을 ColorfulCircles로 변경하고 Finish를 클릭합니다.

프로젝트 셋업

다음과 같은 코드를 쳐 넣습니다. 필요한 import 구문들은 NetBeans IDE에서 제공하는 코드 완성과 자동 임포트 기능을 이용하면 됩니다.

public class ColorfulCircles extends Application { 
    public static void main(String[] args) {
        launch(args);
    }
    
    @Override
    public void start(Stage primaryStage) {
        Group root = new Group();
        Scene scene = new Scene(root, 800, 600, Color.BLACK);
        primaryStage.setScene(scene);

        primaryStage.show();
    }
}

ColorfulCircles 어플리케이션의 경우 루트 노드로 Group을 사용하는 것이 적절합니다. Group의 크기는 그것이 품고 있는 노드의 크기에 의해 결정됩니다. 하지만 대부분의 어플리케이션에서 루트 노드의 크기는 스테이지(윈도우)의 크기를 조절하는 것과 같이 결정되는 것이 보통입니다. 이것을 원할 경우 루트로 크기 조정이 가능한 레이아웃을 지정하는 것이 좋습니다.

이제 ColorfulCircles 어플리케이션이 돌아가게 만들어 놓았으므로 컴파일하여 실행할 수 있습니다. 이어지는 튜토리얼의 내용에서 점진적으로 어플리케이션을 변화시켜 볼 것입니다. 만일 제대로 되지 않는 것 같으면 여기에 전체 소스코드가 있으므로 참고하기 바랍니다. 현재까지는 실행시키면 검은 창만 보입니다.

그래픽 추가하기

이제 다음과 같은 코드를 추가하여 30개의 원을 그립니다. 이 코드는 primaryStage.show() 이전에 위치해야 합니다.

Group circles = new Group();
for (int i = 0; i < 30; i++) {
   Circle circle = new Circle(150, Color.web("white", 0.05));
   circle.setStrokeType(StrokeType.OUTSIDE);
   circle.setStroke(Color.web("white", 0.16));
   circle.setStrokeWidth(4);
   circles.getChildren().add(circle);
}
root.getChildren().add(circles);

위 코드는 circles 라는 이름의 그룹을 만들고 나서, for 루프를 이용하여 30개의 원을 만들어서 이 그룹에 추가합니다. 각 원들의 반지름은 150 이고 흰색으로 채우고, 불투명도는 5% 즉 거의 투명한 상태로 만듭니다.

원 둘레를 따라 경계를 만들기 위해서 StrokeType 클래스를 사용합니다. 이것의 OUTSIDE 타입은 지정된 원의 크기 바깥쪽에 경계선을 그린다는 의미이며 그 두께는 StrokeWidth = 4 로 정의했습니다. 원 둘레의 색깔은 white로 지정했으며 불투명도(opacity)는 16%로 지정하여 원의 안쪽 보다는 밝게 보입니다.

마지막 라인은 만들어진 circles 그룹을 루트 노드에 등록하는 것입니다. 이건 임시적인 등록이며 나중에는 위에서 본 Scene Graph의 형태로 정리될 것입니다.

다음 그림은 이 상태에서 어플리케이션을 돌린 결과입니다. 코드는 만들어진 원들의 위치를 지정하지 않았기 때문에 모든 원들의 중심이 좌표 (0, 0)인 좌상단 구석에 위치합니다. 흰색을 약간 투명하게 그렸기 때문에 배경의 검은색과 섞여서 회색으로 보입니다.


시각 효과(Visual Effect) 더하기

위 코드에서 조금 더 발전시켜 이번에는 box blur 효과를 줘 봅니다. 이 효과를 주면 원들이 약간 촛점이 안맞는 것처럼 흐려집니다. primaryStage.show() 라인 전에 아래 코드를 추가하면 됩니다.

circles.setEffect(new BoxBlur(10, 10, 3));

이 코드는 blur 반지름을 10 pixel x 10 pixel 로 정하고 blur 반복(iteration)을 3으로 정했습니다. 이렇게 하면 가우시안 블러(Gaussian Blur)와 비슷합니다. 이렇게 blur를 적용하면 아래 그림처럼 원의 테두리 부분이 부드럽게 변합니다.


배경 그래디언트(Background Gradient) 만들기

이제 사각형을 만들고 이 내부를 선형 그래디언트로 채워 봅니다.

아래 코드를 root.getChildren().add(circles) 바로 앞에 추가하면 원들의 아래에 그래디언트된 사각형이 위치하게 됩니다.

Rectangle colors = new Rectangle(scene.getWidth(), scene.getHeight(),
     new LinearGradient(0f, 1f, 1f, 0f, true, CycleMethod.NO_CYCLE, new 
         Stop[] {
            new Stop(0, Color.web("#f8bd55")),
            new Stop(0.14, Color.web("#c0fe56")),
            new Stop(0.28, Color.web("#5dfbc1")),
            new Stop(0.43, Color.web("#64c2f8")),
            new Stop(0.57, Color.web("#be4af7")),
            new Stop(0.71, Color.web("#ed5fc2")),
            new Stop(0.85, Color.web("#ef504c")),
            new Stop(1, Color.web("#f2660f")),}));
colors.widthProperty().bind(scene.widthProperty());
colors.heightProperty().bind(scene.heightProperty());
root.getChildren().add(colors);

이 코드는 colors 라는 이름의 네모를 먼저 만듭니다. 이 네모는 Scene의 가로 세로 크기와 동일하게 설정합니다. 그리고 그래디언트는 왼쪽 하단의 좌표인 (0, 1)의 위치에서 시작합니다. 그리고 오른쪽 상단의 좌표인 (1, 0)의 위치에서 끝이 납니다. 그 다음 true의 의미는 사각형의 크기에 비례한다(proportional)는 것이고, CycleMethod.NO_CYCLE는 컬러의 사이클이 반복되지 않음을 의미합니다. Stop[] 배열은 특정 지점에서의 그래디언트 색상을 지정합니다.

그 다음 두 줄의 바인딩 문법은 Scene의 크기 변경에 따라 colors 사각형의 크기도 같이 변하도록 하는 역할입니다. 바인딩에 대해서는 이 글을 참조하세요. 마지막으로 colors 사격형을 루트 노드에 추가합니다.

왼쪽 상단 구석에 있던 회색 원이 이제는 밑의 무지개 색이 비쳐 보입니다.


아래 그림은 지금까지 작성해 온 코드의 현재 Scene Graph를 보여 줍니다. 현재는 circles 그룹과 colors 사각형이 루트 노드의 자식들 입니다.


블렌드 모드(Blend Mode)를 적용하기

다음으로 원들에 색을 더하고 오버레이 블렌드 효과를 더해서 Scene의 색조를 어둡게 만들어 볼 것입니다. 이를 위해 circles 그룹과 colors 사각형을 루트 노드의 자식으로 추가하던 문장을 제거합니다.

root.getChildren().add(colors);
root.getChildren().add(circles);

그 자리에 다음의 코드를 넣습니다.

Group blendModeGroup = 
    new Group(new Group(new Rectangle(scene.getWidth(), scene.getHeight(),
        Color.BLACK), circles), colors);
colors.setBlendMode(BlendMode.OVERLAY);
root.getChildren().add(blendModeGroup);

blendModeGroup 그룹은 오버레이 블렌드를 위해 구조를 설정합니다. 이 그룹은 두개의 자식을 가집니다. 첫번째 자식은 검은색 배경을 가진 Rectangle과 앞에서 만든 circles 그룹을 엮어 만든 새로운 Group이고, 두번째 자식은 역시 앞에서 만든 colors 사각형입니다.

다음 라인의 setBlendMode() 메쏘드는 colors 사각형에 오버레이 블렌드를 실행합니다. 마지막 문장은 이렇게 만든 blendModeGroup을 루트 노드의 자식으로 만듭니다.

오버레이 블렌드는 그래픽 디자인 어플리케이션에서 많이 사용되는 효과입니다. 이렇게 블렌딩하는 색깔에 따라 블렌드 효과는 이미지의 색조를 어둡게 만들거나 더 돋보이게 만들거나 둘 다를 합니다. 이 경우는 선형 그레디언트 사각형이 오버레이로 사용 되었습니다. 검은 사각형은 배경을 어둡게 만드는 역할을 하고 거의 투명한 원은 밑색인 그래디언트의 푸른색이 비쳐 올라옵니다. 하지만 전보다는 색이 어둡습니다.

아래 그림은 위 코드의 실행 결과입니다. 다음 단계에서 애니메이션을 적용하고 나면 오버레이 블렌드의 효과를 확실히 볼 수 있을 겁니다.


애니메이션 추가하기

마지막으로 원들을 JavaFX 애니메이션을 이용하여 움직여 봅시다.

1. java.lang.Math.random 패키지를 import 합니다.

2. 아래 코드를 primaryStage.show() 호출 앞에 추가합니다.

Timeline timeline = new Timeline();
for (Node circle: circles.getChildren()) {
    timeline.getKeyFrames().addAll(
        new KeyFrame(Duration.ZERO, // set start position at 0
            new KeyValue(circle.translateXProperty(), random() * 800),
            new KeyValue(circle.translateYProperty(), random() * 600)
        ),
        new KeyFrame(new Duration(40000), // set end position at 40s
            new KeyValue(circle.translateXProperty(), random() * 800),
            new KeyValue(circle.translateYProperty(), random() * 600)
        )
    );
}
// play 40s of animation
timeline.play();

애니메이션은 타임라인에 의해 주도 됩니다. 그래서 이 코드는 가장 먼저 Timeline을 만듭니다. 다음으로 for 루프를 돌면서 30개의 각 원들에 대해서 두 개의 KeyFrame을 Timeline에 추가합니다. 첫번째 키 프레임은 0초 지점에 있으며 translateXProperty와 translateYProperty를 윈도우 내의 랜덤 위치로 지정합니다. 두번째 키 프레임은 40초 지점에 있으며 역시 같은 코드입니다. 그러므로 이 타임라인을 실행하면 모든 원들이 시작하는 랜덤 위치에서 또 다른 랜덤 위치로 40초 동안 이동하게 됩니다.

다음 그림은 30개의 다양한 색을 가진 원들이 움직이는 장면입니다.


더 볼만 한 자료들

- JDK와 함께 배포되는 샘플들 중에서 JavaFX Ensemble을 꼭 실행해 보세요. JavaFX가 지원하는 다양한 컨트롤과 애니메이션, 효과 등을 샘플 코드와 함께 직접 시연해 볼 수 있습니다. http://www.oracle.com/technetwork/java/javase/downloads/index.html

- 타임라인 애니메이션, 경로, 동시/순차 트랜지션 등에 대해서 더 알고 싶으면 다음 글을 읽어 보세요.
http://docs.oracle.com/javafx/2/animations/jfxpub-animations.htm

- 어플리케이션을 더욱 돋보이게 하는 리플렉션, 라이팅, 쉐도우 효과들에 대해 알고 싶으면 다음 글을 읽어 보세요.
http://docs.oracle.com/javafx/2/visual_effects/jfxpub-visual_effects.htm

- JavaFX Scene Builder를 이용하여 어플리케이션을 만들어 보세요. 이 툴은 시각적으로 레이아웃을 만들 수 있으며 UI를 디자인할 수 있습니다. 그리고 이를 FXML파일로 만들어 JavaFX 어플리케이션에 포함됩니다.
http://docs.oracle.com/javafx/scenebuilder/1/user_guide/jsbpub-user_guide.htm


댓글 없음:

댓글 쓰기