UNPKG

polygonjs-engine

Version:

node-based webgl 3D engine https://polygonjs.com

165 lines (152 loc) 5.75 kB
import {ShaderMaterial} from 'three/src/materials/ShaderMaterial'; import {Object3D} from 'three/src/core/Object3D'; import {Mesh} from 'three/src/objects/Mesh'; import {Material} from 'three/src/materials/Material'; import {PolyScene} from '../../engine/scene/PolyScene'; import {IUniform} from 'three/src/renderers/shaders/UniformsLib'; import {UniformsUtils} from 'three/src/renderers/shaders/UniformsUtils'; export interface IUniforms { [uniform: string]: IUniform; } export interface MaterialWithUniforms extends Material { uniforms: IUniforms; } enum CustomMaterialName { customDistanceMaterial = 'customDistanceMaterial', customDepthMaterial = 'customDepthMaterial', customDepthDOFMaterial = 'customDepthDOFMaterial', } export interface ObjectWithCustomMaterials extends Mesh { // customDistanceMaterial?: Material; // customDepthMaterial?: Material; customDepthDOFMaterial?: Material; } export interface ShaderMaterialWithCustomMaterials extends ShaderMaterial { custom_materials: { [key in CustomMaterialName]?: ShaderMaterial; }; } export interface MaterialWithSkinning extends Material { skinning: boolean; morphTargets: boolean; } import {WebGLRenderer} from 'three/src/renderers/WebGLRenderer'; import {Scene} from 'three/src/scenes/Scene'; import {Camera} from 'three/src/cameras/Camera'; import {BufferGeometry} from 'three/src/core/BufferGeometry'; import {Geometry} from 'three/src/core/Geometry'; import {Group} from 'three/src/objects/Group'; export type RenderHook = ( renderer: WebGLRenderer, scene: Scene, camera: Camera, geometry: BufferGeometry | Geometry, material: Material, group: Group | null // it's only 'Group', and not 'Group|null' in threejs types, but got null sometimes ) => void; export type RenderHookWithObject = ( renderer: WebGLRenderer, scene: Scene, camera: Camera, geometry: BufferGeometry | Geometry, material: Material, group: Group | null, // it's only 'Group', and not 'Group|null' in threejs types, but got null sometimes object: Object3D ) => void; const RENDER_HOOK_USER_DATA_KEY = 'POLY_render_hook'; interface MaterialWithRenderHook { userData: { [RENDER_HOOK_USER_DATA_KEY]: RenderHookWithObject; }; } const EMPTY_RENDER_HOOK: RenderHook = ( renderer: WebGLRenderer, scene: Scene, camera: Camera, geometry: BufferGeometry | Geometry, material: Material, group: Group | null ) => {}; export class CoreMaterial { static node(scene: PolyScene, material: Material) { return scene.node(material.name); } static clone(src_material: Material | ShaderMaterial) { const cloned_material = src_material.clone(); const src_uniforms = (src_material as ShaderMaterial).uniforms; if (src_uniforms) { (cloned_material as ShaderMaterial).uniforms = UniformsUtils.clone(src_uniforms); } return cloned_material; } // static clone_single(src_material: Material) { // const material = src_material.clone(); // // linewidth doesn't seem cloned correctly for ShaderMaterial // (material as LineBasicMaterial).linewidth = (src_material as LineBasicMaterial).linewidth; // return material; // } static add_user_data_render_hook(material: Material, render_hook: RenderHookWithObject) { material.userData[RENDER_HOOK_USER_DATA_KEY] = render_hook; } static apply_render_hook(object: Object3D, material: MaterialWithRenderHook) { if (material.userData) { const render_hook: RenderHookWithObject = material.userData[RENDER_HOOK_USER_DATA_KEY]; if (render_hook) { object.onBeforeRender = ( renderer: WebGLRenderer, scene: Scene, camera: Camera, geometry: BufferGeometry | Geometry, material: Material, group: Group | null ) => { render_hook(renderer, scene, camera, geometry, material, group, object); }; return; } } // make sure to reset the render hook if apply to a material that does not have any object.onBeforeRender = EMPTY_RENDER_HOOK; } static apply_custom_materials(object: Object3D, material: Material) { const material_with_custom = material as ShaderMaterialWithCustomMaterials; if (material_with_custom.custom_materials) { for (let name of Object.keys(material_with_custom.custom_materials)) { const mat_name = name as CustomMaterialName; // http://blog.edankwan.com/post/three-js-advanced-tips-shadow const custom_material = material_with_custom.custom_materials[mat_name]; if (custom_material) { (object as ObjectWithCustomMaterials)[mat_name] = custom_material; custom_material.needsUpdate = true; } } // object.material = material.custom_materials.customDepthDOFMaterial // object.material = material.custom_materials.customDepthMaterial // object.material = material.custom_materials.customDistanceMaterial } } static assign_custom_uniforms(mat: Material, uniform_name: string, uniform_value: any) { const material = mat as ShaderMaterialWithCustomMaterials; if (material.custom_materials) { for (let name of Object.keys(material.custom_materials)) { const mat_name = name as CustomMaterialName; const custom_material = material.custom_materials[mat_name]; if (custom_material) { custom_material.uniforms[uniform_name].value = uniform_value; } } } } static init_custom_material_uniforms(mat: Material, uniform_name: string, uniform_value: any) { const material = mat as ShaderMaterialWithCustomMaterials; if (material.custom_materials) { for (let name of Object.keys(material.custom_materials)) { const mat_name = name as CustomMaterialName; const custom_material = material.custom_materials[mat_name]; if (custom_material) { custom_material.uniforms[uniform_name] = custom_material.uniforms[uniform_name] || uniform_value; } } } } }