Tizen의 사용자 지정 3D 그래픽

이 문서의 목적은 개발자가 Box2d 및 WebGL에 친숙해지고 Tizen 애플리케이션에서 이러한 외부 라이브러리를 사용하는 방법을 설명하는 것입니다. 이러한 주제는 샘플 애플리케이션인 Boules 게임을 사용해서 설명합니다.

이 문서에서는 Tizen 웹 애플리케이션에서 Box2dWeb을 추가하고 사용하는 방법을 보여줍니다. 라이브러리 캔버스, 세계, 정적 및 동적 개체 만들기와 같은 기본 기능에 대해 설명합니다. 또한 디버그 모드에서 실제 세계를 시뮬레이션하는 방법을 알아볼 것입니다. 이 문서의 두 번째 부분에서는 HTML5 Canvas의 WebGL 기초를 설명합니다. 렌더 루프에서 3D 개체를 만들고 텍스처링하고 그리는 방법을 배웁니다. 이 문서에서 다루는 문제는 간단하지만 대상 독자는 컴퓨터 그래픽에 대한 약간의 기본적인 지식을 갖고 있다고 간주합니다.

 

다음 연락처로 지정 담당자에게 문의할 수 있습니다. 지정 담당자: Lisa Smiley-Gillis 지정 담당자 주소: 1796 18th Street, Suite C San Francisco, CA 94107 지정 담당자 전화 번호: 1-415-723-9709 지정 담당자 이메일 주소: copyright@linuxfoundation.org 샘플 애플리케이션 및 필수 구성 요소

"Boules"라는 샘플 게임이 물리 및 그래픽 라이브러리 사용법을 설명하기 위해 제공됩니다. Box2dWeb을 사용하여 물리 세계를 시뮬레이션하고 WebGL을 사용하여 그래픽을 렌더링합니다. 샘플 애플리케이션은 직관적이고 일관된 사용자 인터페이스와 확장성이 높은 웹 애플리케이션을 만들 수 있는 jQuery Mobile 1.2.0 프레임워크를 기반으로 합니다. JQuery Mobile을 사용할 수 있으려면 사용자 애플리케이션에 jQuery 1.8.0 라이브러리가 포함되어 있어야 합니다. 샘플 애플리케이션은 Tizen SDK 2.0.0a2에서 테스트되었습니다.

메인 화면주요 게임 보기

 

코드 샘플은 사용자 지정 함수를 사용하여 콘솔에 로그 메시지를 보냅니다. 이러한 코드 샘플은 애플리케이션의 js/lib/internal 폴더에서 찾을 수 있습니다.

 

2 물리 엔진-Box2dWeb

Box2d는 2D 세계의 강체 시뮬레이션을 위한 오픈 소스 C++ 라이브러리입니다. zlib 라이센스 하에 배포됩니다. Java, Adobe Flash, C# 및 JavaScript를 포함한 다양한 프로그래밍 언어와 환경에 포팅되었습니다.

