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

Support for sRGB framebuffer on WebGPU #6838

Merged
merged 3 commits into from
Jul 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions examples/src/examples/graphics/area-lights.example.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,12 @@ assetListLoader.load(() => {
* @param {string} primitiveType - The primitive type.
* @param {pc.Vec3} position - The position.
* @param {pc.Vec3} scale - The scale.
* @param {pc.Color} color - The color.
* @param {any} assetManifest - The asset manifest.
* @returns {pc.Entity} The returned entity.
*/
function createPrimitive(primitiveType, position, scale, color, assetManifest) {
function createPrimitive(primitiveType, position, scale, assetManifest) {
// create material of specified color
const material = new pc.StandardMaterial();
material.diffuse = color;
material.gloss = 0.8;
material.useMetalness = true;

Expand All @@ -81,7 +79,7 @@ assetListLoader.load(() => {
material.update();

// create primitive
const primitive = new pc.Entity();
const primitive = new pc.Entity(primitiveType);
primitive.addComponent('render', {
type: primitiveType,
material: material
Expand Down Expand Up @@ -194,7 +192,7 @@ assetListLoader.load(() => {
app.scene.envAtlas = assets.helipad.resource;

// create ground plane
createPrimitive('plane', new pc.Vec3(0, 0, 0), new pc.Vec3(20, 20, 20), new pc.Color(0.3, 0.3, 0.3), assets);
createPrimitive('plane', new pc.Vec3(0, 0, 0), new pc.Vec3(20, 20, 20), assets);

// get the instance of the statue and set up with render component
const statue = assets.statue.resource.instantiateRenderEntity();
Expand Down
153 changes: 153 additions & 0 deletions examples/src/examples/graphics/material-transparency.example.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import * as pc from 'playcanvas';
import { deviceType, rootPath } from 'examples/utils';

const canvas = /** @type {HTMLCanvasElement} */ (document.getElementById('application-canvas'));
window.focus();

const assets = {
font: new pc.Asset('font', 'font', { url: rootPath + '/static/assets/fonts/arial.json' })
};

const gfxOptions = {
deviceTypes: [deviceType],
glslangUrl: rootPath + '/static/lib/glslang/glslang.js',
twgslUrl: rootPath + '/static/lib/twgsl/twgsl.js',

// disable anti-aliasing to make dithering more pronounced
antialias: false,

// use sRGB for display format (only supported on WebGPU, fallbacks to LDR on WebGL2)
displayFormat: pc.DISPLAYFORMAT_LDR_SRGB
};

const device = await pc.createGraphicsDevice(canvas, gfxOptions);

// make dithering more pronounced by rendering to lower resolution
device.maxPixelRatio = 1;

const createOptions = new pc.AppOptions();
createOptions.graphicsDevice = device;

createOptions.componentSystems = [
pc.RenderComponentSystem,
pc.CameraComponentSystem,
pc.LightComponentSystem,
pc.ElementComponentSystem
];
createOptions.resourceHandlers = [
pc.TextureHandler,
pc.FontHandler
];

const app = new pc.AppBase(canvas);
app.init(createOptions);

// 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);

// Ensure canvas is resized when window changes size
const resize = () => app.resizeCanvas();
window.addEventListener('resize', resize);
app.on('destroy', () => {
window.removeEventListener('resize', resize);
});

const assetListLoader = new pc.AssetListLoader(Object.values(assets), app.assets);
assetListLoader.load(() => {
app.start();

app.scene.rendering.toneMapping = pc.TONEMAP_LINEAR;

// Create an entity with a camera component
const camera = new pc.Entity();
camera.addComponent('camera', {
clearColor: pc.Color.BLACK
});
camera.translate(0, -0.5, 14);
camera.rotate(0, 0, 0);
app.root.addChild(camera);

const NUM_SPHERES_X = 4;
const NUM_SPHERES_Z = 10;

const ditherOptions = [
pc.DITHER_NONE,
pc.DITHER_BAYER8,
pc.DITHER_BLUENOISE,
pc.DITHER_IGNNOISE
];

/**
* @param {number} x - The x coordinate.
* @param {number} z - The z coordinate.
*/
const createSphere = function (x, z) {
const material = new pc.StandardMaterial();
material.name = `material-${ditherOptions[x]}-${z}`;
material.emissive = new pc.Color(1, 0, 0);
material.specular = new pc.Color(1, 1, 1);
material.metalness = 0.0;
material.gloss = 0.5;
material.useMetalness = true;

if (ditherOptions[x] === pc.DITHER_NONE) {
// alpha blending material
material.blendType = pc.BLEND_NORMAL;
} else {
// alpha dithering material
material.opacityDither = ditherOptions[x];
}

// we want the spheres to seem to fade out in a linear fashion, so we need to convert
// the perceived opacity value from sRGB to linear space
const perceivedOpacity = (z + 1) / NUM_SPHERES_Z;
const linearOpacity = Math.pow(perceivedOpacity, 2.2);
material.opacity = linearOpacity;

material.update();

const sphere = new pc.Entity(`entity-${ditherOptions[x]}-${z}`);
sphere.addComponent('render', {
material: material,
type: 'sphere'
});
sphere.setLocalPosition(1.5 * (x - (NUM_SPHERES_X - 1) * 0.5), z - (NUM_SPHERES_Z - 1) * 0.5, 0);
sphere.setLocalScale(0.9, 0.9, 0.9);
app.root.addChild(sphere);
};
/**
* @param {pc.Asset} fontAsset - The font asset.
* @param {string} message - The message.
* @param {number} x - The x coordinate.
* @param {number} y - The y coordinate.
*/
const createText = function (fontAsset, message, x, y) {
// Create a text element-based entity
const text = new pc.Entity();
text.addComponent('element', {
anchor: [0.5, 0.5, 0.5, 0.5],
fontAsset: fontAsset,
fontSize: 0.3,
pivot: [0.5, 0.5],
text: message,
type: pc.ELEMENTTYPE_TEXT
});
text.setLocalPosition(x, y, 0);
app.root.addChild(text);
};

for (let i = 0; i < NUM_SPHERES_X; i++) {
for (let j = 0; j < NUM_SPHERES_Z; j++) {
createSphere(i, j);
}
}

const y = (NUM_SPHERES_Z + 1) * -0.5;
createText(assets.font, 'Alpha\nBlend', NUM_SPHERES_X * -0.6, y);
createText(assets.font, 'Bayer8\nDither', NUM_SPHERES_X * -0.2, y);
createText(assets.font, 'Blue-noise\nDither', NUM_SPHERES_X * 0.2, y);
createText(assets.font, 'IGN-noise\nDither', NUM_SPHERES_X * 0.6, y);
});

export { app };
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ window.focus();
const assets = {
particlesNumbers: new pc.Asset('particlesNumbers', 'texture', {
url: rootPath + '/static/assets/textures/particles-numbers.png'
})
}, { srgb: true })
};

const gfxOptions = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ window.focus();
const assets = {
particlesCoinsTexture: new pc.Asset('particlesCoinsTexture', 'texture', {
url: rootPath + '/static/assets/textures/particles-coins.png'
}),
}, { srgb: true }),
particlesBonusTexture: new pc.Asset('particlesBonusTexture', 'texture', {
url: rootPath + '/static/assets/textures/particles-bonus.png'
})
}, { srgb: true })
};

const gfxOptions = {
Expand Down
2 changes: 1 addition & 1 deletion examples/src/examples/graphics/particles-snow.example.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const canvas = /** @type {HTMLCanvasElement} */ (document.getElementById('applic
window.focus();

const assets = {
snowflake: new pc.Asset('snowflake', 'texture', { url: rootPath + '/static/assets/textures/snowflake.png' })
snowflake: new pc.Asset('snowflake', 'texture', { url: rootPath + '/static/assets/textures/snowflake.png' }, { srgb: true })
};

const gfxOptions = {
Expand Down
2 changes: 1 addition & 1 deletion examples/src/examples/graphics/particles-spark.example.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const canvas = /** @type {HTMLCanvasElement} */ (document.getElementById('applic
window.focus();

const assets = {
spark: new pc.Asset('spark', 'texture', { url: rootPath + '/static/assets/textures/spark.png' })
spark: new pc.Asset('spark', 'texture', { url: rootPath + '/static/assets/textures/spark.png' }, { srgb: true })
};

const gfxOptions = {
Expand Down
6 changes: 5 additions & 1 deletion examples/src/examples/graphics/post-processing.example.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,11 @@ assetListLoader.load(() => {
const label = new pc.Entity(name);
label.addComponent('element', {
text: text,
color: new pc.Color(100, 50, 80), // very bright color to affect the bloom

// very bright color to affect the bloom - this is not correct, as this is sRGB color that
// is valid only in 0..1 range, but UI does not expose emissive intensity currently
color: new pc.Color(18, 15, 5),

anchor: new pc.Vec4(x, y, 0.5, 0.5),
fontAsset: assets.font,
fontSize: 28,
Expand Down
4 changes: 0 additions & 4 deletions examples/src/examples/graphics/reflection-planar.shader.frag
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,6 @@ uniform vec4 uScreenSize;
// reflection texture
uniform sampler2D uDiffuseMap;

vec3 gammaCorrectOutput(vec3 color) {
return pow(color + 0.0000001, vec3(1.0 / 2.2));
}

void main(void)
{
// sample reflection texture
Expand Down
4 changes: 0 additions & 4 deletions examples/src/examples/graphics/shader-burn.shader.frag
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@ uniform sampler2D uDiffuseMap;
uniform sampler2D uHeightMap;
uniform float uTime;

vec3 gammaCorrectOutput(vec3 color) {
return pow(color + 0.0000001, vec3(1.0 / 2.2));
}

void main(void)
{
float height = texture2D(uHeightMap, vUv0).r;
Expand Down
9 changes: 3 additions & 6 deletions examples/src/examples/graphics/shader-compile.example.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,13 @@ assetListLoader.load(() => {
* @param {string} primitiveType - The primitive type.
* @param {pc.Vec3} position - The position.
* @param {pc.Vec3} scale - The scale.
* @param {pc.Color} color - The color.
* @param {any} assetManifest - The asset manifest.
* @param {boolean} [id] - Prevent shader compilation caching.
* @returns {pc.Entity} The entity.
*/
function createPrimitive(primitiveType, position, scale, color, assetManifest, id = false) {
function createPrimitive(primitiveType, position, scale, assetManifest, id = false) {
// create material of specified color
const material = new pc.StandardMaterial();
material.diffuse = color;
material.gloss = 0.4;
material.useMetalness = true;

Expand Down Expand Up @@ -125,7 +123,7 @@ assetListLoader.load(() => {
app.scene.envAtlas = assets.helipad.resource;

// create ground plane
createPrimitive('plane', new pc.Vec3(0, 0, 0), new pc.Vec3(20, 20, 20), new pc.Color(0.3, 0.3, 0.3), assets);
createPrimitive('plane', new pc.Vec3(0, 0, 0), new pc.Vec3(20, 20, 20), assets);

// Create the camera, which renders entities
const camera = new pc.Entity();
Expand All @@ -142,8 +140,7 @@ assetListLoader.load(() => {
for (let x = -10; x <= 10; x += 6) {
for (let y = -10; y <= 10; y += 6) {
const pos = new pc.Vec3(x, 0.6, y);
const color = new pc.Color(0.3 + Math.random() * 0.7, 0.3 + Math.random() * 0.7, 0.3 + Math.random() * 0.7);
createPrimitive('sphere', pos, new pc.Vec3(1, 1, 1), color, assets, true);
createPrimitive('sphere', pos, new pc.Vec3(1, 1, 1), assets, true);
}
}

Expand Down
13 changes: 2 additions & 11 deletions examples/src/examples/graphics/shader-toon.example.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -87,26 +87,17 @@ assetListLoader.load(() => {
* Set the new material on all meshes in the model, and use original texture from the model on the new material
* @type {pc.Texture | null}
*/
let originalTexture = null;
/** @type {Array<pc.RenderComponent>} */
const renders = entity.findComponents('render');
renders.forEach((render) => {
const meshInstances = render.meshInstances;
for (let i = 0; i < meshInstances.length; i++) {
const meshInstance = meshInstances[i];
if (!originalTexture) {
/** @type {pc.StandardMaterial} */
const originalMaterial = meshInstance.material;
originalTexture = originalMaterial.diffuseMap;
}
render.meshInstances.forEach((meshInstance) => {
meshInstance.material = material;
}
});
});

// material parameters
const lightPosArray = [light.getPosition().x, light.getPosition().y, light.getPosition().z];
material.setParameter('uLightPos', lightPosArray);
material.setParameter('uTexture', originalTexture);
material.update();

// rotate the statue
Expand Down
7 changes: 3 additions & 4 deletions examples/src/examples/graphics/shader-toon.shader.frag
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@

precision mediump float;
uniform sampler2D uTexture;
varying float vertOutTexCoord;
varying vec2 texCoord;
void main(void)
{
float v = vertOutTexCoord;
v = float(int(v * 6.0)) / 6.0;
// vec4 color = texture2D (uTexture, texCoord); // try this to use the diffuse color.
vec4 color = vec4(0.5, 0.47, 0.43, 1.0);
gl_FragColor = color * vec4(v, v, v, 1.0);
vec3 linearColor = vec3(0.218, 0.190, 0.156) * v;
gl_FragColor.rgb = gammaCorrectOutput(linearColor.rgb);
gl_FragColor.a = 1.0;
}
4 changes: 0 additions & 4 deletions examples/src/examples/graphics/shader-wobble.shader.frag
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,6 @@ uniform sampler2D uDiffuseMap;

varying vec2 vUv0;

vec3 gammaCorrectOutput(vec3 color) {
return pow(color + 0.0000001, vec3(1.0 / 2.2));
}

void main(void)
{
vec4 linearColor = texture2D(uDiffuseMap, vUv0);
Expand Down
18 changes: 5 additions & 13 deletions examples/src/examples/graphics/texture-array.example.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -46,18 +46,10 @@ function generateMipmaps(width, height) {
}

const assets = {
rockyTrail: new pc.Asset('rockyTrail', 'texture', {
url: rootPath + '/static/assets/textures/rocky_trail_diff_1k.jpg'
}),
rockBoulder: new pc.Asset('rockBoulder', 'texture', {
url: rootPath + '/static/assets/textures/rock_boulder_cracked_diff_1k.jpg'
}),
coastSand: new pc.Asset('coastSand', 'texture', {
url: rootPath + '/static/assets/textures/coast_sand_rocks_02_diff_1k.jpg'
}),
aerialRocks: new pc.Asset('aeralRocks', 'texture', {
url: rootPath + '/static/assets/textures/aerial_rocks_02_diff_1k.jpg'
}),
rockyTrail: new pc.Asset('rockyTrail', 'texture', { url: rootPath + '/static/assets/textures/rocky_trail_diff_1k.jpg' }, { srgb: true }),
rockBoulder: new pc.Asset('rockBoulder', 'texture', { url: rootPath + '/static/assets/textures/rock_boulder_cracked_diff_1k.jpg' }, { srgb: true }),
coastSand: new pc.Asset('coastSand', 'texture', { url: rootPath + '/static/assets/textures/coast_sand_rocks_02_diff_1k.jpg' }, { srgb: true }),
aerialRocks: new pc.Asset('aeralRocks', 'texture', { url: rootPath + '/static/assets/textures/aerial_rocks_02_diff_1k.jpg' }, { srgb: true }),
script: new pc.Asset('script', 'script', { url: rootPath + '/static/scripts/camera/orbit-camera.js' })
};

Expand Down Expand Up @@ -112,7 +104,7 @@ assetListLoader.load(() => {

const textureArrayOptions = {
name: 'textureArrayImages',
format: pc.PIXELFORMAT_RGBA8,
format: pc.PIXELFORMAT_SRGBA8,
width: 1024,
height: 1024,
arrayLength: 4, // array texture with 4 textures
Expand Down
2 changes: 1 addition & 1 deletion examples/src/examples/graphics/texture-array.ground.frag
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ void main(void)
{
vec4 data = texture(uDiffuseMap, vec3(vUv0, step(vUv0.x, 0.5) + 2.0 * step(vUv0.y, 0.5)));
data.rgb *= 0.8 * max(dot(worldNormal, vec3(0.1, 1.0, 0.5)), 0.0) + 0.5; // simple lighting
gl_FragColor = vec4(data.rgb, 1.0);
gl_FragColor = vec4(gammaCorrectOutput(data.rgb), 1.0);
}
Loading