forked from galacean/engine
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathshader-lab.ts
More file actions
244 lines (198 loc) · 7.7 KB
/
Copy pathshader-lab.ts
File metadata and controls
244 lines (198 loc) · 7.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
/**
* @title Shader Lab Planar Shadow
* @category Material
* @thumbnail https://mdn.alipayobjects.com/merchant_appfe/afts/img/A*09QlQ7IQGecAAAAAAAAAAAAADiR2AQ/original
*/
import {
Color,
Shader,
Vector3,
BlinnPhongMaterial,
Camera,
DirectLight,
GLTFResource,
Logger,
MeshRenderer,
PrimitiveMesh,
WebGLEngine,
AmbientLight,
AssetType,
SkyBoxMaterial,
BackgroundMode
} from "@galacean/engine";
import { OrbitControl } from "@galacean/engine-toolkit-controls";
import { ShaderLab } from "@galacean/engine-shaderlab";
// Create ShaderLab
const shaderLab = new ShaderLab();
Logger.enable();
WebGLEngine.create({ canvas: "canvas", shaderLab }).then((engine) => {
engine.canvas.resizeByClientSize();
const scene = engine.sceneManager.activeScene;
const { background } = scene;
const rootEntity = scene.createRootEntity();
const cameraEntity = rootEntity.createChild("camera_node");
cameraEntity.transform.setPosition(5, 5, 10);
cameraEntity.addComponent(Camera);
cameraEntity.addComponent(OrbitControl).target = new Vector3(0, 1, 0);
const lightEntity = rootEntity.createChild("light_node");
lightEntity.addComponent(DirectLight);
lightEntity.transform.setPosition(-10, 10, 10);
lightEntity.transform.lookAt(new Vector3(0, 0, 0));
const planeEntity = rootEntity.createChild("plane_node");
const renderer = planeEntity.addComponent(MeshRenderer);
renderer.mesh = PrimitiveMesh.createPlane(engine, 10, 10);
const planeMaterial = new BlinnPhongMaterial(engine);
planeMaterial.baseColor.set(1.0, 1.0, 1.0, 1.0);
renderer.setMaterial(planeMaterial);
// Create sky
const sky = background.sky;
const skyMaterial = new SkyBoxMaterial(engine);
background.mode = BackgroundMode.Sky;
sky.material = skyMaterial;
sky.mesh = PrimitiveMesh.createCuboid(engine, 1, 1, 1);
Promise.all([
engine.resourceManager
.load<GLTFResource>("https://gw.alipayobjects.com/os/bmw-prod/150e44f6-7810-4c45-8029-3575d36aff30.gltf")
.then((asset) => {
const { defaultSceneRoot } = asset;
rootEntity.addChild(defaultSceneRoot);
defaultSceneRoot.transform.setPosition(0, 1.5, 0);
const lightDirection = lightEntity.transform.worldForward;
const renderers = new Array<MeshRenderer>();
defaultSceneRoot.getComponentsIncludeChildren(MeshRenderer, renderers);
const shadowShader = Shader.find("PlanarShadow");
for (let i = 0, n = renderers.length; i < n; i++) {
const material = renderers[i].getMaterial();
if (!material) continue;
material.shader = shadowShader;
const shaderData = material.shaderData;
shaderData.setFloat("u_planarShadowFalloff", 0.2);
shaderData.setFloat("u_planarHeight", 0.01);
shaderData.setColor("u_planarShadowColor", new Color(0, 0, 0, 1));
shaderData.setVector3("u_lightDir", lightDirection);
}
}),
engine.resourceManager
.load<AmbientLight>({
type: AssetType.Env,
url: "https://gw.alipayobjects.com/os/bmw-prod/f369110c-0e33-47eb-8296-756e9c80f254.bin"
})
.then((ambientLight) => {
scene.ambientLight = ambientLight;
skyMaterial.texture = ambientLight.specularTexture;
skyMaterial.textureDecodeRGBM = true;
})
]);
engine.run();
});
const PlanarShadowShaderSource = `Shader "PlanarShadow" {
SubShader "Default" {
UsePass "pbr/Default/Forward"
Pass "planarShadow" {
// render states
DepthState {
WriteEnabled = true;
}
BlendState blendState {
Enabled = true;
SourceColorBlendFactor = BlendFactor.SourceAlpha;
DestinationColorBlendFactor = BlendFactor.OneMinusSourceAlpha;
SourceAlphaBlendFactor = BlendFactor.One;
DestinationAlphaBlendFactor = BlendFactor.OneMinusSourceAlpha;
}
StencilState {
Enabled = true;
ReferenceValue = 0;
CompareFunctionFront = CompareFunction.Equal;
CompareFunctionBack = CompareFunction.Equal;
FailOperationFront = StencilOperation.Keep;
FailOperationBack = StencilOperation.Keep;
ZFailOperationFront = StencilOperation.Keep;
ZFailOperationBack = StencilOperation.Keep;
PassOperationFront = StencilOperation.IncrementWrap;
PassOperationBack = StencilOperation.IncrementWrap;
}
BlendState = blendState;
RenderQueueType = Transparent;
vec3 u_lightDir;
float u_planarHeight;
vec4 u_planarShadowColor;
float u_planarShadowFalloff;
sampler2D renderer_JointSampler;
float renderer_JointCount;
mat4 renderer_ModelMat;
mat4 camera_VPMat;
#ifdef RENDERER_HAS_SKIN
#ifdef RENDERER_USE_JOINT_TEXTURE
mat4 getJointMatrix(sampler2D smp, float index) {
float base = index / renderer_JointCount;
float hf = 0.5 / renderer_JointCount;
float v = base + hf;
vec4 m0 = texture2D(smp, vec2(0.125, v ));
vec4 m1 = texture2D(smp, vec2(0.375, v ));
vec4 m2 = texture2D(smp, vec2(0.625, v ));
vec4 m3 = texture2D(smp, vec2(0.875, v ));
return mat4(m0, m1, m2, m3);
}
#elif defined(RENDERER_BLENDSHAPE_COUNT)
mat4 renderer_JointMatrix[ RENDERER_JOINTS_NUM ];
#endif
#endif
vec3 ShadowProjectPos(vec4 vertPos) {
vec3 shadowPos;
// get the world space coordinates of the vertex
vec3 worldPos = (renderer_ModelMat * vertPos).xyz;
// world space coordinates of the shadow (the part below the ground is unchanged)
shadowPos.y = min(worldPos.y , u_planarHeight);
shadowPos.xz = worldPos.xz - u_lightDir.xz * max(0.0, worldPos.y - u_planarHeight) / u_lightDir.y;
return shadowPos;
}
struct a2v {
vec4 POSITION;
vec4 JOINTS_0;
vec4 WEIGHTS_0;
};
struct v2f {
vec4 color;
};
v2f vert(a2v v) {
v2f o;
vec4 position = vec4(v.POSITION.xyz, 1.0 );
#ifdef RENDERER_HAS_SKIN
#ifdef RENDERER_USE_JOINT_TEXTURE
mat4 skinMatrix =
v.WEIGHTS_0.x * getJointMatrix(renderer_JointSampler, v.JOINTS_0.x ) +
v.WEIGHTS_0.y * getJointMatrix(renderer_JointSampler, v.JOINTS_0.y ) +
v.WEIGHTS_0.z * getJointMatrix(renderer_JointSampler, v.JOINTS_0.z ) +
v.WEIGHTS_0.w * getJointMatrix(renderer_JointSampler, v.JOINTS_0.w );
#else
mat4 skinMatrix =
v.WEIGHTS_0.x * renderer_JointMatrix[ int( v.JOINTS_0.x ) ] +
v.WEIGHTS_0.y * renderer_JointMatrix[ int( v.JOINTS_0.y ) ] +
v.WEIGHTS_0.z * renderer_JointMatrix[ int( v.JOINTS_0.z ) ] +
v.WEIGHTS_0.w * renderer_JointMatrix[ int( v.JOINTS_0.w ) ];
#endif
position = skinMatrix * position;
#endif
// get the shadow's world space coordinates
vec3 shadowPos = ShadowProjectPos(position);
// convert to clip space
gl_Position = camera_VPMat * vec4(shadowPos, 1.0);
// get the world coordinates of the center point
vec3 center = vec3(renderer_ModelMat[3].x, u_planarHeight, renderer_ModelMat[3].z);
// calculate shadow falloff
float falloff = 0.5 - clamp(distance(shadowPos , center) * u_planarShadowFalloff, 0.0, 1.0);
// shadow color
o.color = u_planarShadowColor;
o.color.a *= falloff;
return o;
}
VertexShader = vert;
FragmentShader = frag;
void frag(v2f i) {
gl_FragColor = i.color;
}
}
}
}`;
Shader.create(PlanarShadowShaderSource);