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

Add loader for Shader and ShaderChunk asset #2027

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@galacean/engine-core",
"version": "1.2.0-beta.2",
"version": "0.0.0-experimental-shaderlab.1",
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org"
Expand Down
4 changes: 4 additions & 0 deletions packages/core/src/asset/AssetType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ export enum AssetType {
TextureCube = "TextureCube",
/** Material. */
Material = "Material",
/** Shader */
Shader = "Shader",
/** Shader Chunk */
ShaderChunk = "ShaderChunk",
/** Mesh. */
Mesh = "Mesh",
/** AnimationClip. */
Expand Down
2 changes: 1 addition & 1 deletion packages/design/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@galacean/engine-design",
"version": "1.2.0-beta.2",
"version": "0.0.0-experimental-shaderlab.1",
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org"
Expand Down
2 changes: 1 addition & 1 deletion packages/galacean/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@galacean/engine",
"version": "1.2.0-beta.2",
"version": "0.0.0-experimental-shaderlab.1",
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org"
Expand Down
2 changes: 1 addition & 1 deletion packages/loader/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@galacean/engine-loader",
"version": "1.2.0-beta.2",
"version": "0.0.0-experimental-shaderlab.1",
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org"
Expand Down
143 changes: 81 additions & 62 deletions packages/loader/src/MaterialLoader.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
AssetPromise,
AssetType,
Engine,
LoadItem,
Loader,
Material,
Expand Down Expand Up @@ -32,73 +33,91 @@ class MaterialLoader extends Loader<Material> {
})
.then((materialSchema: IMaterialSchema) => {
const engine = resourceManager.engine;
const { name, shader, shaderData, macros, renderState } = materialSchema;
const material = new Material(engine, Shader.find(shader));
material.name = name;
const { shaderRef, shader } = materialSchema;

const texturePromises = new Array<Promise<Texture2D>>();
const materialShaderData = material.shaderData;
for (let key in shaderData) {
const { type, value } = shaderData[key];

switch (type) {
case "Vector2":
materialShaderData.setVector2(key, new Vector2((<IVector2>value).x, (<IVector2>value).y));
break;
case "Vector3":
materialShaderData.setVector3(
key,
new Vector3((<IVector3>value).x, (<IVector3>value).y, (<IVector3>value).z)
);
break;
case "Vector4":
materialShaderData.setVector4(
key,
new Vector4((<IVector4>value).x, (<IVector4>value).y, (<IVector4>value).z, (<IVector4>value).w)
);
break;
case "Color":
materialShaderData.setColor(
key,
new Color((<IColor>value).r, (<IColor>value).g, (<IColor>value).b, (<IColor>value).a)
);
break;
case "Float":
materialShaderData.setFloat(key, <number>value);
break;
case "Texture":
texturePromises.push(
// @ts-ignore
resourceManager.getResourceByRef<Texture2D>(<IAssetRef>value).then((texture) => {
materialShaderData.setTexture(key, texture);
})
);
break;
case "Boolean":
materialShaderData.setInt(key, value ? 1 : 0);
break;
case "Integer":
materialShaderData.setInt(key, Number(value));
break;
}
if (shaderRef) {
resolve(
resourceManager
// @ts-ignore
.getResourceByRef<Shader>(<IAssetRef>shaderRef)
.then((shaderObject) => this.getMaterialByShader(materialSchema, shaderObject, engine))
);
} else {
// compatible with 1.2-pre version material schema
const shaderObject = Shader.find(shader);
resolve(this.getMaterialByShader(materialSchema, shaderObject, engine));
}
})
.catch(reject);
});
}

