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

Unified standard + basic shader intro code #4565

Merged
merged 1 commit into from
Aug 19, 2022
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
25 changes: 4 additions & 21 deletions src/graphics/program-lib/programs/basic.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
import {
SEMANTIC_BLENDINDICES, SEMANTIC_BLENDWEIGHT, SEMANTIC_COLOR, SEMANTIC_POSITION, SEMANTIC_TEXCOORD0,
DEVICETYPE_WEBGPU
SEMANTIC_BLENDINDICES, SEMANTIC_BLENDWEIGHT, SEMANTIC_COLOR, SEMANTIC_POSITION, SEMANTIC_TEXCOORD0
} from '../../constants.js';
import { shaderChunks } from '../chunks/chunks.js';

import {
SHADER_DEPTH, SHADER_PICK
} from '../../../scene/constants.js';

import { begin, end, fogCode, precisionCode, skinCode, versionCode } from './common.js';

// Spector integration
const shaderNameCode = '#define SHADER_NAME BasicMaterial\n';
import { vertexIntro, fragmentIntro, begin, end, fogCode, skinCode } from './common.js';

const basic = {
generateKey: function (options) {
Expand Down Expand Up @@ -49,13 +45,7 @@ const basic = {
}

// GENERATE VERTEX SHADER
let code = versionCode(device) + shaderNameCode;

if (device.deviceType === DEVICETYPE_WEBGPU) {
code += shaderChunks.webgpuVS;
} else if (device.webgl2) {
code += shaderChunks.gles3VS;
}
let code = vertexIntro(device, 'BasicShader', options.pass);

// VERTEX SHADER DECLARATIONS
code += shaderChunks.transformDeclVS;
Expand Down Expand Up @@ -109,14 +99,7 @@ const basic = {
const vshader = code;

// GENERATE FRAGMENT SHADER
code = versionCode(device) + precisionCode(device);
code += shaderNameCode;

if (device.deviceType === DEVICETYPE_WEBGPU) {
code += shaderChunks.webgpuPS;
} else if (device.webgl2) {
code += shaderChunks.gles3PS;
}
code = fragmentIntro(device, 'BasicMaterial', options.pass);

// FRAGMENT SHADER DECLARATIONS
if (options.vertexColors) {
Expand Down
108 changes: 97 additions & 11 deletions src/graphics/program-lib/programs/common.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import {
DEVICETYPE_WEBGPU
DEVICETYPE_WEBGPU, DEVICETYPE_WEBGL
} from '../../../graphics/constants.js';

import {
GAMMA_SRGB, GAMMA_SRGBFAST, GAMMA_SRGBHDR,
TONEMAP_ACES, TONEMAP_ACES2, TONEMAP_FILMIC, TONEMAP_HEJL, TONEMAP_LINEAR
} from '../../../scene/constants.js';
import { ShaderPass } from '../../../scene/shader-pass.js';

import { shaderChunks } from '../chunks/chunks.js';

Expand Down Expand Up @@ -55,18 +56,36 @@ function skinCode(device, chunks) {
return "#define BONE_LIMIT " + device.getBoneLimit() + "\n" + chunks.skinConstVS;
}

function precisionCode(device) {
function precisionCode(device, forcePrecision, shadowPrecision) {

// temporarily ignore precision for WebGPU
if (device.deviceType === DEVICETYPE_WEBGPU) {
return '';
}
let code = '';

if (device.deviceType === DEVICETYPE_WEBGL) {

if (forcePrecision && forcePrecision !== 'highp' && forcePrecision !== 'mediump' && forcePrecision !== 'lowp') {
forcePrecision = null;
}

if (forcePrecision) {
if (forcePrecision === 'highp' && device.maxPrecision !== 'highp') {
forcePrecision = 'mediump';
}
if (forcePrecision === 'mediump' && device.maxPrecision === 'lowp') {
forcePrecision = 'lowp';
}
}

let pcode = 'precision ' + device.precision + ' float;\n';
if (device.webgl2) {
pcode += '#ifdef GL2\nprecision ' + device.precision + ' sampler2DShadow;\n#endif\n';
const precision = forcePrecision ? forcePrecision : device.precision;
code = `precision ${precision} float;\n`;

// TODO: this can be only set on shaders with version 300 or more, so make this optional as many
// internal shaders (particles..) are from webgl1 era and don't set any precision. Modified when upgraded.
if (shadowPrecision && device.webgl2) {
code += `precision ${precision} sampler2DShadow;\n`;
}
}
return pcode;

return code;
}

function versionCode(device) {
Expand All @@ -77,6 +96,73 @@ function versionCode(device) {
return device.webgl2 ? "#version 300 es\n" : "";
}

// SpectorJS integration
function getShaderNameCode(name) {
return `#define SHADER_NAME ${name}\n`;
}

function vertexIntro(device, name, pass, extensionCode) {

let code = versionCode(device);

if (device.deviceType === DEVICETYPE_WEBGPU) {

code += shaderChunks.webgpuVS;

} else { // WebGL

if (extensionCode) {
code += extensionCode + "\n";
}

if (device.webgl2) {
code += shaderChunks.gles3VS;
}
}

code += getShaderNameCode(name);
code += ShaderPass.getPassShaderDefine(pass);

return code;
}

function fragmentIntro(device, name, pass, extensionCode, forcePrecision) {

let code = versionCode(device);
code += precisionCode(device, forcePrecision, true);

if (device.deviceType === DEVICETYPE_WEBGPU) {

code += shaderChunks.webgpuPS;

} else { // WebGL

if (extensionCode) {
code += extensionCode + "\n";
}

if (device.webgl2) { // WebGL 2

code += shaderChunks.gles3PS;

} else { // WebGL 1

if (device.extStandardDerivatives) {
code += "#extension GL_OES_standard_derivatives : enable\n";
}
if (device.extTextureLod) {
code += "#extension GL_EXT_shader_texture_lod : enable\n";
code += "#define SUPPORTS_TEXLOD\n";
}
}
}

code += getShaderNameCode(name);
code += ShaderPass.getPassShaderDefine(pass);

return code;
}

function dummyFragmentCode() {
return "void main(void) {gl_FragColor = vec4(0.0);}";
}
Expand All @@ -89,4 +175,4 @@ function end() {
return '}\n';
}

export { begin, end, dummyFragmentCode, fogCode, gammaCode, precisionCode, skinCode, tonemapCode, versionCode };
export { vertexIntro, fragmentIntro, begin, end, dummyFragmentCode, fogCode, gammaCode, precisionCode, skinCode, tonemapCode, versionCode };
74 changes: 6 additions & 68 deletions src/graphics/program-lib/programs/lit-shader.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import {
DEVICETYPE_WEBGPU,
SEMANTIC_ATTR8, SEMANTIC_ATTR9, SEMANTIC_ATTR10, SEMANTIC_ATTR11, SEMANTIC_ATTR12, SEMANTIC_ATTR13, SEMANTIC_ATTR14, SEMANTIC_ATTR15,
SEMANTIC_BLENDINDICES, SEMANTIC_BLENDWEIGHT, SEMANTIC_COLOR, SEMANTIC_NORMAL, SEMANTIC_POSITION, SEMANTIC_TANGENT,
SEMANTIC_TEXCOORD0, SEMANTIC_TEXCOORD1,
Expand All @@ -24,7 +23,7 @@ import {
import { LightsBuffer } from '../../../scene/lighting/lights-buffer.js';
import { ShaderPass } from '../../../scene/shader-pass.js';

import { begin, end, fogCode, gammaCode, precisionCode, skinCode, tonemapCode, versionCode } from './common.js';
import { vertexIntro, fragmentIntro, begin, end, fogCode, gammaCode, skinCode, tonemapCode } from './common.js';
import { validateUserChunks } from '../chunks/chunk-validation.js';

const builtinAttributes = {
Expand Down Expand Up @@ -85,22 +84,6 @@ class LitShader {
this.chunks = shaderChunks;
}

if (options.forceFragmentPrecision &&
options.forceFragmentPrecision !== "highp" &&
options.forceFragmentPrecision !== "mediump" &&
options.forceFragmentPrecision !== "lowp") {
options.forceFragmentPrecision = null;
}

if (options.forceFragmentPrecision) {
if (options.forceFragmentPrecision === "highp" && device.maxPrecision !== "highp") {
options.forceFragmentPrecision = "mediump";
}
if (options.forceFragmentPrecision === "mediump" && device.maxPrecision === "lowp") {
options.forceFragmentPrecision = "lowp";
}
}

this.lighting = (options.lights.length > 0) || !!options.dirLightMap || !!options.clusteredLightingEnabled;
this.reflections = !!options.reflectionSource;
if (!options.useSpecular) options.specularMap = options.glossMap = null;
Expand Down Expand Up @@ -128,17 +111,6 @@ class LitShader {
this.fshader = null;
}

_getPassDefineString(pass) {
if (pass === SHADER_PICK) {
return '#define PICK_PASS\n';
} else if (pass === SHADER_DEPTH) {
return '#define DEPTH_PASS\n';
} else if (ShaderPass.isShadow(pass)) {
return '#define SHADOW_PASS\n';
}
return '';
}

_vsAddBaseCode(code, chunks, options) {
code += chunks.baseVS;
if (options.nineSlicedMode === SPRITE_RENDERMODE_SLICED ||
Expand Down Expand Up @@ -251,8 +223,6 @@ class LitShader {
let code = '';
let codeBody = '';

code += this._getPassDefineString(options.pass);

// code += chunks.baseVS;
code = this._vsAddBaseCode(code, chunks, options);

Expand Down Expand Up @@ -447,49 +417,17 @@ class LitShader {
}
});

let startCode = "";
if (device.webgl2) {
startCode = versionCode(device);
if (chunks.extensionVS) {
startCode += chunks.extensionVS + "\n";
}
startCode += chunks.gles3VS;
} else {
if (chunks.extensionVS) {
startCode = chunks.extensionVS + "\n";
}
}

const startCode = vertexIntro(device, 'LitShader', this.options.pass, chunks.extensionVS);
this.vshader = startCode + this.varyings + code;
}

_fsGetBeginCode() {
let code = '';

if (this.device.webgl2) {
code += versionCode(this.device);
} else {
if (this.device.extStandardDerivatives) {
code += "#extension GL_OES_standard_derivatives : enable\n";
}
if (this.device.extTextureLod) {
code += "#extension GL_EXT_shader_texture_lod : enable\n";
code += "#define SUPPORTS_TEXLOD\n";
}
}

if (this.chunks.extensionPS) {
code += this.chunks.extensionPS + "\n";
}

if (this.device.deviceType === DEVICETYPE_WEBGPU) {
code += this.chunks.webgpuPS;
} else if (this.device.webgl2) {
code += this.chunks.gles3PS;
}
const device = this.device;
const chunks = this.chunks;

code += this.options.forceFragmentPrecision ? "precision " + this.options.forceFragmentPrecision + " float;\n\n" : precisionCode(this.device);
code += this._getPassDefineString(this.options.pass);
const precision = this.options.forceFragmentPrecision;
let code = fragmentIntro(device, 'LitShader', this.options.pass, chunks.extensionPS, precision);

for (let i = 0; i < this.defines.length; i++) {
code += `#define ${this.defines[i]}\n`;
Expand Down
4 changes: 3 additions & 1 deletion src/graphics/shader.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,9 @@ class Shader {
this.definition = definition;
this.name = definition.name || 'Untitled';

Debug.trace(TRACEID_SHADER_ALLOC, `Alloc: Id ${this.id} ${this.name}`);
Debug.trace(TRACEID_SHADER_ALLOC, `Alloc: Id ${this.id} ${this.name}`, {
definition
});

Debug.assert(definition.vshader, 'No vertex shader has been specified when creating a shader.');
Debug.assert(definition.fshader, 'No fragment shader has been specified when creating a shader.');
Expand Down
17 changes: 17 additions & 0 deletions src/scene/shader-pass.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,23 @@ class ShaderPass {
Debug.assert(ShaderPass.isShadow(pass));
return pass;
}

/**
* Returns the define code line for the shader pass.
*
* @param {number} pass - The shader pass.
* @returns {string} - A code line.
*/
static getPassShaderDefine(pass) {
if (pass === SHADER_PICK) {
return '#define PICK_PASS\n';
} else if (pass === SHADER_DEPTH) {
return '#define DEPTH_PASS\n';
} else if (ShaderPass.isShadow(pass)) {
return '#define SHADOW_PASS\n';
}
return '';
}
}

export { ShaderPass };