Houdini 20.0 hwebserver

hwebserver.fileResponse function

ファイルの内容を送信するResponseオブジェクトを生成します。

On this page

fileResponse(file_path, content_type=None, delete_file=False, download_as_filename=None):hwebserver.Response

file_path

クライアントへダウンロードするディスク上のファイルパス。

content_type

レスポンスのMIMEコンテンツタイプ。 これがNone(デフォルト)の場合、この関数はmimetypes.guess_type()を使用して、ディスクファイルの拡張子からMIMEタイプが推測されます。

delete_file

これがTrueの場合、サーバーは、ファイルをクライアントに送信した後にそのファイルを削除します。 これは、一時ファイルには便利ですが、コードの挙動を変更してこれを無効にするのを忘れてしまった場合には非常に危険です。

download_as_filename

オプションで、クライアントがダウンロードするファイルのファイル名を指定することができます。 サーバーは、Content-Dispositionヘッダを送信します。

import hou
import hwebserver


@hwebserver.urlHandler("/textures", prefix=True)
def texture_download(request):
    path = request.path()
    assert path.startswith("/textures")
    parm_name = path[10:]
    if not parm_name:
        return hwebserver.notFoundResponse(request)

    node = hou.node("/mat/my_material")
    texture_parm = node.parm(parm_name)
    texture_path = texture_parm.evalAsString()

    return hwebserver.fileResponse(request, texture_path)

関連ファイルの用意

時折、ハンドラーを含んだPythonスクリプトファイル関連のパスを使用してファイルを用意したい場合があります。 通常では、__file__変数には、現在実行中のファイルのパスが入るので、os.path.dirname(__file__)を使用することで、そのファイルが含まれているディレクトリを取得することができます。

しかし、コマンドラインからPythonスクリプトを使ってHoudiniを起動した場合などでは、__file__は定義されていません。 これを補足するには、以下の関数を使用すると良いでしょう:

webutils.py

import os
import inspect


def script_file_dir():
    try:
        file_path = __file__
    except NameError:
        file_path = inspect.getfile(inspect.currentframe())

    if not os.path.isabs(file_path):
        file_path = os.path.normpath(os.path.join(os.getcwd(), file_path))

    return os.path.dirname(file_path)

レンダリング画像のサンプル

import os
import tempfile
import hou
import hwebserver

@hwebserver.urlHandler("/tommy.jpg")
def tommy(request):
    """Mantraを使用してTommyテストジオメトリをレンダリング。"""
    rop = hou.node("/out/tommy_rop")
    if rop is None:
        rop = create_tommy_scene()

    rop.render()
    return hwebserver.fileResponse(rop.evalParm("vm_picture"))

def create_tommy_scene():
    sop = hou.node("/obj").createNode("geo").createNode("testgeometry_tommy")

    cam = hou.node("/obj").createNode("cam", "tommy_cam")
    cam.parmTuple("t").set((0, 1.3, 2.3))

    output_file = os.path.join(tempfile.gettempdir(), "tommy.jpg")
    rop = hou.node("/out").createNode("ifd", "tommy_rop")
    rop.parm("camera").set(cam.path())
    rop.parm("vobject").set(sop.parent().name())
    rop.parm("vm_picture").set(output_file)

    return rop

3Dウェブビューアのサンプル

このサンプルは、GLTF ROPを使用してCragテストジオメトリをGLTFフォーマットに保存し、Babylon.jsを使用してブラウザでそれを表示します。

server.py

import os
import tempfile
import json

import hou
import hwebserver

import webutils


OUTPUT_DIR = os.path.join(webutils.script_file_dir(), "static", "temp")


@hwebserver.urlHandler("/")
def index_view(request):
    return hwebserver.redirect(request, "/static/index.html")