for (let i = 0, length = macros.length; i < length; i++) {
const { name, value } = macros[i];
if (value == undefined) {
materialShaderData.enableMacro(name);
} else {
materialShaderData.enableMacro(name, value);
}
}
private getMaterialByShader(materialSchema: IMaterialSchema, shader: Shader, engine: Engine): Promise<Material> {
const { name, shaderData, macros, renderState } = materialSchema;

parseProperty(material, "renderState", renderState);
const material = new Material(engine, shader);
material.name = name;

return Promise.all(texturePromises).then(() => {
resolve(material);
});
})
.catch(reject);
const texturePromises = new Array<Promise<Texture2D>>();
const materialShaderData = material.shaderData;
for (let key in shaderData) {
const { type, value } = shaderData[key];

switch (type) {
case "Vector2":
materialShaderData.setVector2(key, new Vector2((<IVector2>value).x, (<IVector2>value).y));
break;
case "Vector3":
materialShaderData.setVector3(
key,
new Vector3((<IVector3>value).x, (<IVector3>value).y, (<IVector3>value).z)
);
break;
case "Vector4":
materialShaderData.setVector4(
key,
new Vector4((<IVector4>value).x, (<IVector4>value).y, (<IVector4>value).z, (<IVector4>value).w)
);
break;
case "Color":
materialShaderData.setColor(
key,
new Color((<IColor>value).r, (<IColor>value).g, (<IColor>value).b, (<IColor>value).a)
);
break;
case "Float":
materialShaderData.setFloat(key, <number>value);
break;
case "Texture":
texturePromises.push(
// @ts-ignore
engine.resourceManager.getResourceByRef<Texture2D>(<IAssetRef>value).then((texture) => {
materialShaderData.setTexture(key, texture);
})
);
break;
case "Boolean":
materialShaderData.setInt(key, value ? 1 : 0);
break;
case "Integer":
materialShaderData.setInt(key, Number(value));
break;
}
}

for (let i = 0, length = macros.length; i < length; i++) {
const { name, value } = macros[i];
if (value == undefined) {
materialShaderData.enableMacro(name);
} else {
materialShaderData.enableMacro(name, value);
}
}

parseProperty(material, "renderState", renderState);

return Promise.all(texturePromises).then(() => {
return material;
});
}
}
33 changes: 33 additions & 0 deletions packages/loader/src/ShaderChunkLoader.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import {
AssetPromise,
AssetType,
LoadItem,
Loader,
ResourceManager,
Shader,
ShaderFactory,
resourceLoader
} from "@galacean/engine-core";