자바 스크립트에 두 개의 주요 오픈 소스 Box2dWeb 포트인 Box2dJS (http://box2d-js.sourceforge.net/) 및 Box2dweb (http://code.google.com/p/box2dweb/)가 있습니다. 샘플 게임으로 두 번째 것을 선택한 이유는 최신 포트이며 단일 파일에 저장되기 때문입니다.

Http://code.google.com/p/box2dweb/에서 문서를 찾을 수 있습니다. Box2dFlash에 대한 설명서이지만 Box2dWeb 구조는 유사하게 구성되어 있습니다. 왜냐하면 Box2dWeb은 Box2dFlash에서 컴파일되어 있고 JavaScript 1.6과 ActionScript 2.0 모두 동일한 ECMAScript 표준을 기반으로 하고 있기 때문입니다. 또한 http://www.box2d.org/manual.html에서 교육 자료를 참조할 수 있습니다.

Box2dWeb은 물리 엔진입니다. 샘플 애플리케이션의 모든 그래픽은 이 문서의 두 번째 부분에서 설명하는 WebGL에 의해 생성됩니다.

샘플 애플리케이션에서는 boule이 2차원의 평평한 영역에서만 이동하기 때문에 2D 그래픽 엔진을 사용합니다. WebGL은 보다 현실적인 보기에 사용되며 사용자에 의한 원근 시점 변경을 허용하는 데 사용됩니다.

Box2dWeb은 강체 이동과 충돌과 관절 등의 상호 작용을 시뮬레이션합니다. 또한 라이브러리는 개체를 표시하는 데 사용할 수 있는 데이터를 제공합니다. 다각형, 원, 가장자리 모양으로 구성된 몸체를 시뮬레이션할 수 있습니다. 중력, 마찰 및 복원과 같은 힘(개체 바운스를 만드는 힘)은 개체에 적용될 수 있습니다.

 

Tizen 애플리케이션에 Box2dWeb 추가

Tizen 애플리케이션에서 Box2dWeb을 사용하려면 프로젝트로 라이브러리 파일을 가져와야 합니다. 또한 파일이 index.html 파일에서 선언되어야 합니다.

이제 JavaScript 파일에서 Box2dWeb 함수에 액세스할 수 있습니다.

 

캔버스 만들기

Box2dWeb의 캔버스는 index.html 파일에서 정의되어야 합니다.

화면에 맞도록 프로그래밍 방법으로 캔버스의 폭과 높이를 설정할 수 있습니다.

var canvas = document.getElementById('canvas');
canvas.width = window.screen.availWidth;
canvas.height = window.screen.availHeight;

window.screen.availHeight 함수는 상단 막대 없이 사용 가능한 화면 높이를 반환합니다.

캔버스 스크롤을 비활성화는 것이 좋습니다. 이 작업을 수행하려면 터치 이동 이벤트에 대한 리스너를 만들고 항목에 preventDefault() 함수를 호출해야 합니다.

canvas.addEventListener("touchmove", handleTouchMove, true);

function handleTouchMove(e) {
    e.preventDefault();
}

 

Box2dWeb 세계 만들기

먼저 Box2dWeb 세계 개체를 만들어야 합니다. 메모리, 개체 및 시뮬레이션을 관리합니다.

var world = new b2World(new b2Vec2(0, 0) // gravity
, true // allow sleep
);

생성자는 gravity 및 allowSleep의 두 매개 변수를 사용합니다. 샘플 애플리케이션에서 boule이 평평한 영역에서만 이동하기 때문에 중력 벡터를 0으로 설정합니다. 두 번째 매개 변수 allowSleep은 움직임을 멈출 때 몸체가 수면 상태로 전환하는 것을 허용할지 여부를 결정합니다.  몸체 시뮬레이션은 장치의 리소스 대부분을 사용하므로 몸체를 정지할 때 시뮬레이션을 일시 중지하고 CPU 오버헤드가 적은 수면 상태를 사용하려고 합니다. 몸체는 다른 몸체와 충돌할 때 깨어납니다. 또한 다음 작업을 수동으로 수행할 수 있습니다.

bodyDef.awake = true;

 

바닥 만들기

Box2dWeb 몸체는 라이브러리에서 사용하는 기본 개체입니다. 위치와 모양을 비롯하여 마찰이나 밀도와 같은 다른 매개 변수를 정의할 수 있습니다. 샘플 애플리케이션에는 boule을 위한 사각형 영역이 있습니다. 이 영역은 4개의 사각형 개체에 의해 제한됩니다.

몸체를 만들려면 다음 단계를 수행합니다.

  1. 몸체 정의 만들기

바닥의 경우 정적 몸체를 사용합니다.

var bodyDef = new b2BodyDef;
bodyDef.type = b2Body.b2_staticBody;
bodyDef.position.Set(0, 0);
  1. 고정물 정의

고정물은 셰이프를 몸체에 부착하고 밀도, 마찰 및 복원과 같은 물질 속성을 추가합니다. 하나의 고정물은 단일 셰이프를 유지합니다. 몸체는 다양한 고정물을 가질 수 있습니다.

다음 코드 샘플은 위로부터 바닥을 제한하는 사각형에 대한 고정물을 만드는 방법을 보여줍니다. 다른 세 개의 사각형은 비슷한 방식으로 만들어집니다. 유일한 변화는 너비, 높이 및 위치입니다.

//create fixture object
var fixDef = new b2FixtureDef;

//define basic parameters
fixDef.density = 1.0;
fixDef.friction = 0.5;
fixDef.restitution = 0.2;

//scale for debug mode (it will be explained in the Setting debug draw section)
var SCALE = 30;

// canvas width and height in meters
var height = canvas.height / SCALE;
var width = canvas.width / SCALE;

var borderSize = height / 50;

//define shape
fixDef.shape = new b2PolygonShape;
fixDef.shape.SetAsBox(width, borderSize);

다각형 셰이프는 볼록 다각형만 가질 수 있습니다. 즉, 모든 내부 각도가 180도보다 작으며 꼭짓점 두 개 사이의 모든 선 세그먼트가 계속 내부 또는 다각형 경계선에 있습니다.

  1. 다음으로 몸체 위치를 설정하고, 고정물을 몸체 정의에 바인딩하고, 몸체를 세계에 추가합니다.
bodyDef.position.Set(0, 0);

world.CreateBody(bodyDef).CreateFixture(fixDef);

 

동적 몸체 만들기

세계와 바닥을 이미 만들었으므로 이제 boule을 만들 수 있습니다. 이를 위해 동적 몸체를 사용합니다.

var bodyDef = new b2BodyDef;
bodyDef.type = b2Body.b2_dynamicBody;
bodyDef.linearDamping = 1.0;
bodyDef.angularDamping = 1.0;

움직이는 몸체 속도를 줄이는 데 댐핑이 사용됩니다. 값은 0과 무한대 사이여야 합니다. 선형 댐핑은 선형 속도에 영향을 미치며 각도 댐핑은 각도 속도를 줄입니다.

작업의 나머지는 동적 몸체와 정확히 같습니다. boule의 경우 원형 셰이프를 사용합니다.

//radius of the main sphere, 1/10 of the screen width
var mainSphereRadius = width / 10;
fixDef.shape = new b2CircleShape(mainSphereRadius);

Box2dWeb 몸체는 일부 추가 사용자 데이터를 저장할 수 있습니다. 샘플 애플리케이션에서는 게임에서 현재 boule 상태에 대한 정보를 유지하기 위해 이를 사용합니다(활성/유휴). 이 추가 정보는 렌더링 루프 동안 WebGL 엔진으로 전달됩니다.

var sphereBody = world.CreateBody(bodyDef);
sphereBody.SetUserData(data); //in example application data is a number representing boule state

 

디버그 드로우 설정

Box2dWeb은 몸체를 표시하기 위한 함수를 제공하지 않습니다. 모든 몸체의 위치와 회전을 계산할 뿐입니다. Box2dWeb 예제에서 보는 보기는 디버그 모드에서 만들어집니다.

디버그 모드디버그 모드

이 모드는 디버깅 목적으로 사용할 수 있습니다. 그래픽 레이어를 첨부하기 전에 몸체가 보고 행동할지 여부를 확인할 수 있기 때문에 개발 과정에서 매우 유용합니다. 샘플 애플리케이션에서 디버그 모드는 main.js 파일에서 전역 디버그 변수를 사용하여 설정/해제할 수 있습니다.

var debugDraw = new b2DebugDraw();
debugDraw.SetSprite(document.getElementById("canvas").getContext("2d"));
debugDraw.SetDrawScale(30);
debugDraw.SetFillAlpha(0.5);
debugDraw.SetLineThickness(1.0);
debugDraw.SetFlags(b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit);
world.SetDebugDraw(debugDraw);

위의 샘플 코드에서 가장 중요한 값은 측정값(여기서는 30)입니다.  Box2dWeb은 자체 단위 체계를 사용합니다. 그래픽을 렌더링할 때 픽셀 좌표로 변환해야 합니다. 측정값 30은 1미터 = 30픽셀을 의미합니다.

샘플 애플리케이션에서 모든 셰이프 위치와 크기는 화면 너비와 높이에 상대적으로 계산됩니다.

 

세계 시뮬레이션

Box2dWeb은 별도의 시점에서 위치와 몸체의 다른 매개 변수를 새로 고칩니다. 이 작업은 물리학 방정식을 해결하는 적분기라는 연산 알고리즘에 의해 수행됩니다. Box2d 설명서에 따라 게임은 적어도 60Hz(1/60초)와 같은 빈도로 새로 고쳐져야 합니다. 또한 Box2dWeb은 제약 해소기를 사용합니다. 시뮬레이션에서 한 번에 하나씩 모든 제약 조건을 해결합니다. 올바르게 수행하려면 몇 차례 모든 제약 조건을 반복해야 합니다. 반복 횟수는 속도 반복과 위치 반복의 두 매개 변수에 의해 정의됩니다. 이러한 값을 늘리면 계산이 더 정확해지지만 성능에 영향을 미칩니다. 시간 단계, 속도 반복 및 위치 반복의 세 가지 값으로 Box2dWeb Step() 함수를 호출할 수 있습니다.

world.Step(1 / 60, 10, 10);

Box2dWeb 세계는 미터, 킬로그램, 초와 같은 MKS 단위를 사용합니다. 개체가 일반 현실 세계 개체의 크기일 때 가장 잘 동작합니다. 움직이는 개체는 0.1미터와 10미터 사이여야 합니다. 정적 개체는 최대 50미터까지 될 수 있습니다.

함수 구문: world.Step(timeStep, velocityIterations, positionIterations

위의 값은 라이브러리와 함께 배포된 데모에서 가져온 값입니다. 자체 매개 변수를 선택할 수 있습니다.

이제 화면에 디버그 데이터를 그릴 수 있습니다(디버그 모드에 있는 경우).

world.DrawDebugData();

각 세계 단계 후 ClearForces 함수를 사용하여 몸체에 적용한 모든 힘을 지워야 합니다.

world.ClearForces();

 

터치한 몸체 획득

이 문서에서는 Box2dWeb API의 일부만을 보여줍니다. 더 많은 함수와 자세한 설명은 문서 또는 설명서를 참조하십시오.

사용자는 게임을 제어하기 위해 화면을 터치합니다. 주어진 좌표에서 몸체를 가져오려면 b2World 개체에 대한 쿼리를 작성해야 합니다.

var selectedBody;

/**
 * Get b2Body object that was touched
 * @param touchX x touch coordinate
 * @param touchY y touch coordinare
 * @returns Body, that was touched (b2Body object)
 */
function getBodyAtTouch(touchX, touchY) {
    var aabb = new b2AABB();
    aabb.lowerBound.Set(touchX - 0.001, touchY - 0.001);
    aabb.upperBound.Set(touchX + 0.001, touchY + 0.001);

    // Query the world for overlapping shapes.

    selectedBody = null;
    world.QueryAABB(getBodyCB, aabb);
    return selectedBody;
}

/**
 * Get body touched and save it to selectBody variable
 * @param fixture Touched fixture
 * @returns true if success, false otherwise
 */
function getBodyCB(fixture) {
    if (fixture.GetBody().GetType() != b2Body.b2_staticBody) {
        if (fixture.GetShape().TestPoint(fixture.GetBody().GetTransform(), new b2Vec2(touchX, touchY))) {
            selectedBody = fixture.GetBody();
            return false;
        }
    }
    return true;
}

터치한 몸체를 가져오기 위해 QueryAABB() 메서드를 사용합니다. 두 개의 인수를 사용합니다. 첫 번째 인수는 하나의 매개 변수(발견된 고정물)를 갖는 콜백 함수입니다. 두 번째 인수로는 검색하려는 영역의 좌표를 전달합니다. 이 경우에는 하나의 점에 불과하므로 작은 검색 영역(측면 길이가 0,001인 사각형)을 사용합니다. 쿼리는 고정물을 반환합니다. 고정물이 바닥 몸체가 아닌지 확인하고(정적이 아닌 경우) b2Body 개체를 가져옵니다.

 

3 WebGL

Box2DWeb이 물리 엔진이며 셰이프를 표시하기 위해 일부 그래픽 환경이 필요하다는 것을 배웠습니다. 이를 위해 WebGL을 사용하기로 했습니다.

WebGL은 2D, 2.5D 또는 3D 세계를 HTML5 캔버스 요소에 그리고 애니메이션하는 것이 가능한 웹 표준입니다. WebGL은 OpenGL ES 2.0을 기반으로 하며 그와 매우 유사합니다. OpenGL ES 2.0의 기능 대부분은 WebGL에서 찾을 수 있습니다. 또한 많은 유용한 함수도 샘플 애플리케이션에서 사용한 추가 라이브러리에서 찾을 수 있습니다. OpenGL 사용 경험이 있는 개발자는 매우 빨리 새로운 환경에 적응합니다.

WebGL은 낮은 수준의 크로스 플랫폼 API입니다. GPU에서 직접 명령을 처리하는 쉐이딩 언어(GLSL)를 사용합니다. 결과적으로 WebGL은 뛰어난 성능 및 하드웨어 가속을 제공합니다. 한편으로는 사용하기가 그리 쉽지 않기 때문에 세부적으로 깊이 파고들지 않습니다.

 

GLSL

GLSL은 OpenGL 쉐이딩 언어입니다. C 언어를 기반으로 하며 어셈블리 언어를 사용하지 않고 개발자가 직접 그래픽 처리 장치에 액세스할 수 있도록 만들어졌습니다.

본 문서에서는 glMatrix v0.9.5라고 하는 추가 라이브러리를 사용합니다. WebGL에서의 프로그래밍을 더욱 쉽게 만들어주는 많은 유용한 기능을 제공합니다. GlMatrix 라이브러리를 http://code.google.com/p/glmatrix/에서 찾을 수 있습니다.

다음 섹션에서 WebGL 환경을 설정하는 방법, 개체를 만드는 방법, 개체를 WebGL 버퍼에 로드하는 방법, 개체를 HTML5 캔버스에 그리는 방법을 배웁니다.

 

HTML5 캔버스에서 WebGL 초기화

특정 캔버스를 사용하려면 컨텍스트를 가져와야 합니다. 캔버스는 고정 그리기 표면을 만들고 표시합니다. 사용하려는 컨텍스트 종류를 결정할 수 있습니다. 여기서는 WebGL 3D 컨텍스트("experimental-webgl")가 결정됩니다. 또한 캔버스로 2D 컨텍스를 그릴 수 있습니다. 렌더링 컨텍스트에 액세스하려면 다음과 같이 getContext() 메서드를 사용합니다.

canvas = document.getElementById('canvas');
gl = canvas.getContext("experimental-webgl");

캔버스 컨텍스트에 액세스한 후 캔버스에서 그림을 관리할 쉐이더를 처리할 수 있습니다.

 

쉐이더 설정

캔버스에 무엇인가를 그리기 위해서는 WebGL에 두 가지가 필요합니다.

  • 클립스페이스 좌표
  • 색상

이 두 매개 변수 모두 쉐이더를 사용하여 WebGL로 전달해야 합니다. 그리기 위해 WebGL에서 요구하는 두 가지가 있으므로, 이를 제공하는 두 개의 쉐이더가 있습니다.

  • 꼭짓점 쉐이더
    꼭짓점 쉐이더는 꼭짓점을 처리합니다.
  • 프래그먼트 쉐이더
    이 쉐이더는 픽셀을 색칠합니다.

간단한 쉐이더는 다음과 같이 정의될 수 있습니다.

attribute vec2 aVertexPosition;

void main() {
  		gl_Position = vec4(aVertexPosition, 0, 1);
}




void main() {
gl_FragColor = vec4(0,0,1,1);
}

이 두 쉐이더 모두 정의되어야 합니다. 위의 코드는 파란색으로 전체 캔버스를 채울 뿐입니다. 좀 더 복잡한 3D 개체를 그리려면 다음 쉐이더를 사용해야 합니다.

    attribute vec3 aVertexPosition;
    attribute vec3 aVertexNormal;
    attribute vec4 aVertexColor;
    attribute vec2 aTextureCoord;

    uniform mat4 uMVMatrix;
    uniform mat4 uPMatrix;
    uniform mat3 uNMatrix;

    varying vec2 vTextureCoord;

    void main(void) {
        gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition,
     1.0);
        vTextureCoord = aTextureCoord;
    }



    precision mediump float;

    varying vec2 vTextureCoord;

    uniform sampler2D uSampler;

    void main(void) {
        gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.s,
       vTextureCoord.t));
    }