@hwebserver.urlHandler("/static/output/model.gltf")
def gltf_view(request):
    frame = float(request.GET().get("frame", 1))

    # GLTF ROPを使用して一時GLTFファイルを書き出します。
    # これは、処理中に.binとテクスチャを生成します。
    gltf_temp_file = temp_file_path(".gltf")
    hou.parm("/out/gltf1/file").set(gltf_temp_file)
    hou.node("/out/gltf1").render(frame_range=(frame, frame))

    # JSONを読み込んでURIを調整することができますが、その必要はないことに注目してください。
    return hwebserver.fileResponse(
        gltf_temp_file, "application/json",
        delete_file=True)


@hwebserver.urlHandler("/static/output", is_prefix=True)
def temp_output(request):
    # このURLハンドラーは、GLTF用の.binとテクスチャを一時的に用意するのに使用します。
    bin_file_path = os.path.join(OUTPUT_DIR, os.path.basename(request.path()))
    response = hwebserver.fileResponse(
        bin_file_path, "application/octet-stream",
        delete_file=True)
    return response


def temp_file_path(suffix):
    with tempfile.NamedTemporaryFile(
            dir=OUTPUT_DIR, suffix=suffix) as temp_file:
        return temp_file.name


def initialize_scene():
    hou.node("/obj").createNode("geo").createNode("testgeometry_crag")
    hou.node("/out").createNode("gltf")


def run_server():
    if not os.path.exists(OUTPUT_DIR):
        os.makedirs(OUTPUT_DIR)
    initialize_scene()
    hwebserver.registerStaticFilesDirectory(
        os.path.join(webutils.script_file_dir(), "static"))
    hwebserver.run(8008, debug=True)


if __name__ == "__main__":
    run_server()

static/index.html

<script src="https://cdn.babylonjs.com/viewer/babylon.viewer.js"></script>
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="/static/index.js"></script>

<babylon id="babylon-viewer"></babylon>
<br>Frame <input onchange="set_frame(parseInt(this.value, 10))"
    value="1" size="4">

static/index.js

var app = {
    frame: 1,
    viewer: null,
};

BabylonViewer.viewerManager
    .getViewerPromiseById('babylon-viewer').then(function (viewer)
{
    app.viewer = viewer;
    $(viewer.containerElement).css("height", "90%");
    viewer.onEngineInitObservable.add(function (scene) {
        reload_model();
    });
});

function set_frame(frame)
{
    app.frame = frame;
    reload_model();
}

function reload_model()
{
    app.viewer.loadModel({url: "/static/output/model.gltf?frame=" + app.frame});
}
See also

hwebserver

クラス

  • hwebserver.Request

    Houdiniのウェブサーバーに送信されるリクエスト。

  • hwebserver.Response

    Houdiniのウェブサーバーから送り返されるレスポンス。

  • hwebserver.UploadedFile

    Houdiniのウェブサーバーに送信されるリクエストにアップロードされたファイル。

  • URLHandler

    汎用のHTTPハンドラー。

  • AsyncURLHandler

    汎用の非同期HTTPハンドラー。

  • WebSocket

    組み込みサーバーをWebSocketに対応させるための基底クラス。

開始と停止

  • hwebserver.run

    Houdiniのウェブサーバーを開始します。

  • hwebserver.requestShutdown

    すべてのオープンリクエストが処理された後にシャットダウンするようにHoudiniのウェブサーバーに命令します。

  • hwebserver.isInDebugMode

    Houdiniのウェブサーバーがデバッグモード(でdebug=True)で起動されていればTrueを返します。

ウェブリクエストの処理とレスポンスの返し

ウェブソケット

  • WebSocket

    組み込みサーバーをWebSocketに対応させるための基底クラス。

  • hwebserver.webSocket

    HoudiniのウェブサーバーにWebSocketクラスを登録するデコレータ。

APIコール

  • hwebserver.apiFunction

    Houdiniウェブサーバー上のAPIエンドポイント経由で関数をコールを可能にするデコレータで、JSON形式またはバイナリ形式のレスポンスを返します。

  • hwebserver.APIError

    apiFunctionハンドラー内でこの例外を引き起こしてエラーを示します。