2017-05-15 9 views
1

자바 스크립트 핸들러에서 이미지로 저장해야하는 Emscripten 기반 webGL 캔버스가 있습니다. 간단한 JS "저장"버튼이 있다고 가정 해 봅시다.Empscripten webGL 캔버스를 JS로 이미지 저장

기본적으로 WebGL 컨텍스트에는 preserveDrawingBuffer가 false로 설정되어 있으므로 결과 이미지가 비어 있습니다.

이미지가 렌더링 된 webGL 장면을 표시하려면 컴파일 된 Empscripten 코드 내에서 getContext 호출에 전달 된 특성에 preserveDrawingBuffer: true을 추가해야합니다. 컴파일 된 empscripten js 코드를 직접 편집하여이 작업을 수행 할 수 있습니다. 결과 이미지가 올바른지,하지만이 해킹을 피하기 위해 싶습니다 - 나는 각각의 재 컴파일 후에 그것을해야만합니다.

외부에서 webGLContextAttributespreserveDrawingBuffer을 더 쉽고 깨끗하게 추가 할 수 있습니까? 즉 emcc의 컴파일 옵션으로 C 코드 내부 또는 호스팅 페이지의 Javascript에서 일부 SDL 매개 변수를 사용할 수 있습니까?

업데이트 해결책은 아래를 참조하십시오. 내가 직면 한 관련없는 문제는 저장된 이미지의 비트 심도가 낮고 앤티 앨리어싱 처리 된 선이 매우 나 빠졌습니다. c.toDataURL("image/jpeg")을 사용하여 해결했습니다.

+0

나는 Emscripten을 전혀 모른다. webgl은 제외하고 webgl 캔버스를 내보내는 더 좋은 방법은 다음 렌더링 루프를 기다리고 현재 js 스레드를 릴리스하기 전에 toDataURL을 호출하는 것입니다. 드로잉 버퍼는 여전히 존재할 것이고'preserveDrawingBuffer' 옵션에 비해 perfs를 향상시킬 것입니다. – Kaiido

+0

@Kaiido 당신이 제안한 접근법의 문제점은 제 경우에 고정 된 프레임 속도를 항상 렌더링하지 않고 새로운 입력 이벤트를 얻은 후에 뿐이라는 것입니다. 언제든지 이미지를 저장하는 Javascript 버튼을 누를 수 있습니다. 그래서 캔버스를 처음으로 강제로 다시 그려야하고 캔버스 렌더링 코드 (C)에서 다른 자바 스크립트 함수를 호출하여 프레임이 끝나기 전에 버퍼를 캡처해야합니다. 불가능하지는 않지만 오히려 퍼포먼스를 지금 당장 받아 들일 것입니다. –

답변

1

우선 emscripten과 모든 라이브러리는 오픈 소스이므로 변경하기 만하면됩니다.

프로젝트 폴더에 특정 사본 library_gl.js에서

다음 -lGL을 제거하고 빌드 스크립트에 --js-library library_gl.js를 추가, 당신은 그 지역 library_gl.js 원하는 작업을 처리하기 위해 해킹 할 수 있습니다.

그렇지 않으면 SDL을 전혀 알지 못하지만 emscripten 코드를 호출하기 전에 상황을 직접 알 수 있습니다. 캔버스에는 하나의 컨텍스트 만있을 수 있습니다. 동일한 컨텍스트 유형에 대해 getContext을 다시 호출하면 동일한 컨텍스트를 얻을 수 있습니다. 자바 스크립트 컨텍스트를 생성하면 당신도 할 수없는 경우 즉 먼저 emscripten 코드는 오버라이드 (override) 할 수있는이

theCanvasElement.getContext("webgl", {preserveDrawingBuffer: true}); 

... now execute emscripten and have it use `theCanvasElement` 

작동합니다 같은 맥락 그래서

을 얻을 것이다 getContext

HTMLCanvasElement.prototype.getContext = (function(oldGetContextFn) { 
    return function(type, attrs) { 
    attrs = attrs || {}; 
    if (type === "webgl") { 
     attrs.preserveDrawingBuffer = true; 
    } 
    return oldGetContextFn.apply(this, type, attrs); 
    }; 
}(HTMLCanvasElement.prototype.getContext)); 
+0

emscripten이 수행하기 전에 컨텍스트를 얻고 원하는 매개 변수를 제공하는 것이 합리적인 생각처럼 보일 때까지 시도해 볼 것입니다. 여전히 해킹이지만 적어도 한 번만해야합니다. –

+0

왜 내가 "해킹"이라고 생각하는지 모르겠습니다. SDL 레벨에서이 문제를 해결하려면 SDL 라이브러리에 패치를 제출하여 [구성 플래그] (https://wiki.libsdl.org/SDL_WindowFlags)를 추가하거나 emscripten에 패치를 제출해야합니다. 다른 emscripten 만 C++ 노출 된 API를 추가하여 특정 플래그를 강제 적용합니다. – gman

+0

은 공격적으로 그런 뜻이 아니라 단지 느낌이 들었습니다. 아마도 getContext가 두 번째로 변경되지 않았기 때문일 것입니다. 어쩌면 API 의미론 일 뿐이며 createContext 호출이 있어야할까요? –