위의 쉐이더는 더 복잡하지만 작동 방법에 대해 자세하게 알 필요는 없습니다.

 

쉐이더 – 기본 사항

WebGL은 2D이기 때문에 2D 좌표 및 해당 색상을 함께 제공해야 합니다. 하지만 나중에 모든 작업이 3D로 수행됩니다. 어떻게 가능한 걸까요? 꼭짓점 쉐이더의 역할은 3D로 수행한 모든 작업을 2D로 변경하고 WebGL로 전달하는 것입니다. 이것이 쉐이더에서 일어나는 일입니다. 3D 개체를 쉐이더로 전달하면 쉐이더는 3D 개체를 2D로 변경하고, 색상을 설정하고, WebGL로 결과를 전달하여 캔버스에서 모든 것을 그립니다.

3D에서 2D로 변경하는 방법에 대한 지침은 투영 행렬(uPMatrix)에 저장됩니다. 두 번째로 중요한 행렬은 모델 뷰 행렬(uMVMatrix)입니다. 개체에서 수행한 모든 작업을 저장합니다. 즉, 일부 개체를 이동하고 다른 개체 크기를 조정하면 이러한 작업에 대한 정보가 모델 뷰 행렬에 저장됩니다.

결론적으로 3D 개체, 3D 개체에서 수행하려는 작업 및 이러한 요소를 2D 좌표로 변환하는 쉐이더와 함께 쉐이더를 제공해야 합니다.

 

