@animech-public/playcanvas
Version:
PlayCanvas WebGL game engine
133 lines (108 loc) • 4.61 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 = /* glsl */`
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)
{
// calculate splat uv
if (!calcSplatUV()) {
gl_Position = discardVec;
return;
}
// get center
vec3 center = getCenter();
// handle transforms
mat4 model_view = matrix_view * matrix_model;
vec4 splat_cam = model_view * vec4(center, 1.0);
// cull behind camera
if (splat_cam.z > 0.0) {
gl_Position = discardVec;
return;
}
vec4 splat_proj = matrix_projection * splat_cam;
// ensure gaussians are not clipped by camera near and far
splat_proj.z = clamp(splat_proj.z, -abs(splat_proj.w), abs(splat_proj.w));
// get covariance
vec3 covA, covB;
getCovariance(covA, covB);
vec4 v1v2 = calcV1V2(splat_cam.xyz, covA, covB, transpose(mat3(model_view)));
// get color
color = texelFetch(splatColor, splatUV, 0);
// calculate scale based on alpha
float scale = min(1.0, sqrt(-log(1.0 / 255.0 / color.a)) / 2.0);
v1v2 *= scale;
// early out tiny splats
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 = /* glsl */`
varying mediump vec2 texCoord;
varying mediump vec4 color;
void main(void)
{
gl_FragColor = evalSplat(texCoord, color);
}
`;
/**
* @typedef {object} SplatMaterialOptions - The options.
* @property {string} [vertex] - Custom vertex shader, see SPLAT MANY example.
* @property {string} [fragment] - Custom fragment shader, see SPLAT MANY example.
* @property {string} [dither] - Opacity dithering enum.
* @property {string[]} [defines] - List of shader defines.
*
* @ignore
*/
/**
* @param {SplatMaterialOptions} [options] - The options.
* @returns {Material} The GS material.
*/
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 };