@resourceLoader(AssetType.ShaderChunk, ["glsl"], false)
class ShaderChunkLoader extends Loader<void> {
load(item: LoadItem, resourceManager: ResourceManager): AssetPromise<void> {
return this.request<any>(item.url, { ...item, type: "text" }).then(async (code) => {
const { includeKey } = item.params;
ShaderFactory.registerInclude(includeKey, code);

const matches = code.matchAll(/^[ \t]*#include +"([^$\\"]+)"/gm);
await Promise.all(
Array.from(matches).map((m) => {
const path = m[1];
if (path) {
// @ts-ignore
const resource = resourceManager._virtualPathMap[path];
if (!resource) return;
return resourceManager.load({ type: AssetType.ShaderChunk, url: resource, params: { includeKey: path } });
}
})
);
});
}
}
41 changes: 41 additions & 0 deletions packages/loader/src/ShaderLoader.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import {
AssetPromise,
AssetType,
LoadItem,
Loader,
ResourceManager,
Shader,
resourceLoader
} from "@galacean/engine-core";

@resourceLoader(AssetType.Shader, ["gs", "gsl"], false)
class ShaderLoader extends Loader<Shader> {
load(item: LoadItem, resourceManager: ResourceManager): AssetPromise<Shader> {
return this.request<any>(item.url, { ...item, type: "text" }).then((code: string) => {
const builtinShader = this.getBuiltinShader(code);
if (builtinShader) {
return Shader.find(builtinShader);
}

const matches = code.matchAll(/^[ \t]*#include +"([^$\\"]+)"/gm);
return Promise.all(
Array.from(matches).map((m) => {
const path = m[1];
if (path) {
// @ts-ignore
const resource = resourceManager._virtualPathMap[path];
if (!resource) return;
return resourceManager.load({ type: AssetType.ShaderChunk, url: resource, params: { includeKey: path } });
}
})
).then(() => {
return Shader.create(code);
});
});
}

private getBuiltinShader(code: string) {
const match = code.match(/^\s*\/\/\s*@builtin\s+(\w+)/);
if (match && match[1]) return match[1];
}
}
2 changes: 2 additions & 0 deletions packages/loader/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import "./SpriteLoader";
import "./Texture2DLoader";
import "./TextureCubeLoader";
import "./ktx2/KTX2Loader";
import "./ShaderLoader";
import "./ShaderChunkLoader";

export { GLTFLoader } from "./GLTFLoader";
export type { GLTFParams } from "./GLTFLoader";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,5 @@ export type IBasicType =
export type IAssetRef = { key?: string; refId: string };

export type IEntityRef = { entityId: string };

export type IShaderRef = { refId: string };
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
RenderQueueType,
StencilOperation
} from "@galacean/engine-core";
import type { IAssetRef, IColor, IVector2, IVector3 } from "./BasicSchema";
import type { IAssetRef, IColor, IShaderRef, IVector2, IVector3 } from "./BasicSchema";

export interface IRenderState {
/** Blend state. */
Expand Down Expand Up @@ -96,4 +96,5 @@ export interface IMaterialSchema {
};
macros: Array<{ name: string; value?: string }>;
renderState: IRenderState;
shaderRef: IShaderRef;
}
2 changes: 1 addition & 1 deletion packages/math/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@galacean/engine-math",
"version": "1.2.0-beta.2",
"version": "0.0.0-experimental-shaderlab.1",
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org"
Expand Down
2 changes: 1 addition & 1 deletion packages/physics-lite/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@galacean/engine-physics-lite",
"version": "1.2.0-beta.2",
"version": "0.0.0-experimental-shaderlab.1",
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org"
Expand Down
2 changes: 1 addition & 1 deletion packages/physics-physx/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@galacean/engine-physics-physx",
"version": "1.2.0-beta.2",
"version": "0.0.0-experimental-shaderlab.1",
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org"
Expand Down
2 changes: 1 addition & 1 deletion packages/rhi-webgl/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@galacean/engine-rhi-webgl",
"version": "1.2.0-beta.2",
"version": "0.0.0-experimental-shaderlab.1",
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org"
Expand Down
2 changes: 1 addition & 1 deletion packages/shader-lab/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@galacean/engine-shader-lab",
"version": "1.2.0-beta.2",
"version": "0.0.0-experimental-shaderlab.1",
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org"
Expand Down
15 changes: 6 additions & 9 deletions packages/shader-lab/src/RuntimeContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,11 +138,12 @@ export default class RuntimeContext {

addDiagnostic(diagnostic: IDiagnostic) {
let offset = this._parsingContext.getTextLineOffsetAt(diagnostic.token.start.index);
let token: IPositionRange = { start: { ...diagnostic.token.start }, end: { ...diagnostic.token.end } };
if (offset) {
diagnostic.token.start.line += offset;
diagnostic.token.end.line += offset;
token.start.line += offset;
token.end.line += offset;
}
this._diagnostics.push(diagnostic);
this._diagnostics.push({ ...diagnostic, token });
}

setSerializingNode(node: AstNode) {
Expand Down Expand Up @@ -313,12 +314,8 @@ export default class RuntimeContext {
// If be aware of the complete input macro list when parsing, the snippets below is not required.
getExtendedDefineMacros() {
return Array.from(this._preprocessor._definePairs.entries())
.map(([k, v]) => {
let ret = `#define ${k}`;
if (!v.isFunction) {
ret += ` ${v.replacer}`;
}
return ret;
.map(([_, v]) => {
return v.originText;
})
.join("\n");
}
Expand Down