Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Example for rendering to texture with postprocessing #3070

Closed
wants to merge 3 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
261 changes: 150 additions & 111 deletions examples/graphics/render-to-texture.html
Expand Up @@ -6,6 +6,7 @@
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link rel="icon" type="image/png" href="../playcanvas-favicon.png" />
<script src="../../build/playcanvas.js"></script>
<script src="../assets/scripts/asset-loader.js"></script>
<script src="../../build/playcanvas-extras.js"></script>
<style>
body {
Expand Down Expand Up @@ -35,17 +36,6 @@

// Create the app and start the update loop
var app = new pc.Application(canvas);
app.start();

// Set the canvas to fill the window and automatically change resolution to be the same as the canvas size
app.setCanvasFillMode(pc.FILLMODE_FILL_WINDOW);
app.setCanvasResolution(pc.RESOLUTION_AUTO);

window.addEventListener("resize", function () {
app.resizeCanvas(canvas.width, canvas.height);
});

var miniStats = new pcx.MiniStats(app);

// helper function to create a primitive with shape type, position, scale, color and layer
function createPrimitive(primitiveType, position, scale, color, layer) {
Expand All @@ -70,120 +60,169 @@
return primitive;
}

// create texture and render target for rendering into, including depth buffer
var texture = new pc.Texture(this.app.graphicsDevice, {
width: 512,
height: 256,
format: pc.PIXELFORMAT_R8_G8_B8,
autoMipmap: true,
minFilter: pc.FILTER_LINEAR,
magFilter: pc.FILTER_LINEAR,
addressU: pc.ADDRESS_CLAMP_TO_EDGE,
addressV: pc.ADDRESS_CLAMP_TO_EDGE
});
var renderTarget = new pc.RenderTarget(this.app.graphicsDevice, texture, { depth: true });

// create a layer for object that do not render into texture
var excludedLayer = new pc.Layer({ name: "Excluded" });
app.scene.layers.push(excludedLayer);

// get world and skybox layers
var worldLayer = app.scene.layers.getLayerByName("World");
var skyboxLayer = app.scene.layers.getLayerByName("Skybox");

// create ground plane and 3 primitives, visible in world layer
createPrimitive("plane", new pc.Vec3(0, 0, 0), new pc.Vec3(20, 20, 20), new pc.Color(0.2, 0.4, 0.2), [worldLayer.id]);
createPrimitive("sphere", new pc.Vec3(-2, 1, 0), new pc.Vec3(2, 2, 2), pc.Color.RED, [worldLayer.id]);
createPrimitive("box", new pc.Vec3(2, 1, 0), new pc.Vec3(2, 2, 2), pc.Color.YELLOW, [worldLayer.id]);
createPrimitive("cone", new pc.Vec3(0, 1, -2), new pc.Vec3(2, 2, 2), pc.Color.CYAN, [worldLayer.id]);

// Create main camera, which renders entities in world, excluded and skybox layers
var camera = new pc.Entity("Camera");
camera.addComponent("camera", {
fov: 100,
layers: [worldLayer.id, excludedLayer.id, skyboxLayer.id]
// A list of assets that need to be loaded - "huesaturation" post processing script
var assetManifest = {
huesat: {
type: "script",
url: "../../scripts/posteffects/posteffect-huesaturation.js"
}
};

// Load all assets and then run the example
loadManifestAssets(app, assetManifest, function () {
run();
});
camera.translate(0, 9, 15);
camera.lookAt(1, 4, 0);
app.root.addChild(camera);

// Create texture camera, which renders entities in world and skybox layers into the texture
var textureCamera = new pc.Entity("TextureCamera");
textureCamera.addComponent("camera", {
layers: [worldLayer.id, skyboxLayer.id],
var textureCamera;

// set the priority of textureCamera to lower number than the priority of the main camera (which is at default 0)
// to make it rendered first each frame
priority: -1,
function run() {
app.start();

// this camera renders into texture target
renderTarget: renderTarget
});
// Set the canvas to fill the window and automatically change resolution to be the same as the canvas size
app.setCanvasFillMode(pc.FILLMODE_FILL_WINDOW);
app.setCanvasResolution(pc.RESOLUTION_AUTO);

// add sphere at the position of this camera to see it in the world
textureCamera.addComponent("model", {
type: "sphere"
});
app.root.addChild(textureCamera);

// Create an Entity with a omni light component and add it to world layer (and so used by both cameras)
var light = new pc.Entity();
light.addComponent("light", {
type: "omni",
color: pc.Color.WHITE,
range: 200,
castShadows: true,
layers: [worldLayer.id]
});
light.translate(0, 2, 5);
app.root.addChild(light);

// create a plane called tv which we use to display rendered texture
// this is only added to excluded Layer, so it does not render into texture
var tv = createPrimitive("plane", new pc.Vec3(6, 8, -5), new pc.Vec3(20, 10, 10), pc.Color.BLACK, [excludedLayer.id]);
tv.setLocalEulerAngles(90, 0, 0);
tv.model.castShadows = false;
tv.model.receiveShadows = false;
tv.model.material.emissiveMap = texture; // assign the rendered texture as a emissive texture
tv.model.material.update();

// setup skydome
app.scene.skyboxMip = 0; // use top mipmap level of cubemap (full resolution)

// Load a cubemap asset. This DDS file was 'prefiltered' in the PlayCanvas Editor and then downloaded.
var cubemapAsset = new pc.Asset('helipad.dds', 'cubemap', {
url: "../assets/cubemaps/helipad.dds"
}, {
type: pc.TEXTURETYPE_RGBM
});
app.assets.add(cubemapAsset);
app.assets.load(cubemapAsset);
cubemapAsset.ready(function () {
app.scene.setSkybox(cubemapAsset.resources);
});
window.addEventListener("resize", function () {
app.resizeCanvas(canvas.width, canvas.height);
});

app.scene.gammaCorrection = pc.GAMMA_SRGB;
app.scene.toneMapping = pc.TONEMAP_ACES;
var miniStats = new pcx.MiniStats(app);

// create texture and render target for rendering into, including depth buffer
var texture = new pc.Texture(this.app.graphicsDevice, {
width: 512,
height: 256,
format: pc.PIXELFORMAT_R8_G8_B8,
autoMipmap: true,
minFilter: pc.FILTER_LINEAR,
magFilter: pc.FILTER_LINEAR,
addressU: pc.ADDRESS_CLAMP_TO_EDGE,
addressV: pc.ADDRESS_CLAMP_TO_EDGE
});
var renderTarget = new pc.RenderTarget(this.app.graphicsDevice, texture,
{
depth: true,
name: "tvRenderTarget"
});

// create a layer for object that do not render into texture
var excludedLayer = new pc.Layer({ name: "Excluded" });
app.scene.layers.push(excludedLayer);

// get world and skybox layers
var worldLayer = app.scene.layers.getLayerByName("World");
var skyboxLayer = app.scene.layers.getLayerByName("Skybox");

// create ground plane and 3 primitives, visible in world layer
createPrimitive("plane", new pc.Vec3(0, 0, 0), new pc.Vec3(20, 20, 20), new pc.Color(0.2, 0.4, 0.2), [worldLayer.id]);
createPrimitive("sphere", new pc.Vec3(-2, 1, 0), new pc.Vec3(2, 2, 2), pc.Color.RED, [worldLayer.id]);
createPrimitive("box", new pc.Vec3(2, 1, 0), new pc.Vec3(2, 2, 2), pc.Color.YELLOW, [worldLayer.id]);
createPrimitive("cone", new pc.Vec3(0, 1, -2), new pc.Vec3(2, 2, 2), pc.Color.CYAN, [worldLayer.id]);

// Create main camera, which renders entities in world, excluded and skybox layers
var camera = new pc.Entity("Camera");
camera.addComponent("camera", {
fov: 100,
layers: [worldLayer.id, excludedLayer.id, skyboxLayer.id]
});
camera.translate(0, 9, 15);
camera.lookAt(1, 4, 0);
app.root.addChild(camera);

// Create texture camera, which renders entities in world and skybox layers into the texture
textureCamera = new pc.Entity("TextureCamera");
textureCamera.addComponent("camera", {
layers: [worldLayer.id, skyboxLayer.id],

// set the priority of textureCamera to lower number than the priority of the main camera (which is at default 0)
// to make it rendered first each frame
priority: -1,

// this camera renders into texture target
renderTarget: renderTarget
});

// add script component and attach hueSaturation effect script
// this will apply post processing to the texture the textureCamera renders to
textureCamera.addComponent("script");
textureCamera.script.create("hueSaturation", {
attributes: {
hue: 0.0,
saturation: 0
}
});

// add sphere at the position of this camera to see it in the world
textureCamera.addComponent("model", {
type: "sphere"
});
app.root.addChild(textureCamera);

// Create an Entity with a omni light component and add it to world layer (and so used by both cameras)
var light = new pc.Entity();
light.addComponent("light", {
type: "omni",
color: pc.Color.WHITE,
range: 200,
castShadows: true,
layers: [worldLayer.id]
});
light.translate(0, 2, 5);
app.root.addChild(light);

// create a plane called tv which we use to display rendered texture
// this is only added to excluded Layer, so it does not render into texture
var tv = createPrimitive("plane", new pc.Vec3(6, 8, -5), new pc.Vec3(20, 10, 10), pc.Color.BLACK, [excludedLayer.id]);
tv.setLocalEulerAngles(90, 0, 0);
tv.model.castShadows = false;
tv.model.receiveShadows = false;
tv.model.material.emissiveMap = texture; // assign the rendered texture as a emissive texture
tv.model.material.update();

// setup skydome
app.scene.skyboxMip = 0; // use top mipmap level of cubemap (full resolution)

// Load a cubemap asset. This DDS file was 'prefiltered' in the PlayCanvas Editor and then downloaded.
var cubemapAsset = new pc.Asset('helipad.dds', 'cubemap', {
url: "../assets/cubemaps/helipad.dds"
}, {
type: pc.TEXTURETYPE_RGBM
});
app.assets.add(cubemapAsset);
app.assets.load(cubemapAsset);
cubemapAsset.ready(function () {
app.scene.setSkybox(cubemapAsset.resources);
});

app.scene.gammaCorrection = pc.GAMMA_SRGB;
app.scene.toneMapping = pc.TONEMAP_ACES;
}

// update things each frame
var time = 0;
var switchTime = 0;
app.on("update", function (dt) {
// rotate texture camera around the objects
time += dt;
textureCamera.setLocalPosition(12 * Math.sin(time), 3, 12 * Math.cos(time));
textureCamera.lookAt(pc.Vec3.ZERO);

// every 5 seconds switch texture camera between perspective and orthographic projection
switchTime += dt;
if (switchTime > 5) {
switchTime = 0;
if (textureCamera.camera.projection === pc.PROJECTION_ORTHOGRAPHIC) {
textureCamera.camera.projection = pc.PROJECTION_PERSPECTIVE;
} else {
textureCamera.camera.projection = pc.PROJECTION_ORTHOGRAPHIC;
textureCamera.camera.orthoHeight = 5;

if (textureCamera) {
textureCamera.setLocalPosition(12 * Math.sin(time), 3, 12 * Math.cos(time));
textureCamera.lookAt(pc.Vec3.ZERO);

// every 5 seconds switch texture camera between perspective and orthographic projection
switchTime += dt;
if (switchTime > 5) {
switchTime = 0;
if (textureCamera.camera.projection === pc.PROJECTION_ORTHOGRAPHIC) {
textureCamera.camera.projection = pc.PROJECTION_PERSPECTIVE;
} else {
textureCamera.camera.projection = pc.PROJECTION_ORTHOGRAPHIC;
textureCamera.camera.orthoHeight = 5;
}
}

// apply values in -1 .. 1 range to hue effect
textureCamera.script.hueSaturation.hue = Math.sin(time * 0.3);
}
});
</script>
Expand Down