UNPKG

gpu-curtains

Version:

gpu-curtains is a 3D WebGPU rendering engine. It can be used as a standalone 3D engine, but also includes extra classes focused on mapping 3d objects to DOM elements; It allows users to synchronize values such as position, sizing, or scale between them.

411 lines (408 loc) 12 kB
import { Mesh } from '../../core/meshes/Mesh.mjs'; import { isCameraRenderer } from '../../core/renderers/utils.mjs'; import { getFragmentShaderCode } from '../../core/shaders/full/fragment/get-fragment-shader-code.mjs'; import { Vec2 } from '../../math/Vec2.mjs'; import { Vec3 } from '../../math/Vec3.mjs'; import { getVertexShaderCode } from '../../core/shaders/full/vertex/get-vertex-shader-code.mjs'; import { sRGBToLinear } from '../../math/color-utils.mjs'; class LitMesh extends Mesh { /** * LitMesh constructor * @param renderer - {@link CameraRenderer} object or {@link GPUCurtains} class object used to create this {@link LitMesh}. * @param parameters - {@link LitMeshParameters} used to create this {@link LitMesh}. */ constructor(renderer, parameters = {}) { renderer = isCameraRenderer(renderer, "LitMesh"); let { material, ...defaultParams } = parameters; if (!material) material = {}; let { colorSpace } = material; if (!colorSpace) { colorSpace = "srgb"; } const { shading, additionalVaryings, vertexChunks, fragmentChunks, toneMapping, // material uniform values color, opacity, alphaCutoff, metallic, roughness, normalScale, occlusionIntensity, emissiveIntensity, emissiveColor, specularIntensity, specularColor, shininess, transmission, ior, dispersion, thickness, attenuationDistance, attenuationColor, // texture descriptors baseColorTexture, normalTexture, emissiveTexture, occlusionTexture, metallicRoughnessTexture, specularTexture, specularFactorTexture, specularColorTexture, transmissionTexture, thicknessTexture, environmentMap } = material; const materialUniform = LitMesh.getMaterialUniform({ shading, colorSpace, color, opacity, alphaCutoff, metallic, roughness, normalScale, occlusionIntensity, emissiveIntensity, emissiveColor, specularIntensity, specularColor, shininess, transmission, ior, dispersion, thickness, attenuationDistance, attenuationColor, environmentMap }); if (defaultParams.uniforms) { defaultParams.uniforms = { ...defaultParams.uniforms, ...{ material: materialUniform } }; } else { defaultParams.uniforms = { material: materialUniform }; } if (!defaultParams.textures) { defaultParams.textures = []; } if (!defaultParams.samplers) { defaultParams.samplers = []; } const materialTextures = LitMesh.getMaterialTexturesDescriptors({ shading, baseColorTexture, normalTexture, emissiveTexture, occlusionTexture, metallicRoughnessTexture, specularTexture, specularFactorTexture, specularColorTexture, transmissionTexture, thicknessTexture }); materialTextures.forEach((textureDescriptor) => { if (textureDescriptor.sampler) { const samplerExists = defaultParams.samplers.find((s) => s.uuid === textureDescriptor.sampler.uuid); if (!samplerExists) { defaultParams.samplers.push(textureDescriptor.sampler); } } defaultParams.textures.push(textureDescriptor.texture); }); const useEnvMap = environmentMap && (shading === "PBR" || !shading); if (useEnvMap) { if (!defaultParams.textures) { defaultParams.textures = []; } defaultParams.textures = [ ...defaultParams.textures, environmentMap.lutTexture, environmentMap.diffuseTexture, environmentMap.specularTexture ]; if (!defaultParams.samplers) { defaultParams.samplers = []; } defaultParams.samplers = [...defaultParams.samplers, environmentMap.sampler]; } let transmissionBackgroundTexture = null; if (parameters.transmissive) { renderer.createTransmissionTarget(); transmissionBackgroundTexture = { texture: renderer.transmissionTarget.texture, sampler: renderer.transmissionTarget.sampler }; } const extensionsUsed = []; if (dispersion) { extensionsUsed.push("KHR_materials_dispersion"); } const hasNormal = defaultParams.geometry && defaultParams.geometry.getAttributeByName("normal"); if (defaultParams.geometry && !hasNormal) { defaultParams.geometry.computeGeometry(); } const vs = LitMesh.getVertexShaderCode({ bindings: defaultParams.bindings, geometry: defaultParams.geometry, chunks: vertexChunks, additionalVaryings }); const fs = LitMesh.getFragmentShaderCode({ shadingModel: shading, chunks: fragmentChunks, extensionsUsed, receiveShadows: defaultParams.receiveShadows, toneMapping, geometry: defaultParams.geometry, additionalVaryings, materialUniform, baseColorTexture, normalTexture, metallicRoughnessTexture, specularTexture, specularFactorTexture, specularColorTexture, transmissionTexture, thicknessTexture, emissiveTexture, occlusionTexture, transmissionBackgroundTexture, environmentMap }); const shaders = { vertex: { code: vs, entryPoint: "main" }, fragment: { code: fs, entryPoint: "main" } }; super(renderer, { ...defaultParams, ...{ shaders } }); if (useEnvMap) { environmentMap.onRotationAxisChanged(() => { this.uniforms.material.envRotation.value = environmentMap.rotationMatrix; }); } } /** * Get the material {@link BufferBindingParams} to build the material uniform. * @param parameters - {@link GetLitMeshMaterialUniform} parameters. * @returns - Material uniform {@link BufferBindingParams}. */ static getMaterialUniform(parameters) { const { shading, colorSpace, color, opacity, alphaCutoff, metallic, roughness, normalScale, occlusionIntensity, emissiveIntensity, emissiveColor, specularIntensity, specularColor, shininess, transmission, ior, dispersion, thickness, attenuationDistance, attenuationColor, environmentMap } = parameters; const baseUniformStruct = { color: { type: "vec3f", value: color !== void 0 ? colorSpace === "srgb" ? sRGBToLinear(color.clone()) : color.clone() : new Vec3(1) }, opacity: { type: "f32", value: opacity !== void 0 ? opacity : 1 }, alphaCutoff: { type: "f32", value: alphaCutoff !== void 0 ? alphaCutoff : 0.5 } }; const diffuseUniformStruct = { ...baseUniformStruct, normalScale: { type: "vec2f", value: normalScale !== void 0 ? normalScale : new Vec2(1) }, occlusionIntensity: { type: "f32", value: occlusionIntensity !== void 0 ? occlusionIntensity : 1 }, emissiveIntensity: { type: "f32", value: emissiveIntensity !== void 0 ? emissiveIntensity : 1 }, emissiveColor: { type: "vec3f", value: emissiveColor !== void 0 ? colorSpace === "srgb" ? sRGBToLinear(emissiveColor.clone()) : emissiveColor.clone() : new Vec3() } }; const specularUniformStruct = { ...diffuseUniformStruct, specularIntensity: { type: "f32", value: specularIntensity !== void 0 ? specularIntensity : 1 }, specularColor: { type: "vec3f", value: specularColor !== void 0 ? colorSpace === "srgb" ? sRGBToLinear(specularColor.clone()) : specularColor.clone() : new Vec3(1) } }; const phongUniformStruct = { ...specularUniformStruct, shininess: { type: "f32", value: shininess !== void 0 ? shininess : 30 } }; const pbrUniformStruct = { ...specularUniformStruct, metallic: { type: "f32", value: metallic !== void 0 ? metallic : 1 }, roughness: { type: "f32", value: roughness !== void 0 ? roughness : 1 }, transmission: { type: "f32", value: transmission !== void 0 ? transmission : 0 }, ior: { type: "f32", value: ior !== void 0 ? ior : 1.5 }, dispersion: { type: "f32", value: dispersion !== void 0 ? dispersion : 0 }, thickness: { type: "f32", value: thickness !== void 0 ? thickness : 0 }, attenuationDistance: { type: "f32", value: attenuationDistance !== void 0 ? attenuationDistance : Infinity }, attenuationColor: { type: "vec3f", value: attenuationColor !== void 0 ? colorSpace === "srgb" ? sRGBToLinear(attenuationColor.clone()) : attenuationColor.clone() : new Vec3(1) }, ...environmentMap && { envRotation: { type: "mat3x3f", value: environmentMap.rotationMatrix }, envDiffuseIntensity: { type: "f32", value: environmentMap.options.diffuseIntensity }, envSpecularIntensity: { type: "f32", value: environmentMap.options.specularIntensity } } }; const materialStruct = (() => { switch (shading) { case "Unlit": return baseUniformStruct; case "Lambert": return diffuseUniformStruct; case "Phong": return phongUniformStruct; case "PBR": default: return pbrUniformStruct; } })(); return { visibility: ["fragment"], struct: materialStruct }; } /** * Get all the material {@link ShaderTextureDescriptor} as an array. * @param parameters - {@link GetMaterialTexturesDescriptors} parameters. * @returns - Array of {@link ShaderTextureDescriptor} to use. */ static getMaterialTexturesDescriptors(parameters) { const { shading, baseColorTexture, normalTexture, emissiveTexture, occlusionTexture, metallicRoughnessTexture, specularTexture, specularFactorTexture, specularColorTexture, transmissionTexture, thicknessTexture } = parameters; const baseTextures = [baseColorTexture]; const diffuseTextures = [...baseTextures, normalTexture, emissiveTexture, occlusionTexture]; const specularTextures = [ ...diffuseTextures, metallicRoughnessTexture, specularTexture, specularFactorTexture, specularColorTexture ]; const pbrTextures = [...specularTextures, transmissionTexture, thicknessTexture]; const materialTextures = (() => { switch (shading) { case "Unlit": return baseTextures; case "Lambert": return diffuseTextures; case "Phong": return specularTextures; case "PBR": default: return pbrTextures; } })(); return materialTextures.filter(Boolean); } /** * Generate the {@link LitMesh} vertex shader code. * @param parameters - {@link VertexShaderInputParams} used to generate the vertex shader code. * @returns - The vertex shader generated based on the provided parameters. */ static getVertexShaderCode(parameters) { return getVertexShaderCode(parameters); } /** * Generate the {@link LitMesh} fragment shader. * @param parameters - {@link FragmentShaderInputParams} used to build the fragment shader. * @returns - The fragment shader generated based on the provided parameters. */ static getFragmentShaderCode(parameters) { return getFragmentShaderCode(parameters); } } export { LitMesh };