const ZA = -1;
const LIGHT_RATIO = 32 ;
class module_D3
{
canvas = null;
$Scene = null;
$Camera = null;
$Renderer = null;
$Root = null;
camera_target = new THREE.Vector3(0,0,0);
camera_euler = new THREE.Euler(0,0,0,'YXZ');
MATERIAL = {} ;
LIGHT = {} ;
axis_helper = null ;
Dispose()
{
this.$Renderer?.clear(true, true, true);
for( let id in this.LIGHT )
{ this.$Root.remove(this.LIGHT[id]);
}
this.LIGHT = {};
THREE.Cache.clear();
this.$Renderer.dispose();
this.$Renderer.domElement.remove();
this.canvas = null;
}
constructor()
{
var $aspect = µB.$Config.width / µB.$Config.height;
this.$Root = new THREE.Group();
this.$Scene = new THREE.Scene();
this.$Scene.add( this.$Root );
this.$Camera = new THREE.PerspectiveCamera( 70, $aspect, 0.1, 1000 );
this.$Camera.position.set(0,0,-50*ZA);
this.$Camera.lookAt(0,0,0);
this.$Renderer = new THREE.WebGLRenderer( { antialias:true, alpha:true, stencil:false, preserveDrawingBuffer:true} );
this.$Renderer.setPixelRatio( 1 ) ;
this.$Renderer.setClearColor( 0x000000, 0);
this.$Renderer.setSize(µB.$Config.width,µB.$Config.height,false);
THREE.ColorManagement.enabled = true;
this.$Renderer.outputColorSpace = THREE.LinearSRGBColorSpace ;
this.$Renderer.shadowMap.enabled = true;
this.$Renderer.shadowMap.type = THREE.PCFSoftShadowMap;
Log( "Canvas/D3" );
this.$Renderer.domElement.className = "d3" ;
General.AppendChild(this.$Renderer.domElement);
this.canvas = this.$Renderer.domElement ;
this.canvas.style.zIndex = Z_D3 ;
this.PrepareScene() ;
this.PrepareMaterials() ;
}
PrepareScene()
{
this.create_light( "glow" ) ;
this.light_power( "glow", 25 ) ;
this.create_light( "sun" ) ;
this.move_light( "sun", -5,5,-5 ) ;
this.light_power( "sun", 100 ) ;
}
PrepareMaterials()
{
let DEF = [
{ type:1, id:"normal", roughness:1.00, metalness:0.00 },
{ type:1, id:"metal", roughness:0.30, metalness:0.40 },
{ type:1, id:"glass", roughness:0.05, metalness:0.00, transparent:true },
{ type:2, id:"neon", roughness:1.00, metalness:0.00, transparent:true, emissive:0x888888, blending:THREE.AdditiveBlending, lights:false },
{ type:2, id:"ui", roughness:1.00, metalness:0.00, transparent:true, emissive:0x888888, fog:false, blending:THREE.AdditiveBlending, lights:false, depthTest:false, depthWrite:false }
];
for( let PAINT of DEF )
{
let T = {
color: 0xffffff,
vertexColors: true,
side: PAINT.side??THREE.FrontSide,
transparent: PAINT.transparent??false,
blending: PAINT.blending??THREE.NormalBlending,
depthWrite: PAINT.depthWrite??true,
depthTest: PAINT.depthTest??true,
fog: PAINT.fog??true,
dithering: true
};
if( PAINT.type === 1 )
{
T.roughness = PAINT.roughness;
T.metalness = PAINT.metalness;
T.flatShading = true;
T.emissive = PAINT.emissive??0x0 ;
this.MATERIAL[PAINT.id] = new THREE.MeshStandardMaterial(T) ;
}
else if( PAINT.type === 2 )
{
T.premultipliedAlpha = true;
this.MATERIAL[PAINT.id] = new THREE.MeshBasicMaterial(T) ;
}
}
}
Update()
{
if( µB.$Config.is_autobuild )
{ µB.$Sprite.UpdateDirty();
}
this.$Renderer?.render( this.$Scene, this.$Camera );
}
Resize(x, y)
{
let aspect = x/y ;
this.$Camera.aspect = x/y ;
this.$Camera.updateProjectionMatrix();
this.$Renderer.setSize(x,y,false);
}
IsLight( name, silent=false )
{
if( ! this.LIGHT[name] )
{ if( ! silent )
{ µB.RuntimeError( "Light " + name + " doesn't exist" ) ;
}
return false ;
}
else
{ return true ;
}
}
show_axis()
{
if( this.axis_helper == null )
{ this.axis_helper = new THREE.AxesHelper(3);
this.axis_helper.scale.set(8,8,8*ZA);
this.$Root.add(this.axis_helper);
}
}
hide_axis()
{ if( this.axis_helper != null )
{ this.$Root.remove(this.axis_helper);
this.axis_helper = null ;
}
}
free_camera()
{
this.camera_target = null;
}
move_camera_all($x)
{ this.camera_move($x,$x,$x*ZA) ;
}
move_camera($x, $y, $z)
{
this.$Camera.position.set($x,$y,$z*ZA);
if( this.camera_target )
{ this.$Camera.lookAt(this.camera_target);
}
}
move_camera_by_all($x)
{ this.camera_move_by($x,$x,$x*ZA);
}
move_camera_by($x, $y, $z)
{
this.$Camera.position.x += $x ;
this.$Camera.position.y += $y ;
this.$Camera.position.z += $z*ZA ;
if( this.camera_target )
{ this.$Camera.lookAt(this.camera_target);
}
}
camera_position_set($xyz, $value)
{
if( $xyz === "z" ) $value = $value*ZA ;
this.$Camera.position[$xyz] = $value ;
if( this.camera_target )
{ this.$Camera.lookAt(this.camera_target);
}
}
target_camera( $x,$y,$z )
{
this.camera_target = new THREE.Vector3($x,$y,$z*ZA);
this.$Camera.lookAt(this.camera_target);
}
turn_camera(x, y, z)
{ this.camera_euler.x = x * µB.$Config.deg ;
this.camera_euler.y = y * µB.$Config.deg ;
this.camera_euler.z = z * µB.$Config.deg ;
this.$Camera.setRotationFromEuler( this.camera_euler ) ;
}
turn_camera_by(x, y, z)
{ this.camera_euler.x += x * µB.$Config.deg ;
this.camera_euler.y += y * µB.$Config.deg ;
this.camera_euler.z += z * µB.$Config.deg ;
this.$Camera.setRotationFromEuler( this.camera_euler ) ;
}
hide_fog()
{ this.$Scene.fog = null ;
this.$Scene.background = null ;
}
show_fog( $color, $distance )
{
if( $color == 0 )
{ this.$Scene_fog_off();
}
else
{ let $rgb = µB.$Config.Color2Hex24($color) ;
this.$Scene.fog = new THREE.Fog($rgb, 1, $distance );
this.$Scene.background = new THREE.Color($rgb);
}
}
fov( v )
{
this.$Camera.fov = v*1 ;
this.$Camera.updateProjectionMatrix();
}
delete_light($name)
{
if( this.IsLight($name) )
{
if( this.LIGHT[$name].node.target )
{ this.$Root.remove(this.LIGHT[$name].node.target);
}
this.$Root.remove(this.LIGHT[$name].node);
delete this.LIGHT[$name] ;
}
}
create_light(type)
{ this.create_light_as(type, type);
}
create_light_as(type, id)
{
type = µB.$Config.GetEnum(type);
if( this.IsLight(id,true) )
{ this.delete_light(id);
}
let light = null;
let multiply = 1 ;
if( type == "glow" )
{ light = new THREE.AmbientLight(0xFFFFFF,1);
}
else if( type == "orb" )
{ light = new THREE.PointLight(0xFFFFFF,1,0,1);
multiply = 10 ;
}
else if( type == "sun" )
{ light = new THREE.DirectionalLight(0xFFFFFF,1);
}
else if( type == "shadow" )
{
light = new THREE.DirectionalLight(0xFFFFFF,1);
light.castShadow = true ;
/*
$light.shadow.camera.near=1;
$light.shadow.camera.far=64;
$light.shadow.bias= -0.05;
$light.shadow.camera.left = -50;
$light.shadow.camera.bottom = -50;
$light.shadow.camera.top = 50;
$light.shadow.camera.right = 50;
*/
}
else
{ Guru( "? Light type: "+type ) ;
}
if( light )
{ this.LIGHT[id] = new Light(light,multiply);
this.$Root.add(light);
if( type >= 10 )
{ this.$Root.add(light.target);
}
this.light_power(id, 100);
}
}
show_light(id)
{ if( this.IsLight(id) )
{ this.LIGHT[id].node.visible = true ;
}
}
hide_light(id)
{ if( this.IsLight(id) )
{ this.LIGHT[id].node.visible = false ;
}
}
light_power(id, power)
{
if( this.IsLight(id) )
{ this.LIGHT[id].node.visible = true ;
this.LIGHT[id].node.intensity = this.LIGHT[id].multiply * power / LIGHT_RATIO ;
}
}
light_color(id, color)
{
if( this.IsLight(id) )
{ let rgb = µB.$Config.Color2Hex24( color );
this.LIGHT[id].node.visible = true ;
this.LIGHT[id].node.color.set( rgb ) ;
}
}
target_light(id, x, y, z)
{ if( this.IsLight(id) )
{ if( this.LIGHT[id].node.target )
{ this.LIGHT[id].node.target.position.set(x,y,z*ZA) ;
}
}
}
move_light_all(id, a)
{ this.light_move(id,a,a,a*ZA);
}
move_light(id, x, y, z)
{ if( this.IsLight(id) )
{ this.LIGHT[id].node.position.set(x,y,z*ZA) ;
}
}
move_light_by(id, x, y, z)
{ if( this.IsLight(id) )
{ this.LIGHT[id].node.position.x += x;
this.LIGHT[id].node.position.y += y;
this.LIGHT[id].node.position.z += z*ZA;
}
}
light_position_set(id, xyz, $value)
{ if( xyz === "z" ) value = value*ZA ;
if( this.IsLight(id) )
{ this.LIGHT[id].node.position[xyz] = value ;
}
}
};