쉐이더 초기화

쉐이더가 설정되었으므로, 이제 쉐이더가 컴파일될 수 있도록 코드를 WebGL로 전달해야 합니다. 다음과 같은 방법으로 수행할 수 있습니다.

var vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, str);
gl.compileShader(vertexShader);

and fragment shader:

var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, str);
gl.compileShader(fragmentShader);

 

shaderSource 함수에 전달된 str 변수는 이전 섹션에 설명되어 있는 적합한 쉐이더 구현을 포함해야 합니다.

WebGL에서 쉐이더는 쉐이더 프로그램을 사용하여 처리됩니다. 이 프로그램을 만들고 컴파일된 쉐이더를 이 프로그램에 연결해야 합니다. 쉐이더 없이는 프로그램 쉐이더가 작동하지 않습니다. 다음은 이 작업을 수행하는 방법을 보여주는 샘플 코드입니다(http://learningwebgl.com 블로그 참조).

var fragmentShader = getShader(gl, "shader-fs");
var vertexShader = getShader(gl, "shader-vs");

shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);

if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
    alert("Could not initialise shaders");
}

gl.useProgram(shaderProgram);

전에 언급했듯이 더 복잡한 그림을 그리기 위해서는 개체의 좌표, 색상(또는 텍스처), 투영 행렬 및 모델 뷰 행렬을 포함한 쉐이더를 제공해야 합니다. JavaScript 변수와 쉐이더 변수 사이에 일종의 다리를 만들어 이 작업을 수행할 수 있습니다.  다음 코드 정보는 JavaScript 변수에서 쉐이더 변수로의 데이터 전송을 담당합니다.

