@animech-public/playcanvas
Version:
PlayCanvas WebGL game engine
89 lines (86 loc) • 3.47 kB
JavaScript
import { CULLFACE_NONE } from '../../platform/graphics/constants.js';
import { ShaderProcessorOptions } from '../../platform/graphics/shader-processor-options.js';
import { DITHER_NONE, BLEND_NONE, BLEND_NORMAL, SHADER_FORWARDHDR, GAMMA_SRGBHDR, GAMMA_NONE, TONEMAP_LINEAR } from '../constants.js';
import { Material } from '../materials/material.js';
import { getProgramLibrary } from '../shader-lib/get-program-library.js';
import { gsplat } from './shader-generator-gsplat.js';
const splatMainVS = `
uniform vec3 view_position;
uniform sampler2D splatColor;
varying mediump vec2 texCoord;
varying mediump vec4 color;
mediump vec4 discardVec = vec4(0.0, 0.0, 2.0, 1.0);
void main(void)
{
if (!calcSplatUV()) {
gl_Position = discardVec;
return;
}
vec3 center = getCenter();
mat4 model_view = matrix_view * matrix_model;
vec4 splat_cam = model_view * vec4(center, 1.0);
if (splat_cam.z > 0.0) {
gl_Position = discardVec;
return;
}
vec4 splat_proj = matrix_projection * splat_cam;
splat_proj.z = clamp(splat_proj.z, -abs(splat_proj.w), abs(splat_proj.w));
vec3 covA, covB;
getCovariance(covA, covB);
vec4 v1v2 = calcV1V2(splat_cam.xyz, covA, covB, transpose(mat3(model_view)));
color = texelFetch(splatColor, splatUV, 0);
float scale = min(1.0, sqrt(-log(1.0 / 255.0 / color.a)) / 2.0);
v1v2 *= scale;
if (dot(v1v2.xy, v1v2.xy) < 4.0 && dot(v1v2.zw, v1v2.zw) < 4.0) {
gl_Position = discardVec;
return;
}
gl_Position = splat_proj + vec4((vertex_position.x * v1v2.xy + vertex_position.y * v1v2.zw) / viewport * splat_proj.w, 0, 0);
texCoord = vertex_position.xy * scale / 2.0;
#ifdef USE_SH1
vec4 worldCenter = matrix_model * vec4(center, 1.0);
vec3 viewDir = normalize((worldCenter.xyz / worldCenter.w - view_position) * mat3(matrix_model));
color.xyz = max(color.xyz + evalSH(viewDir), 0.0);
#endif
#ifndef DITHER_NONE
id = float(splatId);
#endif
}
`;
const splatMainFS = `
varying mediump vec2 texCoord;
varying mediump vec4 color;
void main(void)
{
gl_FragColor = evalSplat(texCoord, color);
}
`;
const createGSplatMaterial = (options = {}) => {
var _options$dither;
const ditherEnum = (_options$dither = options.dither) != null ? _options$dither : DITHER_NONE;
const dither = ditherEnum !== DITHER_NONE;
const material = new Material();
material.name = 'splatMaterial';
material.cull = CULLFACE_NONE;
material.blendType = dither ? BLEND_NONE : BLEND_NORMAL;
material.depthWrite = dither;
material.getShaderVariant = function (device, scene, defs, unused, pass, sortedLights, viewUniformFormat, viewBindGroupFormat) {
var _options$vertex, _options$fragment;
const programOptions = {
pass: pass,
gamma: pass === SHADER_FORWARDHDR ? scene.gammaCorrection ? GAMMA_SRGBHDR : GAMMA_NONE : scene.gammaCorrection,
toneMapping: pass === SHADER_FORWARDHDR ? TONEMAP_LINEAR : scene.toneMapping,
vertex: (_options$vertex = options.vertex) != null ? _options$vertex : splatMainVS,
fragment: (_options$fragment = options.fragment) != null ? _options$fragment : splatMainFS,
dither: ditherEnum,
defines: options.defines
};
const processingOptions = new ShaderProcessorOptions(viewUniformFormat, viewBindGroupFormat);
const library = getProgramLibrary(device);
library.register('splat', gsplat);
return library.getProgram('splat', programOptions, processingOptions);
};
material.update();
return material;
};
export { createGSplatMaterial };