안녕하세요 박동윤입니다. 오늘 모임 내용 정리해 드립니다.
- DIP Introduction
- Exhibition 2008
- Processing?
- Why Programming? : Digital Era, New Design Environment
- Programming "Language" : Just like Japanese, English, Chinese
- Programming Basic : Grammar
- Reference, Examples
1. 프로그래밍 기본
- 순차적 실행 : 윗줄의 코드가 먼저실행되고, 아랫줄의 코드가 나중에 실행됨
예) rect 를 이용해 사각형을 먼저그리고, 같은 좌표에 ellipse 로 원을 그리면 사각형 위에 원이 덮히는 모양이 나옴
- 매 행이 끝날때 세미콜론 ; 을 붙여주어야 함
(한줄의 명령이 끝났다는 표시, 세미콜론이 없으면 몇줄에 나누어써도 상관은 없음)
- 함수(function, method) : 특정한 기능을 수행하는 모듈, 우리는 프로세싱에서 제공하는 다양한 함수들을 사용하여 작업
예) rect(), ellipse(), size(), fill(), noStroke() ... 등등 - 어떻게 구현되어있는지는 알필요 없음
- // 으로 시작하는 줄은 주석 (comment)처리되어 실행되지 않음. 설명을 달아놓거나 할때 유용
- 여러줄에 걸친 주석은 /* 로시작하여 */ 로 끝내면 됨
2. Processing의 기본 뼈대
void setup()
{
}
void draw()
{
}
- setup 부분은 최초실행시 한번만 실행되며, draw 부분이 반복적으로 실행이 됨(예:초당 30번 - 설정에 따라 바꿀 수 있음)
- draw 부분이 반복적으로 불려지는 점을 활용하여 변화하는 애니메이션, 또는 잔상을 남기는 작업등이 가능
- void 는 추후설명
사각형 그리기
void setup()
{
size(700, 500); // 윈도우 크기를 700x500 pixel로 설정
background(0); // 배경을 검정색으로 설정, 255는 흰색
}
void draw()
{ fill(120, 30, 210); // RGB 값이 120,30,210 인 컬러로 채운다. 이 명령 뒤에 나오는 모든 도형들에 적용됨 rect(70, 40, 300, 200); // x, y 좌표가 70,40 인 지점에 폭300, 높이200 인 사각형을 그린다
}
사각형 움직여보기
void setup()
{
size(700, 500); // 윈도우 크기를 700x500 pixel로 설정
background(0); // 배경을 검정색으로 설정, 255는 흰색
}
void draw()
{ fill(120, 30, 210); // RGB 값이 120,30,210 인 컬러로 채운다. 이 명령 뒤에 나오는 모든 도형들에 적용됨 rect(mouseX, mouseY, 300, 200); // mouse 포인터의 현재 위치의 x,y 좌표에 폭300, 높이200 인 사각형을 그린다
}
위의 결과는 매번 불리는 draw 에서 매 프레임마다 새롭게 배경을 그리지 않으므로 이전 프레임의 잔상이 남음
이를 없애기 위해서는 background(0); 을 삽입해서 매 프레임마다 사각형을 그리기 전에 전체를 검은색으로 칠함
사각형 움직여보기 - 잔상 없애기
void setup()
{
size(700, 500); // 윈도우 크기를 700x500 pixel로 설정
background(0); // 배경을 검정색으로 설정, 255는 흰색
}
void draw()
{ background(0); fill(120, 30, 210); // RGB 값이 120,30,210 인 컬러로 채운다. 이 명령 뒤에 나오는 모든 도형들에 적용됨 rect(mouseX, mouseY, 300, 200); // mouse 포인터의 현재 위치의 x,y 좌표에 폭300, 높이200 인 사각형을 그린다
}
3. Reference의 활용
예제들에서 알 수 있듯이, 프로세싱에는 다양한 기능을 하는 메소드들이 있고, 주로 이들을 호출해서 다양한 작업을 합니다.
이때 메소드(method)는, 언어에따라 함수(function)로 표기하기도 하고 같은 것이라고 일단 아시면 됩니다.
플래시 AS2.0 / 3.0 에서도 function 많이 보셨죠. 특정 기능을 수행하는 모듈이라고 보면 되고요.
중요한점은, 프로그래머들도 이런 수많은 메소드들을 전부 외워서 사용하는게 아니라는겁니다.
그래서 제일중요한것이 바로 Reference 입니다.
http://www.processing.org 에 가시면 상단 메뉴중 Reference 가 있는데요, 들어가보시면 프로세싱에 내장된 다양한 함수들이 보입니다. rect() 나 ellipse() 등 부터 다양하게 카테고리별로 잘 분류가 되어있습니다.
클릭하면 사용 방법에 대한 설명이 아주 자세히 나와있는데요,
사용 예제와 결과 화면을 일단 간단히 보시고, 어떤기능을 하는 메소드인지 Description 을 보고 이해하신 후
사용 방법을 보시면 됩니다.
Syntax, 말그대로 문법이라고 할 수 있겠는데, 메소드를 사용할때 몇개의 파라매터가 필요하고 각각의 파라매터는 무엇을 의미하는지 잘 설명이 되어있습니다. 이부분이 가장 중요하겠죠.
물론, 문법은 말그대로 규칙/약속과 같은 것이기에, 파라매터의 개수가 틀리다던가, 타입이 틀리다면 에러를 냅니다.
마지막으로 가장 밑의 Releated 는 말그대로 관련이 있는 메소드들인데, 한번씩 보시면 유용하게 함께 사용할 수
있는 것들이 많습니다.
결론은, 모든 정보와 해결책은 processing.org 에 있다는 점이고요, 특히 Reference 는 영어공부할때 영어사전을 사용하듯이 항상 북마크 해놓고 사용하세요-
(중국어, 일본어 공부하듯 역시 컴퓨터와 대화할 수 있는 '언어'를 공부한다는 점을 한번 떠올리시고...당연히 사전이 필수겠지요?)
그리고, 참고로 코딩시 주황색으로 나타나는 프로세싱 내장 메소드들은 블럭지정후 오른쪽클릭해서 Find in Reference 하면 마찬가지의 위의 Reference 페이지가 열립니다. 코딩중간중간에 유용하게 수시로 사용해야할 기능입니다.
4. Examples
위와같이 Processing 메뉴의 File - Examples 에 보시면 정말 무궁무진한 예제들이 많습니다.
간단한 기본 도형부터 복잡한 3D 예제까지 전부 소스가 있으니 한번씩 쭉 전부 실행을 해보시고요.
재미있는 것들이 워낙 많아서 이들 예제들만 조합해서도 충분히 멋진 interactive 한 작업들을 해낼 수 있습니다. 아이디어와 영감을 얻을 수 있는 좋은 소스이기도 하고요.
당장 코드가 이해 안되는 예제도 많겠지만, 일단 심심할때마다 하나씩 실행해보시고 어떠한 표현들이 가능한지 보는데 큰 도움이 됩니다.
다른 언어를 공부할때도 그렇듯이, 역시 반복적으로 자꾸 사용해봐야 언어는 실력이 늡니다. 꾸준하게 심심할때마다 간단히 배운것들을 쳐보고 실행을 해보시고요...
"백견이 불여 일타(打)" 라는 말이 있습니다. 아무리 영어 문법공부 해봤자 말한마디 못하는것과 마찬가지로,
직접 쳐보고 뭔가 만들어 보지 않으면 금방 다 까먹고 아무것도 못하게 됩니다^^
Mac OS X 에서 APM 환경을 구현하기 위해서는 OS X 에 기본적으로 설치되어있는 Apache 와 PHP 에
MySQL 만 추가하여 사용하는 방법이 있지만, 아주 손쉽게 한방에 모든게 되는 솔루션이 있어 소개합니다.
이들은 OS X 내장 Apache, PHP 모듈은 건드리지 않고 별도로 동작하는 것 같습니다. (제거할때도 깔끔한듯)
MAMP: Mac - Apache - MySQL - PHP
The
abbreviation "MAMP" stands for: Macintosh, Apache, Mysql and PHP. With
just a few mouse-clicks, you can install Apache, PHP and MySQL for Mac
OS X!
예전의 Beta 버전들과 달리 library 의 설치 방법이 달라졌습니다.
기존 버전들의 경우는 Processing Application 의 libraries 폴더에 넣었었습니다만, 최근의 버전들 에서는
다음과 같이 Sketch들이 저장되는 폴더에 libraries 라는 폴더를 생성 후 거기에 복사해 넣으면 됩니다.
(각각의 Sketch 에 넣는 것이 아님)
참고로 Sketch들이 저장되는 디폴트 폴더는 다음과 같이 Processing 의 Preference 에서 확인/변경이 가능합니다.
void listPrinters(){
services = PrintServiceLookup.lookupPrintServices(null, null);
for (int i = 0; i < services.length; i++) {
System.out.println(services[i].getName());
DocFlavor[] d = services[i].getSupportedDocFlavors();
for(int j = 0; j < d.length; j++)
System.out.println(" "+d[j].getMimeType());
}
services = null;
}
// prints a given image
void printJpg(PImage img){
setDocFlavor(DocFlavor.BYTE_ARRAY.JPEG);
print(bufferImage(img));
}
// prints a given string
void printString(String s){
setDocFlavor(DocFlavor.BYTE_ARRAY.AUTOSENSE);
print(s.getBytes());
}
boolean print(byte[] b){
if(!service.isDocFlavorSupported(docflavor)){
println("MimeType: \""+docflavor.getMimeType()+"\" not supported by the currently selected printer");
return false;
}
boolean ret = true;
try{
myDoc = new SimpleDoc(b, docflavor, null);
}
catch(Exception e){
println(e);
ret = false;
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
self.title = @"Movie Player";
[self playVideoWithControls];
}
- (void)playVideoWithURL:(NSURL *)url showControls:(BOOL)showControls {
if (!player) {
player = [[MPMoviePlayerController alloc] initWithContentURL:url];
1.Papervision3D 관련 class들을 다운받는다. ( http://code.google.com/p/papervision3d/ )
2.Papervision3D는 AS3.0의 기본 계층구조와는 다른 별도의 계층구조를 가지고 있으므로 경우에 따른 상속관계를 잘
따져보아야 한다. (무엇을 상속 받았는가에 따라 가능한 기능이 달라지므로 계층구조를 숙지해야할 필요가 있다.)
3.Papervision3D의 기본 요소(viewPort3D, Sceane3D, Camera3D, BasicRenderEngine )를 익히고 활용해본다.
[SWF (width="640", height="480", frameRate="36", backgroundColor="0xEEEEEE")] //meta tag는 꼭 붙여줍니다.
public class PV3Test1 extends Sprite
{ // 1. ViewPort
private var viewPort:Viewport3D; // 2. Scene3D
private var scene3D:Scene3D; // 3. Camera3D
private var camera3D:Camera3D; // 4. BasicRenderEngine
private var randerEngine:BasicRenderEngine;
//3D Object
private var plan:Plane;
public function PV3Test1()
{
super(); //1.ViewPort 만들고 화면에 붙이기
this.viewPort= new Viewport3D();
this.addChild(this.viewPort); //눈에 보이는 것이므로 addChild //2.Scene3D 만들기
this.scene3D= new Scene3D(); //3.Camera3D 만들기
this.camera3D= new Camera3D();
this.camera3D.zoom=40;
this.camera3D.moveBackward(500); //4.RanderEngine 만들기
this.randerEngine= new BasicRenderEngine();
//3D Object 만들기
this.plan= new Plane();
this.scene3D.addChild(this.plan); //눈에 보이는 것이므로 addChild
위의 코드는 PV3D의 기본 틀이다. 자 이제부터는 위의 기본 요소들을 하나씩 짚어보면서 Papervision3D의 상속관계를 알아본다.
!!!!!상속받은 class로 직접 이동하는 방법.. ctrl
을 누르고 원하는 class 이름 위에 커서를 올리면 이름에 underline이 생깁니다. 그 상태에서 class 이름을
클릭하면 곧바로 해당 class 로 이동하게 됩니다. (mac은 사과를 누르세요~) 이러한 방법으로 잘 모르는 class일지라도
상속관계를 찾아들어가 유추할 수 있는 것입니다.
1. ViewPort3D *상속관계 ViewPort3D -> Sprite
(ViewPort는 Sprite 상속받았으므로 눈에 보이는 것임을 알 수 있다.)
ViewPort는 PV3D에 의해서 만들어지는 화면(이미지/영상)을 플래시에 연결시키는 ... 클래스이다.
PV3D는 flash와는 전혀 다른 독자적인 화면랜더링 방식을 취하기 때문에 PV3D와 flash를 연결해주는 것이 필요하다.
그 역할을 ViewPort가 하는 것이다. { PV3D <--> flash }
2. Scene3D *상속관계 Scene3D -> SceneObject3D -> DisplayObjectContainer3D -> EventDispatcher -> Object (기본 상속관계 뼈대를 벗어나 자기만의 상속관계를 가진다는 것을 알 수 있다.)
Scene3D는 PV3D에서 stage와 같은 역할을 하는 객체이다. 그러므로 container 역할이 필요함( DisplayObjectContainer3D 상속 )
여기서 DisplayObjectContainer3D 는 DisplayObject3D를 담을 수 있는 능력이 있어서
addChild( displayObject3D ) / removeChild / numChildren 와 같은 기능이 가능하다.
( AS3 DisplayObject 기본 계층구조의 DisplayObjectContainer 참조)
3. Camera3D *상속관계 Camera3D -> CameraObject3D -> DisplayObject3D -> DisplayObjectContainer3D -> EventDispatcher -> Object
( DisplayObjectContainer3D을 상속받았다는 것이 매우 중요하다.)
DisplayObject3D ::: 플래시의 Sprite 같은 객체로서
x, y, z, scaleX, scaleY, scaleZ, rotationX, rotationY, rotationZ, alpha, ... addChild/ removeChild 가 가능하다.
기존 flash는 고정 카메라였으나 PV3D에서는 다양한 각도와 움직임이 있기 때문에 상당히 복잡한 메카니즘을 가지게 된다.
4.BasicRenderEngine *상속관계 BasicRenderEngine -> AbstractRenderEngine -> EventDispatcher -> Object
플래쉬는 플래시 플레이어가 알아서 랜더링 해주지만 플래시 플레이어는 DisplayObject를 상속받은 객체만 랜더링 해준다...
PV3D는 DisplayObject를 상속받은게 아니라서.... 별로도 랜더링 해 줄수있는... flashPlayer 같은 객체가 필요하다...!!
그 역할을 RenderEngine이 하는 것이다.
*** Plane (for 3D Object) *상속관계 Plane -> TriangleMesh3D
-> Vertices3D -> DisplayObject3D -> DisplayObjectContainer3D
-> EventDispatcher -> Object
TriangleMesh3D :: 삼각형 면 <--- 안에 내용( material )을 채울 수 있다..
눈에 보이기 위한 최소면 단위는 삼각형이다. (3개 vertexs(점들)이 이루는 최소면 ) 그래서 눈에 보이는 도형들은 모두
TriangleMesh3D 로 만든다. (점 두개가 모이면 선...선은 눈에 보이지 않는다...점 세개가 모이면 면이 된다.
그러므로 최소한의 면은 점 세개가 모여서 만들어진 트라이앵글이다.) 복잡한 도형의 경우 여러개의 triangle을 연결하여
만드는 것이다.
3.Papervision3D 활용 Basic 틀이 되는 코드 만들기 SuperClass: Sprite
[SWF (width="640", height="480", frameRate="36", backgroundColor="0xEEEEEE")] //meta tag는 꼭 붙여줍니다.
public class PV3DTest extends Sprite
{ // 1. ViewPort
private var viewPort:Viewport3D; // 2. Scene3D
private var scene3D:Scene3D; // 3. Camera3D
private var camera3D:Camera3D; // 4. BasicRenderEngine
private var randerEngine:BasicRenderEngine;
//3D Object
private var plan:Plane;
public function PV3DTest()
{
super(); //1.ViewPort 만들고 화면에 붙이기
this.viewPort= new Viewport3D();
this.addChild(this.viewPort); //눈에 보이는 것이므로 addChild //2.Scene3D 만들기
this.scene3D= new Scene3D(); //3.Camera3D 만들기
this.camera3D= new Camera3D();
this.camera3D.zoom=40;
this.camera3D.moveBackward(500); //4.RanderEngine 만들기
this.randerEngine= new BasicRenderEngine();
//3D Object 만들기
this.plan= new Plane();
this.scene3D.addChild(this.plan); //눈에 보이는 것이므로 addChild
내부가 채워지지 않고 뼈대만으로 구성된 사각형 도형이 가운데 축을 중심으로 빙글빙글 돕니다.
참고로 뼈대의 색은 렌덤하게 설정되므로 Test할 때마다 변합니다.
기본이 되는 코드를 별도 class로 만들어 놓으면 기본 사항을 반복하여 코딩하지 않아도 되므로 유용하다.
기본 내용을 포함한 Base3D라는 class를 만들어 저장하고 이것을 Document class로 불러들여 (상속) 활용하도록 해보자.
먼저 flex내에서 Base3D class를 만들기 위한 as 파일을 생성한다.
해당 프로젝트 src폴더에서 오른쪽 마우스 클릭 > new > Actionscript class
팝업이 뜨면 package 이름/ 경로와 as. 파일의 name, 기본적으로 상속받을 Superclass를 지정해준다. (Superclass 시작은 대문자)
package 이름/경로는 본인이 원하는대로 적어주면 자동으로 생성된다.
여기서는 자신이 만든 class를 timo라는 폴더에 넣어두어 관리하고있다.
public class Base3D extends Sprite
{
public var viewPort3D: Viewport3D;
public var scene3D: Scene3D;
public var camera3D: Camera3D;
public var renderEngine: BasicRenderEngine;
public function Base3D( width: Number = 640,
height: Number = 480,
autoScaleToStage: Boolean = false,
interactive: Boolean = false )
{
super(); // 1. viewPort
this.viewPort3D = new Viewport3D( width,height, autoScaleToStage, interactive );
this.addChild( this.viewPort3D ); // 2. stage
this.scene3D = new Scene3D(); // 3. camera
this.camera3D = new Camera3D();
this.camera3D.zoom = 40;
this.camera3D.moveBackward( 500 ); // 4. render
this.renderEngine = new BasicRenderEngine(); // 5. 매 프레임마다 렌더링..
this.addEventListener( Event.ENTER_FRAME, onEnter );
}
private function onEnter( e: Event ): void
{
this.renderEngine.renderScene( this.scene3D, this.camera3D, this.viewPort3D );
}
[SWF (width="640", height="480", frameRate="36", backgroundColor="0xEEEEEE")] //Meta tag는 꼭 써줍니다.
public class PV3Test1 extends Sprite
{ //1. viewPort
private var viewPort:Viewport3D; //2.Sceane3D
private var scene3D:Scene3D; //3.camera
private var camera3D:Camera3D; //4.randerEngine 위 네가지 요소가 기본적으로 필요한 필수사항이므로 머리에 기억하고 있어야 한다.
private var randerEngine:BasicRenderEngine;
private var plan:Plane;
public function PV3Test1()
{
super();
//1. viewPort 만들고 화면에 붙이기::스프라이트를 상속받았으므로 눈에보인다.
this.viewPort= new Viewport3D(640,480,false,false); // autoscale은 화면에 꽉 채울 것인지를 묻는 것임 (false가 기본) //interactive는 인터렉션이 가능하도록 할 것인지를 묻는 것임
this.addChild(this.viewPort);
//this.viewPort.scaleX=2; //기준점을 기준으로 화면 스케일을 쭉~ 늘리는 것임 //화면전환을 하고 싶다면 뷰포트 2개를 만들어서 애드차일드를 번갈아 가면서 한다.
//2.Sceane3D 만들기
this.scene3D= new Scene3D();
//3.camera 만들기
this.camera3D= new Camera3D();
this.camera3D.zoom=40;
this.camera3D.moveBackward(500);
//4.randerEngine 만들기
this.randerEngine= new BasicRenderEngine();
//3D 오브젝트 만들기 // 뼈대 이외의 속성들은 material이라는 것으로 컨트롤 한다.(material은 plane 윗라인에 쓰자)
var material:ColorMaterial= new ColorMaterial(0xFF0000);
material.doubleSided=true;
this.plan= new Plane(material); //뼈대를 만드는 것 !!!!!
this.scene3D.addChild(this.plan);
[ SWF (width="640", height="480", frameRate="36", backgroundColor="0xEEEEEE")]//꼭써주자!!
public class PV3DTest2 extends Base3D
{
private var plane:Plane;
private var plane2:Plane; private var planeContainer:DisplayObject3D;
public function PV3DTest2(width:Number=640, height:Number=480,
autoScaleToStage:Boolean=false, interactive:Boolean=false)
{ //부모클래스의 생성자 호출 base3d의 것 모두 가짐
super(width, height, autoScaleToStage, interactive); //3D 객체 생성하기
this.createObject3D(); //매 프래임마다 할 일 (객체변화주기)
this.addEventListener(Event.ENTER_FRAME, onEnter);
}
private function createObject3D():void
{ //채울물질 만들기 var material:ColorMaterial= new ColorMaterial(0xFF99999); var material2:ColorMaterial= new ColorMaterial(0xFFF078); //material.doubleSided=true;//2개의 plane을 만들 것이므로 더블사이드일 필요가 없으니 지워준다.
//물질이 채워진 면 만들기 this.plane= new Plane(material); //material을 꼭 넣어주어 해당 요소를 적용시킨다. this.plane2= new Plane(material2); //material을 꼭 넣어주어 해당 요소를 적용시킨다. this.plane.rotationY=180;//2개의 plane의 등이 맡닿을 수 있도록 한쪽면을 180도로 회전시킨다.
//this.scene3D.addChild(this.plane);
//this.scene3D.addChild(this.plane2); this.planeContainer= new DisplayObject3D(); this.scene3D.addChild(this.planeContainer); this.planeContainer.addChild(this.plane); this.planeContainer.addChild(this.plane2);
}
private function onEnter(e:Event):void
{
//this.plane.rotationY+=10;
//this.plane2.rotationY+=10; this.planeContainer.rotationY+=10;
}
}//class
}//package
/* 과정
1. case로 활용할 planeContainer라는 변수를 선언한다. 2. plane을 2개 만들어 2개의 material로 각각 다른 색을 입힌다.
3. 두개의 plane을 planeContainer에 담고 planeContainer를 회전시켜준다. 즉 두가지 오브젝트를 한 case에 넣고 case 자체를
회전하는 것이다.
[ SWF( width="640", height="480", frameRate="36", backgroundColor="0xEEEEEE")]
public class PV3DTest3 extends Base3D
{
public function PV3DTest3( width:Number=640, height:Number=480,
autoScaleToStage:Boolean=false, interactive:Boolean=false)
{ // 부모클래스의 생성자 호출..
super(width, height, autoScaleToStage, interactive);
// 3D 객체 생성하기
this.createObject3D();
// 매 프레임마다 할 일... {객체변화주기}
this.addEventListener( Event.ENTER_FRAME, onEnter );
}
private var planeContainer: DisplayObject3D;
private var plane1: Plane;
private var plane2: Plane;
private function createObject3D(): void
{ // 채울 물질 만들기
var material1: ColorMaterial = new ColorMaterial( 0xFF9900 );
var material2: ColorMaterial = new ColorMaterial( 0x0000FF );
// 물질이 채워진 면 만들기
this.plane1 = new Plane( material1, 400, 400 );
this.plane2 = new Plane( material2, 400, 400 );
// this.plane1.x = 200; this.plane2.x = 200;
this.plane2.rotationY = 180;
this.planeContainer = new DisplayObject3D();
this.scene3D.addChild( this.planeContainer );
}
} /* 회전의 중심을 바꾸려면 DisplayObject3D를 Sprite 처럼 활용하자 flash stage와는 다르게 PV3D에서 오브젝트의 중심은 기본적으로 오브젝트의 중심이다. 그러므로 가로 세로길이가 각 400인 오브젝트에서는 그 중심에서 200만큼 증가시키면
한쪽 변을 중심으로 도는 모션을 구현할 수 있다.
노란색 면을 기준으로 하여 왼쪽 모서리를 중심으로 (파란색 면은 오른쪽 모서리) 뱅글뱅글 회전.
[ SWF (width="640", height="480", frameRate="36", backgroundColor="0xEEEEEE")]//꼭써주자!!
public class PV3DTest4 extends Base3D
{
public function PV3DTest4(width:Number=640, height:Number=480,
autoScaleToStage:Boolean=false, interactive:Boolean=false)
{
super(width, height, autoScaleToStage, interactive);
this.createObject3D();
this.addEventListener(Event.ENTER_FRAME, onEnter);
}
private var earth:Sphere;
private function createObject3D(): void
{
var bitmapData:BitmapData= new BitmapData(400,300,false,0); bitmapData.perlinNoise( 128,128,8,12345, true, true);//네번째 트루는 말렸을 때 끝이 매끄럽게 연결하는것 // bitmapData.perlinNoise( 128,128,8,12345, false, true);
var material:BitmapMaterial = new BitmapMaterial(bitmapData);
this.earth= new Sphere(material, 300,20,20) //껍질, 반지름 , 가로세로등분
this.scene3D.addChild(this.earth);
}
private function onEnter(e:Event):void
{
this.earth.rotationX+=2;
this.earth.rotationY+=3;
}
}
}
<변경사항>
Object3D를 만들기 위해 함수 createObject3D를 만든다. perlinNoise를 쓰기위해 bitmapData를 상속받는다.
private var earth: Sphere; private var moon: Sphere; private var moonContainer: DisplayObject3D;
private function createObject3D(): void
{
// 지구 만들기 var material1: BitmapFileMaterial = new BitmapFileMaterial( "./img/world.jpg" );
this.earth = new Sphere( material1, 300, 12, 12 );
this.scene3D.addChild( earth );
this.earth.rotationZ = -20;
// 달 만들기 var material2: BitmapFileMaterial = new BitmapFileMaterial( "./img/img1.jpg" );
this.moon = new Sphere( material2, 50, 8, 8 ); this.moon.x = 450;
// 달을 화면에 붙이기 { moonContainer - moon } this.moonContainer = new DisplayObject3D(); this.moonContainer.rotationZ = -25; this.moonContainer.addChild( moon ); this.scene3D.addChild( this.moonContainer );
}
private function onEnter( e: Event ): void
{ this.earth.rotationY += 1; // 지구 자전 this.moonContainer.rotationY += 2; // 달이 지구를 중심으로 공전 this.moon.rotationY += 1; // 달 자전
// this.earth.rotationX += 3;
}
} // class
} // package
과정 moon의 case역할을 하게 될 moonContainer 변수 만들기 ( DisplayObject3D 임포트) earth와 moon 변수 생성하고 각각 material 처리 오브젝트인 moon의 중심점 x위치를 450 만큼 증가 (earth와의 실질적인 거리차이) moon을 moonContainer 에 넣기 moonContainer를 earth를 중심으로 공전하도록 함 earth를 자전하도록 함
moonContainer에 moon을 넣었기 때문에 earth와 rotationY 를 공유할 수 있는 것임 moonContainer를 쓰지 않았다면 각기 다른 기준점으로 공전/자전을 해야함
그렇게 되면 오브젝트가 많아질 경우 각각 기준점이 다르기 때문에 컨트롤하기가 어려워짐 그러므로 컨테이너를 적극 활용하여 움직임 컨트롤를 쉽게 해야함.
지구와 지구 주위를 도는 달 (달 sphere를 만들고 달의 공전 중심을 지구로 설정합니다. this.moonContainer.rotationY += 2; )
Superclass Base3D (특정 개체의 움직임을 절대 중심에 두고 카메라를 이동 시켜보기 )
private var earth: Sphere;
private var moon: Sphere;
private var moonContainer: DisplayObject3D;
private function createObject3D(): void
{ // 지구 만들기
var material1: BitmapFileMaterial = new BitmapFileMaterial( "./img/world.jpg" );
this.earth = new Sphere( material1, 300, 12, 12 );
this.scene3D.addChild( earth );
this.earth.rotationZ = -20;
// 달 만들기
var material2: BitmapFileMaterial = new BitmapFileMaterial( "./img/img1.jpg" );
this.moon = new Sphere( material2, 50, 8, 8 );
this.moon.x = 450;
// 달을 화면에 붙이기 { moonContainer - moon }
this.moonContainer = new DisplayObject3D();
this.moonContainer.rotationZ = -25;
this.moonContainer.addChild( moon );
this.scene3D.addChild( this.moonContainer );
}
private function onEnter( e: Event ): void
{
this.earth.rotationY += 1; // 지구 자전
this.moonContainer.rotationY += 2; // 달이 지구를 중심으로 공전
this.moon.rotationY += 1; // 달 자전
// this.earth.rotationX += 3;
this.camera3D.x += 0.01 * ( 2000 - this.camera3D.x ); this.camera3D.z += 0.01 * ( 2000 - this.camera3D.z ); this.camera3D.y += 0.01 * ( 2000 - this.camera3D.y ); this.camera3D.lookAt( this.earth ); //이차원에서는 좌우상하로 돌아보기만 하면 되지만 삼차원에서는 좌우상하로 바라보고 / 카메라의 위치도 틀어야 한다. //어려운 프로세스이므로 기본적으로 lookAt(특정개체) 를 제공한다. // lookAt(특정개체)를 쓰면 특정개체의 움직임을 화면 정면으로 바라본 채 카메라가 움직인다. 즉 특정 개체는 항상 화면의 중앙에 놓이게 된다. 특정 개체가 절대기준이 되는 것임. lookAt(특정개체)을 dimmed시키고 실험해보면 차이점을 알수 있다.
}
} // class
} // package
로딩하자마자 달과 지구는 앞으로 zoom in되다가 서서히 zoom out 됩니다. 지구와 달은 중앙에서 벗어나지 않습니다.
다양한 웹사이트와 레퍼런스를 참조한 결과 단순히 다음 코드 한줄로 될 줄 알았습니다만,
보안정책상 마우스나 키보드 이벤트를 받은 후처리로서의 동작으로만 가능하다고 합니다.
즉, 시작부분에 단순히 다음 코드를 삽입해서 자동으로 풀스크린으로 들어가도록 하는것은 동작하지 않는것 같습니다.
stage.displayState = StageDisplayState.FULL_SCREEN;
다음과 같이 메뉴나 버튼등을 활용하여 이벤트 처리시 풀스크린 진입을 가능하게 해주면 됩니다.
아래의 예는 플래시에서 우측클릭시 뜨는 팝업메뉴에 Go Full Screen / Exit full Screen 메뉴를 삽입한 경우입니다.
... 클래스의 constructor 부분에서 다음과 같이 built-in 메뉴를 풀스크린 관련 메뉴 아이템으로 대체, 이벤트 핸들러 선언.
var fullscreenCM:ContextMenu = new ContextMenu();
fullscreenCM.addEventListener(ContextMenuEvent.MENU_SELECT, menuHandler);
fullscreenCM.hideBuiltInItems();
var fs:ContextMenuItem = new ContextMenuItem("Go Full Screen" );
fs.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, goFullScreen);
fullscreenCM.customItems.push( fs );
var xfs:ContextMenuItem = new ContextMenuItem("Exit Full Screen");
xfs.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, exitFullScreen);
fullscreenCM.customItems.push( xfs );
contextMenu = fullscreenCM;
다음과 같이 이벤트 핸들러 구현.
// functions to enter and leave full screen mode
public function goFullScreen(event:ContextMenuEvent):void
{ stage.displayState = StageDisplayState.FULL_SCREEN;
}
public function exitFullScreen(event:ContextMenuEvent):void
{ stage.displayState = StageDisplayState.NORMAL;
}
중요한것은 이걸로 끝이 아니고 publish된 html 파일에서 allowFullScreen 내용들을 true로 수정해 주어야 합니다.
수정하지 않으면 다음과 같이 보안관련 에러가 발생합니다.
Arduino에서 XBee 를 사용하는 방법입니다. 책 Making Things Talk 의 203페이지에서는 XBee 칩의 초기화
및 주소 설정 과정이 있습니다만, 브로드케스팅방식을 사용하는데는 굳이 위의 주소설정 과정을 거치지 않아도 잘 동작 합니다.
책에서는 XBee 의 좁은 핀을 넓혀주는 Breakout board를 사용하거나 Arduino 에 장착되기 쉽게 만든 XBee Shield를 사용합니다. 여기서는 sadi의 XBee Shield 를 사용하였으나, 굳이 Shield 가 없어도 구성 방법은 동일합니다. XBee의 핀에 소켓등을 꽂아 핀번호에 맞게 Power / Tx, Rx 등을 연결만 해주면 됩니다. (선들이 좀 주렁주렁 지저분 해지겠지만요)
sadi XBee shield 를 사용할 경우 다음과 같이 Analog 와 Digital Pin 을 사용할 수 있습니다.
주의할점은, USB 를 통하여 컴퓨터와 통신 (Arduino 프로그램 작성 및 다운로드 등) 하는 경우는 우측하단의 점퍼 두개를 왼쪽두개로 잡아주어야 합니다. (XBee 와 통신시에는 오른쪽 두개)
XBee 간의 통신은 브로드캐스팅 방식으로, 별 특별한 코드 없이 일반적인 Serial.print() 와 Serial.read() 로 정보를 쏘고 수신할 수 있습니다. 다음과 같이 마스터/슬레이브 또는 서버/클라이언트 구분없이 동일 코드에서 송신/수신을 테스트 해 볼 수 있습니다.
1. Navigation-Based Application 으로 프로젝트 생성
- AppDelegate 와 RootViewController 가 기본적으로 생성됨
- 이때 RootViewController 는 UITableViewController 를 상속받고, tableView 라는 UITableView 를 담고 있음
그리고, AppDelegate 의 UINavigationController 에서 보여지는 첫 화면이 됨
- AppDelegate 는 UINavigationController *navigationController 를 담고 있음
2. RootViewController의 tableView 를 위한 모델(데이터) 생성
- AppDelegate의 applicationDidFinishLaunching와 같은 초기화 부분에서 NSArray 등의 데이터 생성
- RootViewController 는 UITableViewController를 상속받으므로, tableView와 관련된 메소드가 정의되어 있음
이 메소드들을 수정하여 데이터를 채워줄 수 있도록 함
(numberOfSectionsInTableView, numberOfRowsInSection, cellForRowAtIndexPath)
3. 메뉴 선택시 로드될 UIViewController 추가
- Add - New File - UIViewController subclass 또는 기타 목적에 맞는 클래스 선택
- xib 파일도 RootViewController.xib 등을 열어 새이름으로 저장, 새클래스 이름 지정
4. 하위 계층의 새로운 UI 로딩(push) 구현
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 부분에서
하위 계층의 새로운 UIViewController (또는 다른 UIView 화면)를 로딩하도록 구현 (pushViewController 사용)
- 이때 self.navigationController 는 UINavigationController 에 담긴 View controller 라면 접근 가능하도록 되어있음
5. 하위계층에서 복귀(pop)는 특별히 구현하지 않아도 됨
- UINavigationController 의 Back 버튼 처리가 자동으로 됨
- 다른 버튼 등을 사용한 수동 구현시는 [self.navigationController popViewControllerAnimated:YES]; 사용