shaderProgram.vertexPositionAttribute =
gl.getAttribLocation(shaderProgram,"aVertexPosition");
gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);

shaderProgram.textureCoordAttribute =
gl.getAttribLocation(shaderProgram, "aTextureCoord");
gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute);

shaderProgram.vertexColorAttribute =
gl.getAttribLocation(shaderProgram, "aVertexColor");
gl.enableVertexAttribArray(shaderProgram.vertexColorAttribute);

shaderProgram.pMatrixUniform =
gl.getUniformLocation(shaderProgram, "uPMatrix");
shaderProgram.mvMatrixUniform =
gl.getUniformLocation(shaderProgram, "uMVMatrix");
shaderProgram.nMatrixUniform =
gl.getUniformLocation(shaderProgram, "uNMatrix");
shaderProgram.samplerUniform =
gl.getUniformLocation(shaderProgram, "uSampler");

이제 WebGL이 시작되고 쉐이더가 로드되었습니다.

이제 개체 만들기를 진행할 수 있습니다. 개체를 그리려며 먼저 개체를 생성해야 합니다. WebGL에서 개체를 만들면 꼭짓점, 인덱스 및 색상 또는 텍스처 좌표를 정의하는 것입니다. 이러한 모든 매개 변수는 WebGL 버퍼로 전달되어야 합니다. 그런 다음 개체를 그리려고 할 때마다 이러한 특정 개체를 그리려 한다는 사실을 WebGL에 알리기 위해 이러한 버퍼를 활성으로 설정해야 합니다.

 

WebGL에서 개체 만들기

아래에 간단한 WebGL 개체인 직육면체를 만드는 방법이 설명되어 있습니다. 이것은 Boules 게임의 바닥 개체가 됩니다.

개체를 만들려면 다음을 수행해야 합니다.

다음 연락처로 지정 담당자에게 문의할 수 있습니다. 지정 담당자: Lisa Smiley-Gillis 지정 담당자 주소: 1796 18th Street, Suite C San Francisco, CA 94107 지정 담당자 전화 번호: 1-415-723-9709 지정 담당자 이메일 주소: copyright@linuxfoundation.org 꼭짓점을 정의합니다

WebGL에서 좌표 범위는 -1에서 1까지입니다. 즉 모든 개체의 꼭짓점 좌표가 -1과 1 사이에 있어야 합니다. 나중에 모든 개체를 필요에 맞는 크기로 조정하기 때문에 문제가 되지 않습니다.

바닥 꼭짓점은 아래 그림과 같습니다.

직육면체 좌표직육면체 좌표

 

x축은 빨간색이고 y축은 파란색이며 z는 녹색입니다. 이 좌표계는 OpenGL ES와 정확히 동일합니다.

8개의 꼭짓점이 있으며 꼭짓점 배열은 다음과 같아야 합니다.

var vertices = [
    -1.0, -1.0,  0.0,
     1.0, -1.0,  0.0,
     1.0,  1.0,  0.0,
    -1.0,  1.0,  0.0,

    -1.0, -1.0, -0.1,
     1.0, -1.0, -0.1,
     1.0,  1.0, -0.1,
    -1.0,  1.0, -0.1,
];

이제 이 배열을 버퍼로 변환하고 WebGL에 연결해야 합니다.

groundVertexPositionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, groundVertexPositionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
groundVertexPositionBuffer.itemSize = 3;
groundVertexPositionBuffer.numItems = 8;

 

2. 꼭지점 연결

꼭짓점은 개체를 형성하기 위해 서로 올바르게 연결되어야 합니다. WebGL에서 그린 기본 도형이 삼각형이기 때문에 모든 개체는 삼각형으로부터 만들어야 합니다. 이러한 삼각형은 직육면체의 면을 만듭니다. 간편한 계산으로 12개의 삼각형을 정의하고 좌표에 저장할 배열을 만듭니다.

var cubeVertexIndices = [
    0, 1, 2,      0, 2, 3,
    0, 4, 3,      4, 7, 3,
    0, 4, 1,      1, 5, 4,
    1, 5, 6,      1, 6, 2,
    3, 7, 2,      2, 6, 7,
    7, 4, 6,      6, 4, 5
];

위 배열의 각 숫자는 이전에 정의된 꼭짓점 배열의 인덱스입니다. 따라서 첫 번째 삼각형은 0, 1, 2개 꼭지점으로부터 만들어집니다. 두 번째 삼각형은 0, 2, 3개 꼭짓점으로부터 만들어집니다. 이후 삼각형에도 이와 비슷한 방식이 적용됩니다. 다음은 직육면체 꼭짓점 인덱스를 보여주는 이미지입니다.

직육면체의 꼭짓점 인덱스

직육면체의 꼭짓점 인덱스

이제 버퍼를 만들고 WebGL에 연결합니다.

groundVertexIndexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, groundVertexIndexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(cubeVertexIndices), gl.STATIC_DRAW);
groundVertexIndexBuffer.itemSize = 1;
groundVertexIndexBuffer.numItems = 36;

 

3. 개체 텍스처링

정의된 꼭짓점과 인덱스로 직육면체를 그릴 수 있지만 색상은 없습니다. 텍스처를 만들기 위해 텍스처를 그릴 위치를 프래그먼트 쉐이더가 알 수 있도록 텍스처 좌표를 정의합니다. 각 꼭짓점에는 자체 텍스처 좌표가 있어야 합니다. 텍스처는 2D 이미지입니다. 즉, 각 꼭짓점에 텍스처 점에 해당하는 (x, y) 좌표 쌍이 있습니다. 직육면체가 바닥을 시뮬레이션하기 때문에 위의 삼각형 2개와 아래의 삼각형 2개를 통과하여 잔디 텍스처를 늘여야 합니다. 아래 코드를 참조하십시오.

 

var textureCoords = [
  0.0, 0.0,
  1.0, 0.0,
  1.0, 1.0,
  0.0, 1.0,

  0.0, 0.0,
  1.0, 0.0,
  1.0, 1.0,
  0.0, 1.0,
];

게임 시작 시 점 4, 5, 6, 7로 제한된 직육면체 면은 사용자에게 보이는 바닥이 됩니다. 모든 boule이 이 면에 배치됩니다. 이 때문에 텍스처가 이러한 점 사이를 통과해 늘여야 하고 텍스처 좌표 범위가 4점의 0,0 ~ 6점의 1,1 사이여야 하는 것입니다.

 좌표계를 기반으로 한 버퍼를 만들고 이를 WebGL에 연결해야 합니다.

groundVertexTextureCoordBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, groundVertexTextureCoordBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoords), gl.STATIC_DRAW);
groundVertexTextureCoordBuffer.itemSize = 2;
groundVertexTextureCoordBuffer.numItems = 4;

아직 파일 텍스처를 로드하지 않았습니다. 지금 로드해보겠습니다(자세한 내용은 http://learningwebgl.com 참조).

var texture = gl.createTexture();
texture.image = new Image();
texture.image.onload = function() {
  handleLoadedTexture(texture)
}

texture.image.src = "images/Grass.jpg";

이미지가 로드되면 handleLoadedTexture()가 호출됩니다. 아래 코드를 참조할 수 있습니다.

var handleLoadedTexture = function (texture) {
    gl.bindTexture(gl.TEXTURE_2D, texture);
    gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.image);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
    gl.bindTexture(gl.TEXTURE_2D, null);
  };

텍스처 파일을 로드한 후 WebGL을 사용해서 텍스처 참조를 연결해야 합니다. 이 작업을 수행한 후 텍스처를 활성 상태로 설정할 수 있습니다. 꼭짓점, 인덱스 및 텍스처 좌표가 이미 WebGL에 로드되었고 텍스처 이미지가 로드되어 연결되었기 때문에 바닥 개체 만들기가 완료되었습니다.

WebGL이 그리려는 것을 모르기 때문에 바로 바닥 개체를 그릴 수 없습니다.

 

개체 그리기

그리기 전의 마지막 명령은 개체의 버퍼를 활성 상태로 설정하는 것입니다. 아래의 코드를 사용하여 이 작업을 수행합니다.

gl.bindBuffer(gl.ARRAY_BUFFER, groundVertexPositionBuffer);
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, groundVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);

gl.bindBuffer(gl.ARRAY_BUFFER, groundVertexTextureCoordBuffer);
gl.vertexAttribPointer(shaderProgram.textureCoordAttribute, groundVertexTextureCoordBuffer.itemSize, gl.FLOAT, false, 0, 0);

gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.uniform1i(shaderProgram.samplerUniform, 0);

gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, groundVertexIndexBuffer);

이제 실제로 요소를 그리기 위해 마지막 메서드를 호출해야 합니다.

gl.drawElements(gl.TRIANGLES, groundVertexIndexBuffer.numItems, gl.UNSIGNED_SHORT, 0);

위의 코드는 WebGL이 이미 설정한 활성 버퍼를 그리도록 강제로 설정합니다.

 불행히도, 이 코드는 캔버스에 그림을 그리기에 충분하지 않습니다. 왜냐하면 3D 세계에서는 WebGL이 관점이나 모델 뷰 및 투영 행렬과 같은 몇 가지 다른 매개 변수를 설정해야 하기 때문입니다.

이러한 설정을 지원하기 위해 하나의 추가 라이브러리를 사용합니다. glMatrix는 행렬 작업을 매우 잘 처리하는 빠른 라이브러리입니다.

 

WebGL 설정

몇 가지 중요한 매개 변수를 설정해야 합니다.

  • 캔버스의 배경색을 설정합니다. 이 메서드는 캔버스를 지우고 사용자 지정 RGB 색상으로 채웁니다. 마지막 매개 변수는 transparency입니다.
gl.clearColor(0.0, 0.0, 0.5, 0.5);
  • 버퍼 깊이 활성화:

실제로 z축을 추가합니다. 일반적으로 WebGL은 서로에 요소를 그립니다. 즉, 마지막으로 그려진 요소가 z 좌표에 관계없이 모든 것의 위에 그려집니다. 깊이 버퍼를 활성화할 때 z 매개 변수를 사용하도록 WebGL에 알립니다. 결과적으로 카메라에 가까운 개체는 다른 개체 위에 그려집니다.

gl.enable(gl.DEPTH_TEST);
  • WebGL 크기 설정:
gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
  • 색상 및 깊이 버퍼 지우기

모든 렌더링 반복에서 3D 세계를 올바르게 표시하기 위해 색상과 깊이 버퍼를 지워야 합니다. 그렇지 않으면 이전에 그려진 개체의 흔적이 유지되고 캔버스에 표시됩니다.  

gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

 

관점 및 절두체

원하는 수만큼 개체를 만들고 로드할 수 있습니다. 또한 위치를 지정하고 화면에 그리도록 WebGL에 알릴 수 있습니다. WebGL은 뷰 범위를 벗어난 개체는 렝더링하지 않은 채 카메라 관점에서 보이는 것만 그리므로 시간과 자원이 낭비되지 않습니다. 이것이 바로 관점 메서드를 사용하여 WebGL의 절두체를 지정해야 하는 이유입니다. 절두체가 무엇인지는 아래 이미지를 참조하십시오.

WebGL 절두체

WebGL 절두체

 

절두체는 zNear와 zFar 사이에 있는 피라미드의 오른쪽 부분입니다. 카메라가 왼쪽에 있습니다. perspective() 메서드를 사용하여, 언급된 두 변수(zNear 및 zFar)와 피라미드 각도를 설정합니다. 이제 개체를 표시하려는 경우 이 절두체에 해당 개체를 배치해야 합니다. 그렇지 않으면 캔버스 화면을 렌더링할 때 개체가 고려되지 않습니다.

아래에서 Boules 게임에 내장된 관점을 확인할 수 있습니다.

mat4.perspective(45, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0, pMatrix);

값 45는 피라미드 각도이며 0.1과 100.0은 zNear 및 zFar 설정입니다. 즉, 0.1과 100.0 사이의 z 좌표를 갖는 개체만 화면에 그려집니다. 앞에서 설명한 대로 pMatrix는 3D 장면을 2D 장면으로 변경하는 작업을 맡는 투영 행렬입니다. 그 이유는 WebGL이 본질적으로 2D 공간에서 작동하고 관점을 사용하여 3D 환상을 만들어야 하기 때문입니다. 관점 메서드를 사용하여 투영 행렬을 만드는 방식으로 3D에서 2D로 변환하는 방법에 대한 정보를 쉐이더에 제공합니다.

 

변환 및 회전

개체에서 수행할 수 있는 가장 간단하고 기본적인 작업은 변환과 회전입니다. WebGL에서 개체를 이동하고 개체 크기를 변경하는 데 사용됩니다. 개체에서 수행될 모든 작업은 나중에 쉐이더에서 사용할 모델 뷰 행렬에 저장되어야 합니다. 즉, 각 작업이 행렬에 저장됩니다. 이 작업을 수행하는 가장 간단한 방법은 항등 행렬부터 시작하는 것입니다. 항등 행렬은 개체에 영향을 주지 않는 행렬입니다.

mat4.identity(mvMatrix);

이동과 회전은 다음과 같이 수행됩니다.

mat4.translate(mvMatrix, [0, 0, -4]);
mat4.rotateX(mvMatrix, tiltAngle);
mat4.rotateZ(mvMatrix, twistAngle);

무언가를 변환하려면 x, y 및 z축에서의 이동과 함께 벡터를 전달해야 합니다.

보시다시피 그리려는 개체에 참조를 지정하지 않습니다. 이 때문에 일부 버퍼를 활성 상태로 설정하고 WebGL에서 개체를 그리기 위해 버퍼를 사용하는 것입니다. 또 다른 중요한 점은 그릴 위치를 WebGL에 알리기 위해 좌표를 사용하지 않지만 3D 공간의 카메라를 이동하고 WebGL이 현재 카메라 위치의 관점에서 그린다는 것입니다. 따라서 z축의 시작 부분 가까이 다음 요소를 그리려는 경우 양의 z 값과 함께 translate() 메서드를 사용해야 합니다.

개체의 크기를 조정할 수 있는 함수도 있습니다.

mat4.scale(mvMatrix, [1, gl.viewportHeight/gl.viewportWidth, 1]);

바닥 개체와 함께 이 함수를 사용하여 화면 크기에 맞게 바닥 개체의 크기를 조정합니다.

보시다시피 모델 뷰 행렬에 대한 참조가 이러한 각 함수에 전달됩니다. 덕분에 수행한 모든 작업이 mvMatrix에 직접 저장됩니다. 앞에서 설명한 대로 mvMatrix가 쉐이더에 사용됩니다.

 

4 WebGL 인터페이스는 Box2DWeb에 대 한 제공

지금까지 Box2D 물리 엔진과 WebGL(그리기 환경)에 대해 설명했습니다. 마지막으로 수행해야 할 작업은 이들을 연결하는 것입니다. Boules 게임에서, 요소를 표시하기 위해 WebGL가 간단한 메서드를 제공하는 방식을 채택했으며 Box2D가 그리기 위해 그러한 메서드를 사용합니다.

WebGL 그리기 기능을 게임 로직으로부터 완전히 분리하기로 결정했습니다. 결과적으로 Boules 애플리케이션의 webgl.js 모듈이 만들어졌습니다. 이 모듈은 다음 메서드를 제공합니다.

  • webGLStart(canvas)
    이 메서드는 참조 캔버스에서 WebGL을 초기화합니다.
    이 메서드 호출만으로 그리기 적합하도록 캔버스를 구성하기에 충분합니다. 이 메서드는 WebGL 섹션의 시작 부분에서 설명한 모든 쉐이더 구성을 담당합니다.
  • itSphere(radius, sphereType)
    지정된 유형으로 WebGL에 구체를 만듭니다. 이 함수에서 구체 꼭짓점과 인덱스가 만들어지고 올바른 텍스처가 로드되었습니다. 이 함수는 "WebGL에서 개체 만들기" 절에서 설명한 모든 사항을 담당합니다.
  • drawScene(sphereData, distance, tiltAngle, twistAngle)
    이 함수는 관점 등의 WebGL 설정에 사용됩니다 또한 이전에 만든 모든 구체를 sphereData 변수로 제공된 위치에 그립니다.
    이 함수에서 수행된 작업은 "WebGL 설정", "관점 및 절두체", "개체 그리기", "변환 및 회전" 섹션에 설명되었습니다.

 

렌더링 루프는 game.js 모듈의 업데이트 함수에서 Box2D에 의해 수행됩니다. 각 물리학 계산 후 Box2D는 업데이트 함수를 호출합니다. 이 함수는 구체의 위치 및 카메라와 보드 사이 거리를 업데이트합니다. 이러한 매개 변수는 drawScene 메서드에 전달됩니다. drawScene 메서드가 호출될 때 새로운 프레임이 캔버스에 그려집니다.

 

5 게임 규칙

게임은 인기 게임 Boules(http://en.wikipedia.org/wiki/Boules)을 기반으로 합니다. 이 게임의 목적은 사용자의 boule을 가능한 한 목표 boule(잭) 가까이로 굴리는 것입니다.

 

시작:

모든 플레이어는 한 가지 색상의 boule 2개를 가지고 있습니다. 이러한 boule은 화면의 짧은쪽 가장자리를 따라 배치됩니다. 잭(목표 boule)은 화면의 반대편에 배치됩니다.

 

플레이:

  • 플레이어는 교대로 boule을 이동합니다. boule 이동 후 사용자는 보드를 확대/축소하고 회전시킬 수 있습니다. 다음 플레이어의 차례를 시작하려면 화면을 두드려야 합니다.
  • 각 플레이어는 세 번 움직일 수 있습니다.
  • 플레이어 차례일 때는 아무 boule이나 움직일 수 있습니다(예를 들어 플레이어 boule 1개를 3번 이동하고 다른 boule은 원래 위치에 두거나 boule 1개를 2번 이동하고 다른 boule을 1번 이동합니다).
  • 플레이어는 자신의 boule만 이동시킬 수 있습니다.
  • 잭은 다른 boule과 부딪혔을 때만 이동시킬 수 있습니다.
  • 공의 속도는 이동 벡터 길이에 따라 달라집니다(플레이어의 손가락으로 쓸어넘기는 속도에 따라 결정되지 않음).

 

플레이어의 이동플레이어의 이동

끝:

잭과 플레이어의 boule 사이 거리가 계산됩니다. 잭과 제일 가까이 있는 boule의 플레이어가 승리합니다. 게임이 끝나면 결과가 별도 페이지에 표시됩니다.

결과 화면

결과 화면

 

6개월 동안 문제를 일으키지 않으면 조치가 해제됩니다. 프리젠테이션 요약

이 문서에서는 Box2dWeb 물리 엔진 및 WebGL 그래픽 엔진을 사용하여 Tizen 애플리케이션을 만드는 방법을 설명합니다. 이러한 라이브러리를 사용하여 뛰어난 Tizen용 대화형 게임을 만들 수 있습니다. 또한 이 문서에서는 개발자가 애플리케이션 로직 및 사용자 인터페이스에 초점을 맞출 수 있도록 외부 라이브러리에 의해 모바일 애플리케이션의 물리학이 처리될 수 있다는 것을 보여줍니다.

첨부 파일: 
List
SDK Version Since: 
2.3.1