!1643 优化:重构太阳光助手、射灯助手,更新灯光在WebCAD中的显示

point_light_line
林三 3 years ago committed by ChenX
parent b52c8a83e5
commit 0b69adc0c3

@ -43,8 +43,13 @@ export class CustomUcs implements Command
let xv: Vector3, yv: Vector3, zv: Vector3;
while (true)
{
let xRes = await app.Editor.GetPoint({ Msg: "请点击X轴方向:", BasePoint: p1Res.Point, AllowDrawRubberBand: true });
if (xRes.Status !== PromptStatus.OK)
let xRes = await app.Editor.GetPoint({ Msg: "请点击X轴方向(空格仅修改基点):", BasePoint: p1Res.Point, AllowDrawRubberBand: true, AllowNone: true });
if (xRes.Status === PromptStatus.None)
{
return;
}
else if (xRes.Status !== PromptStatus.OK)
{
app.Editor.UCSMatrix = oldMat;
return;
@ -70,7 +75,7 @@ export class CustomUcs implements Command
while (true)
{
let yRes = await app.Editor.GetPoint({
Msg: "XY轴平面上的点(接受):",
Msg: "XY轴平面上的点(空格接受自动计算坐标系):",
BasePoint: p1Res.Point,
AllowDrawRubberBand: true,
AllowNone: true

@ -3,52 +3,21 @@ import { RectAreaLight } from "../../DatabaseServices/Lights/RectAreaLight";
import { Command } from "../../Editor/CommandMachine";
import { JigUtils } from "../../Editor/JigUtils";
import { PromptStatus } from "../../Editor/PromptResult";
import { Box3, Vector3 } from "three";
import { midPoint, equaln } from "../../Geometry/GeUtils";
import { midPoint } from "../../Geometry/GeUtils";
export class DrawRectAreaLight implements Command
{
async exec()
{
let ptRes = await app.Editor.GetPoint({
Msg: "选择矩形光范围点"
});
if (ptRes.Status === PromptStatus.Cancel)
return;
let light = JigUtils.Draw(new RectAreaLight());
light.ApplyMatrix(app.Editor.UCSMatrix);
let p1 = ptRes.Point;
ptRes = await app.Editor.GetPoint({
Msg: "选择矩形光范围点2",
Callback: p => this.UpdateLight(p1, p, light)
});
if (ptRes.Status === PromptStatus.OK)
{
this.UpdateLight(p1, ptRes.Point, light);
app.Database.ModelSpace.Append(light);
}
}
private UpdateLight(p1: Vector3, p2: Vector3, light: RectAreaLight)
{
let cen = midPoint(p1, p2);
light.Position = cen;
light.Target = cen.add(light.Normal.multiplyScalar(100).negate());
let box = new Box3();
box.setFromPoints([p1, p2].map(p => p.clone().applyMatrix4(app.Editor.UCSMatrixInv)));
let size = box.getSize(new Vector3());
if (equaln(size.x, 0) || equaln(size.y, 0)) return;
if (!equaln(light.Normal.x, 0))
{
light.Width = size.y;
light.Height = size.x;
}
else
let rectRes = await app.Editor.GetRectPoint({ Msg: "选择矩形光范围:" });
if (rectRes.Status === PromptStatus.OK)
{
light.Width = size.x;
light.Height = size.y;
let light = JigUtils.Draw(new RectAreaLight());
light.ApplyMatrix(app.Editor.UCSMatrix);
light.Position = midPoint(rectRes.Point1WCS, rectRes.Point2WCS);
light.Width = Math.abs(rectRes.Width);
light.Height = Math.abs(rectRes.Height);
app.Database.Lights.Append(light);
}
}
}

@ -1,4 +1,4 @@
import { Vector3 } from "three";
import { MathUtils, Vector3 } from "three";
import { app } from "../../ApplicationServices/Application";
import { SpotLight } from "../../DatabaseServices/Lights/SpotLight";
import { Command } from "../../Editor/CommandMachine";
@ -21,18 +21,28 @@ export class DrawSpotLight implements Command
light.ApplyMatrix(app.Editor.UCSMatrix);
light.Position = ptRes.Point;
ptRes = await app.Editor.GetPoint({
Msg: "选择照射目标点",
let ucsRo = app.Editor.UCSMatrix.setPosition(0, 0, 0);
let v = new Vector3();
let anRes = await app.Editor.GetAngle({
Msg: "选择照射角度",
BasePoint: ptRes.Point,
Callback: p => light.Target = p
Callback: an =>
{
an *= MathUtils.DEG2RAD;
v.set(Math.cos(an) * light.Distance, Math.sin(an) * light.Distance, 0);
v.applyMatrix4(ucsRo);
light.Target = v.add(ptRes.Point);
}
});
if (ptRes.Status === PromptStatus.OK)
if (anRes.Status === PromptStatus.OK)
{
light.Target = ptRes.Point;
let an = anRes.Distance * MathUtils.DEG2RAD;
v.set(Math.cos(an) * light.Distance, Math.sin(an) * light.Distance, 0);
v.applyMatrix4(ucsRo);
light.Target = v.add(ptRes.Point);
app.Database.Lights.Append(light);
}
}
}
export class DrawSpotLight2 implements Command
@ -62,6 +72,5 @@ export class DrawSpotLight2 implements Command
if (equalv3(light.Position, target))
light.Target = target.add(light.Normal.multiplyScalar(100).negate());
}
}

@ -538,7 +538,30 @@ function ConverRectAreaLight2Data(light: RectAreaLight)
let ed: any = {};
ed.Id = light.Id?.Index ?? 0;
ed.Type = "RectAreaLight";
ed.OCS = light.OCS.toArray();
let z = light.Normal;//由于UE的坐标轴相反 所以我们翻转它
let x = new Vector3();
let y = new Vector3();
Orbit.ComputUpDirection(z, y, x);
ed.OCS = [
//-z
z.x,
z.y,
z.z,
0,
y.x,
y.y,
y.z,
0,
-x.x,
-x.y,
-x.z,
0,
light.OCSNoClone.elements[12],
light.OCSNoClone.elements[13],
light.OCSNoClone.elements[14],
light.OCSNoClone.elements[15],
];
ed.Width = light.Width;
ed.Height = light.Height;
@ -572,6 +595,9 @@ function ConverHemisphereLight2Data(light: HemisphereLight)
ed.Color = light.Color.toArray();
ed.Intensity = light.Intensity;
ed.AutoExposure = light.AutoExposure;
ed.ExposureCompensation = light.ExposureCompensation;
// light.GroundColor 底色(默认黑色)
// ed.Temperature = light.Temperature;

@ -6,19 +6,22 @@ import { CameraUpdate } from "../GraphicsSystem/CameraUpdate";
let cameraUpdate = new CameraUpdate();
cameraUpdate.SetSize(2028, 2048);
let box = new Box3();
export function DirLightShadowArea(light: DirectionalLight)
export function DirLightShadowArea(light: DirectionalLight, calcBox = true)
{
let box = new Box3();
//场景内的包围盒
for (let obj of app.Viewer.VisibleObjects)
if (obj instanceof Mesh)
box.union(GetBox(obj));
let direction = light.Position.clone().sub(light.Target).normalize();
cameraUpdate.LookAt(direction.negate());
cameraUpdate.ZoomExtensBox3(box);
if (calcBox)
{
box.makeEmpty();
//场景内的包围盒
for (let obj of app.Viewer.VisibleObjects)
if (obj instanceof Mesh)
box.union(GetBox(obj));
cameraUpdate.ZoomExtensBox3(box);
}
light.DrawObject.traverse(o =>
{

@ -10,6 +10,7 @@ import { Box3Ext } from "../../Geometry/Box";
import { FastWireframe2 } from "../../Geometry/CreateWireframe";
import { GenerateExtrudeEdgeGeometry } from "../../Geometry/ExtrudeEdgeGeometry";
import { AsVector3, equaln, equalv2, equalv3, ZeroVec } from "../../Geometry/GeUtils";
import { ScaleUV } from "../../Geometry/UVUtils";
import { RenderType } from "../../GraphicsSystem/RenderType";
import { AutoRecord } from "../AutoRecord";
import { Factory } from "../CADFactory";
@ -198,6 +199,7 @@ export class ExtrudeHole extends Hole
};
let geo = new ExtrudeGeometry(this.ContourCurve.Shape, extrudeSettings);
geo.applyMatrix4(this._contourCurve.OCS);
ScaleUV(geo);
return geo;
}
GetGripOrStretchPoints(dragType: DragPointType)
@ -366,9 +368,10 @@ export class ExtrudeHole extends Hole
}
else if (renderType === RenderType.Physical)
{
return new Object3D().add(
new Mesh(this.MeshGeometry, ColorMaterial.GetConceptualMaterial(this.ColorIndex))
);
let mesh = new Mesh(this.MeshGeometry, this.MeshMaterial);
mesh.castShadow = true;
mesh.receiveShadow = true;
return mesh;
}
else if (renderType === RenderType.Jig)
{
@ -400,7 +403,13 @@ export class ExtrudeHole extends Hole
{
obj.add(...this.GetPrintObject3D());
}
else if (renderType === RenderType.Conceptual || renderType === RenderType.Physical || renderType === RenderType.Physical2)
else if (renderType === RenderType.Physical)
{
let mesh = obj as Mesh;
mesh.geometry = this.MeshGeometry;
mesh.material = this.MeshMaterial;
}
else if (renderType === RenderType.Conceptual || renderType === RenderType.Physical2)
{
obj.add(
new Mesh(this.MeshGeometry, ColorMaterial.GetConceptualMaterial(this.ColorIndex)),

@ -84,6 +84,9 @@ export class EntityRef extends Entity
{
if (o instanceof Mesh)
{
o.castShadow = true;
o.receiveShadow = true;
if (Array.isArray(o.material))
o.material = await Promise.all(o.material.map((m: MeshPhongMaterial) => ConverMaterial2(m, exr, this._url)));
else

@ -1,4 +1,4 @@
import { DirectionalLight as TDirectionalLight, DirectionalLightHelper, Group, MathUtils, Matrix3, Matrix4, Object3D, Vector2, Vector3 } from "three";
import { DirectionalLight as TDirectionalLight, Group, MathUtils, Matrix3, Matrix4, Object3D, Vector2, Vector3 } from "three";
import { HostApplicationServices } from "../../ApplicationServices/HostApplicationServices";
import { UpdateDraw } from "../../Common/Status";
import { equalv3 } from "../../Geometry/GeUtils";
@ -7,6 +7,7 @@ import { AutoRecord } from "../AutoRecord";
import { Factory } from "../CADFactory";
import { CADFiler } from "../CADFiler";
import { Light } from "./Light";
import { SunLightHelper } from "./SunLightHelper";
/**
*
@ -14,6 +15,7 @@ import { Light } from "./Light";
@Factory
export class DirectionalLight extends Light
{
protected _Intensity: number = 50; //强度
//光源源角度 0-50
@AutoRecord LightSourceAngle = 0.5357;
//源软角度角度
@ -63,6 +65,13 @@ export class DirectionalLight extends Light
this.Update();
}
}
get WebIntensity()
{
let x = this._Intensity / 150;
x = Math.pow(x, 0.4);
return x * 7;
}
ApplyMatrix(m: Matrix4)
{
super.ApplyMatrix(m);
@ -88,13 +97,13 @@ export class DirectionalLight extends Light
protected InitDrawObject(renderType: RenderType = RenderType.Wireframe): Object3D
{
let lightGroup = new Group();
let light = new TDirectionalLight(this._LightColor, this._Intensity);
let light = new TDirectionalLight(this._LightColor, this.WebIntensity);
light.castShadow = HostApplicationServices.UseShadow;
light.shadow.camera.matrixAutoUpdate = true;
light.shadow.camera.near = 1;
light.shadow.camera.far = 100000;
light.shadow.mapSize = new Vector2(2048, 2048);
let helper = new DirectionalLightHelper(light, 500);
let helper = new SunLightHelper(light, 500);
helper.lightPlane.matrixAutoUpdate = true;
lightGroup.add(light, helper);
@ -114,16 +123,12 @@ export class DirectionalLight extends Light
en.updateMatrixWorld(true);
let helper = en.children[1] as DirectionalLightHelper;
let helper = en.children[1] as SunLightHelper;
helper.visible = this._ShowHelper;
if (this._ShowHelper)
{
helper.update();
helper.matrix = light.matrix;
helper.lightPlane.lookAt(this._Target);
helper.targetLine.lookAt(this._Target);
let dist = this._Target.distanceTo(this.Position);
helper.targetLine.scale.set(dist, dist, dist);
helper.targetLine.updateMatrix();
}
}

@ -1,4 +1,4 @@
import { Color, HemisphereLight as THemisphereLight, Object3D } from "three";
import { Color, HemisphereLight as THemisphereLight, Light as TLight, Object3D } from "three";
import { RenderType } from "../../GraphicsSystem/RenderType";
import { AutoRecord } from "../AutoRecord";
import { Factory } from "../CADFactory";
@ -9,7 +9,7 @@ import { Light } from "./Light";
export class HemisphereLight extends Light
{
private _GroundColor = new Color(); //UE有这个属性 但是默认是黑的
protected _Intensity = 3;
protected _Intensity = 1;
@AutoRecord AutoExposure = false;//自动曝光
@AutoRecord ExposureCompensation = 1;//默认为1
@ -22,13 +22,18 @@ export class HemisphereLight extends Light
this.Update();
}
get WebIntensity()
{
return this._Intensity / 5;
}
protected InitDrawObject(renderType: RenderType = RenderType.Wireframe): Object3D
{
let light = new THemisphereLight(this.Color, this._LightColor);
let light = new THemisphereLight(this.Color, this._LightColor, this.WebIntensity);
return light;
}
UpdateDrawObject(type: RenderType, en: Object3D)
UpdateDrawObject(type: RenderType, en: TLight)
{
super.UpdateDrawObject(type, en);
let lg = en as THemisphereLight;

@ -1,4 +1,4 @@
import { Color, Object3D, Vector3 } from 'three';
import { Color, Light as TLight, Vector3 } from 'three';
import { UpdateDraw } from '../../Common/Status';
import { ObjectSnapMode } from '../../Editor/ObjectSnapMode';
import { MoveMatrix } from '../../Geometry/GeUtils';
@ -18,7 +18,7 @@ export class Light extends Entity
{
OnlyRenderType = true;
protected _Intensity: number = 2; //强度
protected _LightColor: Color = new Color(0xffffff);//光源颜色
protected _LightColor: Color = new Color();//光源颜色
@AutoRecord Temperature = 6500;//色温
@AutoRecord IndirectLightingIntensity = 1; //0-200 间接光照强度
protected _ShowHelper = false;
@ -35,6 +35,14 @@ export class Light extends Entity
get CaseShadow() { return this._CaseShadow; }
set CaseShadow(v: boolean)
{
if (v === this._CaseShadow) return;
this.WriteAllObjectRecord();
this._CaseShadow = v;
this.Update();
}
get Position()
{
return super.Position;
@ -90,10 +98,10 @@ export class Light extends Entity
this.ApplyMatrix(MoveMatrix(vec));
this.Update();
}
UpdateDrawObject(type: RenderType, en: Object3D)
UpdateDrawObject(type: RenderType, en: TLight)
{
(en as THREE.Light).intensity = this._Intensity;
(en as THREE.Light).color = this._LightColor;
en.intensity = this.WebIntensity;
en.color = this._LightColor;
}
get Intensity()
{
@ -106,6 +114,10 @@ export class Light extends Entity
this._Intensity = v;
this.Update();
}
get WebIntensity()
{
return this._Intensity;
}
protected _ReadFile(file: CADFiler)
{
super._ReadFile(file);

@ -1,4 +1,4 @@
import { Mesh, MeshBasicMaterial, Object3D, PointLight as TPointLight, SphereGeometry } from 'three';
import { Light as TLight, Mesh, MeshBasicMaterial, Object3D, PointLight as TPointLight, SphereGeometry } from 'three';
import { HostApplicationServices } from '../../ApplicationServices/HostApplicationServices';
import { RenderType } from '../../GraphicsSystem/RenderType';
import { AutoRecord } from '../AutoRecord';
@ -15,12 +15,13 @@ export class PointLight extends Light
/**
* ,0
*/
private _Distance: number = 5000;
private _Distance: number = 20000;//20米
protected _Intensity: number = 100; //强度
// 光线沿着光线的距离变暗的量
// 在物理上正确的模式下,衰减 = 2会导致物理上真实的光线衰减。
// 缺省值是1。
private _Decay: number = 0.2;
private _Decay: number = 0.45;
//PointLightComponent
@AutoRecord SourceRadius = 0;//源半径 范围0-300
@ -57,9 +58,18 @@ export class PointLight extends Light
this._Distance = dist;
this.Update();
}
get WebIntensity()
{
let x = this._Intensity / 2000;
x = Math.pow(x, 0.7);
return (x * 2000) / (4 * Math.PI);//流明转cd 文档是4pi
}
protected InitDrawObject(renderType: RenderType = RenderType.Wireframe): Object3D
{
let ptLight = new TPointLight(this._LightColor, this._Intensity, this._Distance, this._Decay);
let ptLight = new TPointLight(this._LightColor, this.WebIntensity, this._Distance, this._Decay);
ptLight.castShadow = HostApplicationServices.UseShadow;
ptLight.shadow.camera.matrixAutoUpdate = true;
ptLight.shadow.camera.far = 10000;
@ -69,7 +79,7 @@ export class PointLight extends Light
ptLight.add(new Mesh(lightGeo, geoMat));
return ptLight;
}
UpdateDrawObject(type: RenderType, en: Object3D)
UpdateDrawObject(type: RenderType, en: TLight)
{
super.UpdateDrawObject(type, en);
let ptLight = en as TPointLight;
@ -82,8 +92,11 @@ export class PointLight extends Light
{
super._ReadFile(file);
let ver = file.Read();
this._Distance = file.Read();
this._Decay = file.Read();
// this._Distance = file.Read();
// this._Decay = file.Read();
//屏蔽原先的2个属性
file.Read();
file.Read();
if (ver > 1)
{

@ -1,5 +1,4 @@
import { BoxBufferGeometry, Group, Matrix4, Mesh, MeshBasicMaterial, Object3D, PlaneBufferGeometry, RectAreaLight as TRectAreaLight, Vector3 } from "three";
import { RectAreaLightHelper } from "three/examples/jsm/helpers/RectAreaLightHelper";
import { Group, Matrix4, Object3D, RectAreaLight as TRectAreaLight, Vector3 } from "three";
import { UpdateDraw } from "../../Common/Status";
import { RenderType } from "../../GraphicsSystem/RenderType";
import { AutoRecord } from "../AutoRecord";
@ -7,11 +6,12 @@ import { Factory } from "../CADFactory";
import { CADFiler } from "../CADFiler";
import { ObjectId } from "../ObjectId";
import { Light } from "./Light";
import { RectAreaLightHelper } from "./RectAreaLightHelper";
@Factory
export class RectAreaLight extends Light
{
protected _Intensity = 3;
protected _Intensity = 100;
private _Target = new Vector3();
private _Width: number = 1;//UE SourceWidth
@ -77,57 +77,48 @@ export class RectAreaLight extends Light
this._Width = v;
this.Update();
}
get WebIntensity()
{
let x = this._Intensity / 2000;
x = Math.pow(x, 0.5);
return (x * 500) / (Math.PI);//流明转cd 文档是4pi
}
protected InitDrawObject(renderType: RenderType = RenderType.Wireframe): Object3D
{
let lightGroup = new Group();
let light = new TRectAreaLight(this.Color, this._Intensity, this._Width, this._Height);
//绘制灯光助手
let rectLightMesh = new Mesh(new PlaneBufferGeometry(), new MeshBasicMaterial({ color: this._LightColor }));
light.add(rectLightMesh);
let helper = new RectAreaLightHelper(light);
// 灯光目标点
let box = new Mesh(new BoxBufferGeometry(50, 50, 50), new MeshBasicMaterial({ color: this._LightColor }));
lightGroup.add(light, helper, box);
lightGroup.matrixAutoUpdate = false;
lightGroup.matrix.copy(this._Matrix);
lightGroup.updateMatrixWorld(true);
let light = new TRectAreaLight(this.Color, this.WebIntensity, this._Width, this._Height);
lightGroup.add(light);
this.UpdateDrawObject(renderType, lightGroup);
return lightGroup;
}
UpdateDrawObject(type: RenderType, en: Object3D)
UpdateDrawObject(type: RenderType, obj: Object3D)
{
let lg = en.children[0] as TRectAreaLight;
super.UpdateDrawObject(type, lg);
lg.width = this._Width;
lg.height = this._Height;
lg.lookAt(this._Target);
let mesh = lg.children[0] as Mesh;
mesh.visible = this._ShowHelper;
mesh.scale.x = lg.width;
mesh.scale.y = lg.height;
(mesh.material as MeshBasicMaterial).color = this._LightColor;
let light = obj.children[0] as TRectAreaLight;
super.UpdateDrawObject(type, light);
light.width = this._Width;
light.height = this._Height;
light.color.copy(this.Color);
light.lookAt(this._Target);
// light.castShadow = true;//threejs没有支持这个影子
let helper = en.children[1] as RectAreaLightHelper;
helper.visible = this._ShowHelper;
if (this._ShowHelper)
if (this._ShowHelper || true)
{
helper.matrix = lg.matrix;
helper.update();
helper.lookAt(this._Target);
}
let help: RectAreaLightHelper;
if (obj.children.length === 1)
{
help = new RectAreaLightHelper(light, light.color);
obj.add(help);
}
else
help = obj.children[1] as RectAreaLightHelper;
let box = en.children[2] as Mesh;
box.visible = this._ShowHelper;
if (this._ShowHelper)
help.updateMatrixWorld();
}
else
{
box.matrix.identity();
box.applyMatrix4(new Matrix4().setPosition(this.Target.applyMatrix4(this.OCSInv)));
box.updateMatrixWorld(true);
if (obj.children.length > 1)
obj.children[1].visible = false;
}
}
protected _ReadFile(file: CADFiler)

@ -0,0 +1,102 @@
import { BackSide, BufferGeometry, Color, Float32BufferAttribute, Line, LineBasicMaterial, Mesh, MeshBasicMaterial, RectAreaLight as TRectAreaLight } from "three";
/**
* This helper must be added as a child of the light (threejs)
*/
export class RectAreaLightHelper extends Line
{
light: TRectAreaLight;
color: Color;
material: LineBasicMaterial;
children: [Mesh];
constructor(light: TRectAreaLight, color: Color)
{
const positions = [1, 1, 0, -1, 1, 0, -1, -1, 0, 1, -1, 0, 1, 1, 0,
0.618, 0.618, 0,
0.618, 0.618, -100,
0.618, 0.618, 0,
-0.618, 0.618, 0,
-1, 1, 0,
-0.618, 0.618, 0,
-0.618, 0.618, -100,
-0.618, 0.618, 0,
-0.618, -0.618, 0,
-1, -1, 0,
-0.618, -0.618, 0,
-0.618, -0.618, -100,
-0.618, -0.618, 0,
0.618, -0.618, 0,
1, -1, 0,
0.618, -0.618, 0,
0.618, -0.618, -100,
0.618, -0.618, 0,
0.618, 0.618, 0
];
const geometry = new BufferGeometry();
geometry.setAttribute('position', new Float32BufferAttribute(positions, 3));
geometry.computeBoundingSphere();
const material = new LineBasicMaterial({ fog: false });
super(geometry, material);
this.light = light;
this.color = color; // optional hardwired color for the helper
this.type = 'RectAreaLightHelper';
//
const positions2 = [1, 1, 0, -1, 1, 0, -1, -1, 0, 1, 1, 0, -1, -1, 0, 1, -1, 0];
const geometry2 = new BufferGeometry();
geometry2.setAttribute('position', new Float32BufferAttribute(positions2, 3));
geometry2.computeBoundingSphere();
this.add(new Mesh(geometry2, new MeshBasicMaterial({ side: BackSide, fog: false, transparent: true, opacity: 0.8 })));
}
updateMatrixWorld()
{
this.scale.set(0.5 * this.light.width, 0.5 * this.light.height, 1);
if (this.color !== undefined)
{
this.material.color.set(this.color);
//@ts-ignore
this.children[0].material.color.set(this.color);
}
else
{
this.material.color.copy(this.light.color).multiplyScalar(this.light.intensity);
// prevent hue shift
const c = this.material.color;
const max = Math.max(c.r, c.g, c.b);
if (max > 1)
c.multiplyScalar(1 / max);
//@ts-ignore
this.children[0].material.color.copy(this.material.color);
}
// ignore world scale on light
this.matrixWorld.extractRotation(this.light.matrixWorld).scale(this.scale).copyPosition(this.light.matrixWorld);
this.children[0].matrixWorld.copy(this.matrixWorld);
}
dispose()
{
this.geometry.dispose();
this.material.dispose();
this.children[0].geometry.dispose();
//@ts-ignore
this.children[0].material.dispose();
}
}

@ -1,4 +1,4 @@
import { BufferGeometry, ConeGeometry, Group, Line, Matrix4, Mesh, MeshBasicMaterial, Object3D, SpotLight as TSpotLight, SpotLightHelper, Vector3 } from "three";
import { BufferGeometry, ConeGeometry, Group, Line, Matrix4, Mesh, MeshBasicMaterial, Object3D, SpotLight as TSpotLight, Vector3 } from "three";
import { HostApplicationServices } from "../../ApplicationServices/HostApplicationServices";
import { ColorMaterial } from "../../Common/ColorPalette";
import { UpdateDraw } from "../../Common/Status";
@ -10,6 +10,7 @@ import { AutoRecord } from "../AutoRecord";
import { Factory } from "../CADFactory";
import { CADFiler } from "../CADFiler";
import { Light } from "./Light";
import { SpotLightHelper } from "./SpotLightHelper";
@Factory
export class SpotLight extends Light
@ -19,6 +20,7 @@ export class SpotLight extends Light
* Default 0.0.
*/
private _Distance: number = 5000;
protected _Intensity: number = 100; //强度
// 光线沿着光线的距离变暗的量
// 在物理上正确的模式下,衰减 = 2会导致物理上真实的光线衰减。
@ -59,6 +61,7 @@ export class SpotLight extends Light
this.Update();
}
}
get Angle()
{
return this._Angle;
@ -103,6 +106,13 @@ export class SpotLight extends Light
{
return this.Position.add(this.Target.sub(this.Position).normalize().multiplyScalar(this._Distance));
}
get WebIntensity()
{
let x = this._Intensity / 2000;
x = Math.pow(x, 0.45);
return (x * 125) / Math.PI;//流明转cd 文档是4pi
}
ApplyMatrix(m: Matrix4)
{
super.ApplyMatrix(m);
@ -157,7 +167,7 @@ export class SpotLight extends Light
// if (renderType !== RenderType.Physical) return;
let lightGroup = new Group();
let light = new TSpotLight(this._LightColor, this._Intensity, this._Distance, this._Angle, this._Penumbra, this._Decay);
let light = new TSpotLight(this._LightColor, this.WebIntensity, this._Distance, this._Angle, this._Penumbra, this._Decay);
light.castShadow = HostApplicationServices.UseShadow;
light.shadow.camera.matrixAutoUpdate = true;
light.shadow.camera.far = this._Distance;
@ -193,6 +203,7 @@ export class SpotLight extends Light
light.decay = this._Decay;
light.angle = this._Angle;
light.penumbra = this._Penumbra;
let con = light.children[0] as Mesh;
con.lookAt(this._Target);
con.updateMatrixWorld(false);
@ -212,9 +223,12 @@ export class SpotLight extends Light
if (this._ShowHelper)
{
helper.matrix = light.matrix;
helper.InnerConeAngle = this.InnerConeAngle;
helper.update();
helper.cone.lookAt(light.target.position);
helper.cone.updateMatrix();
helper.cone[0].lookAt(light.target.position);
helper.cone[1].lookAt(light.target.position);
helper.cone[0].updateMatrix();
helper.cone[1].updateMatrix();
}
}
protected _ReadFile(file: CADFiler)

@ -0,0 +1,90 @@
import { BufferGeometry, Float32BufferAttribute, LineBasicMaterial, LineSegments, MathUtils, Matrix4, Object3D, SpotLight, Vector3 } from 'three';
export class SpotLightHelper extends Object3D
{
light: SpotLight;
matrix: Matrix4;
/**
* @default false
*/
matrixAutoUpdate: boolean;
cone: LineSegments[];
material: LineBasicMaterial[];
InnerConeAngle: number;
constructor(light: SpotLight)
{
const geometry = new BufferGeometry();
const positions = [
0, 0, 0, 0, 0, 1,
0, 0, 0, 1, 0, 1,
0, 0, 0, - 1, 0, 1,
0, 0, 0, 0, 1, 1,
0, 0, 0, 0, - 1, 1
];
for (let i = 0, j = 1, l = 32; i < l; i++, j++)
{
const p1 = (i / l) * Math.PI * 2;
const p2 = (j / l) * Math.PI * 2;
positions.push(
Math.cos(p1), Math.sin(p1), 1,
Math.cos(p2), Math.sin(p2), 1
);
}
geometry.setAttribute('position', new Float32BufferAttribute(positions, 3));
super();
this.light = light;
this.light.updateMatrixWorld();
this.matrix = light.matrixWorld;
this.matrixAutoUpdate = false;
this.material = [];
this.material[0] = new LineBasicMaterial({ fog: false });;
this.material[1] = new LineBasicMaterial({ fog: false });;
this.InnerConeAngle = 0;
this.cone = [];
this.cone[0] = new LineSegments(geometry, this.material[0]);
this.cone[1] = new LineSegments(geometry, this.material[1]);
this.add(this.cone[0], this.cone[1]);
}
dispose()
{
this.InnerConeAngle = undefined;
this.material[0].dispose();
this.material[1].dispose();
this.cone[0].geometry.dispose();
this.cone[1].geometry.dispose();
//@ts-ignore
this.cone[0].material.dispose();
//@ts-ignore
this.cone[1].material.dispose();
}
update()
{
this.light.updateMatrixWorld();
const coneLength = this.light.distance ? this.light.distance : 1000;
const coneWidth1 = coneLength * Math.tan(this.light.angle);
const coneWidth2 = coneLength * Math.tan(MathUtils.degToRad(this.InnerConeAngle));
this.cone[0].scale.set(coneWidth1, coneWidth1, coneLength);
this.cone[1].scale.set(coneWidth2, coneWidth2, coneLength);
this.cone[0].lookAt(new Vector3().setFromMatrixPosition(this.light.target.matrixWorld));
this.cone[1].lookAt(new Vector3().setFromMatrixPosition(this.light.target.matrixWorld));
//@ts-ignore
this.cone[0].material.color.set(this.light.color).multiplyScalar(0.3);
//@ts-ignore
this.cone[1].material.color.set(this.light.color);
}
}

@ -0,0 +1,33 @@
import { Color, DirectionalLight, DirectionalLightHelper, LineBasicMaterial, Matrix4, Mesh, SphereBufferGeometry } from "three";
export class SunLightHelper extends DirectionalLightHelper
{
light: DirectionalLight;
children: [Mesh];
size: number;
/**
* @default undefined
*/
color: Color | string | number;
matrix: Matrix4;
constructor(light: DirectionalLight, size: number, color?: Color)
{
const geometry = new SphereBufferGeometry(1, 16, 16);
const material = new LineBasicMaterial({ fog: false });
material.color = light.color;
super(light, size, color);
this.children[0].geometry = geometry.scale(400, 400, 400);
this.children[0].material = material;
this.light = light;
this.color = color;
}
/**
* @default false
*/
matrixAutoUpdate: boolean;
}

@ -99,8 +99,8 @@ export class PhysicalMaterialRecord extends MaterialTableRecord
if (this.type === "玻璃")
this.material.metalness = 0.2;
else
this.material.metalness = Math.min(0.8, this.matalness);
// else
// this.material.metalness = Math.max(0.01, this.matalness);
this.material.opacity = Math.max(0.1, this.opacity);
this.material.depthTest = this.depthTest;
this.material.bumpScale = this.bumpScale;

@ -13,7 +13,10 @@ import { Line } from "../../DatabaseServices/Entity/Line";
import { Polyline } from "../../DatabaseServices/Entity/Polyline";
import { HardwareCompositeEntity } from "../../DatabaseServices/Hardware/HardwareCompositeEntity";
import { HardwareTopline } from "../../DatabaseServices/Hardware/HardwareTopline";
import { DirectionalLight } from "../../DatabaseServices/Lights/DirectionalLight";
import { Light } from "../../DatabaseServices/Lights/Light";
import { RectAreaLight } from "../../DatabaseServices/Lights/RectAreaLight";
import { SpotLight } from "../../DatabaseServices/Lights/SpotLight";
import { Text } from "../../DatabaseServices/Text/Text";
import { TextArea } from "../../DatabaseServices/Text/TextArea";
import { ViewportEntity } from "../../DatabaseServices/ViewportEntity";
@ -21,6 +24,7 @@ import { BoardModalType } from "../../UI/Components/Board/BoardModal";
import { BoardOptionModal } from "../../UI/Components/Board/BoardOptionModal";
import { EntityModal } from "../../UI/Components/EntityModal/EntityModal";
import { ExtrudeHoleModal } from "../../UI/Components/EntityModal/ExtrudeHoleModal";
import { CADModal } from "../../UI/Components/Modal/CadModal";
import { GetHardwareModal } from "../../UI/Components/Modal/HardwareModal";
import { ModalPosition } from "../../UI/Components/Modal/ModalInterface";
import { CompositeMatalPanel } from "../../UI/Components/RightPanel/CompositeMetalsPanel";
@ -29,7 +33,9 @@ import { ToplineMetalsPanel } from "../../UI/Components/RightPanel/ToplineMetals
import { AppToaster } from "../../UI/Components/Toaster";
import { EntityStore } from "../../UI/Store/EntityStore";
import { compositeMetalsOptionStore, toplineMetalsStore } from "../../UI/Store/RightPanelStore/HardwareStore";
import { LightStore } from "../../UI/Store/RightPanelStore/LightStore";
import { RightPanelStore } from "../../UI/Store/RightPanelStore/RightPanelStore";
import { SpotLightModel } from "../../UI/Store/RightPanelStore/SpotLightMOdel";
import { CommandWrap } from "../CommandMachine";
import { VP_TOATER_KEY } from "../LayoutTool";
import { PointPickOneObject } from "../PointPick";
@ -73,10 +79,24 @@ export class DbClickManager extends Singleton
if (pickEnt instanceof Light)
{
let rightStore = RightPanelStore.GetInstance();
rightStore.m_IsShow = true;
rightStore.m_TabId = RightTabId.Scene;
rightStore.lightStore.InitLightData(pickEnt);
if (pickEnt instanceof DirectionalLight)
{
let rightStore = RightPanelStore.GetInstance();
rightStore.m_IsShow = true;
rightStore.m_TabId = RightTabId.Scene;
return;
}
const width = 500;
const height = 500;
let lightStore = LightStore.GetInstance();
lightStore.InitLightData(pickEnt);
let isPointLight = pickEnt instanceof SpotLight || pickEnt instanceof RectAreaLight;
let p = app.Viewer.WorldToScreen(pickEnt.Position);
CADModal.ModalOldPosition.left = `${Math.min(p.x + app.Viewer.DomEl.offsetLeft + 10, window.innerWidth - width)}px`;
CADModal.ModalOldPosition.top = `${Math.min(p.y + app.Viewer.DomEl.offsetTop + 10, window.innerHeight - height)}px`;
app.Editor.ModalManage.RenderModeless(SpotLightModel,
{ store: lightStore, isPointLight: isPointLight }, { position: ModalPosition.Old });
}
else if (pickEnt instanceof Text)
{

@ -5,7 +5,7 @@ import { IUpdateBoardInfosOption } from "../UI/Components/Board/UpdateBoardInfoi
import { EMetalsType, ICompHardwareOption, ICylMetalsOption, IExtMetalsOption, IToplineOption } from "../UI/Components/RightPanel/RightPanelInterface";
import { IKuGangDrawOption } from "../UI/Components/Template/TemplateInterface";
import { ECompareType, IBoardFindOption } from "../UI/Store/BoardFindInterface";
import { BehindBoardOption, BehindHeightPositon, BoardProcessOption, BoardType, BrRelativePos, ClosingStripOption, ComposingType, CurtailType, FaceDirection, IBatchModifyPanelOption, IBoardBatchCurtailOption, LayerBoardOption, LayerNailOption, LinesType, ModifyTextsConfigOption, RadioType, SideBoardOption, SingleBoardOption, StripType, TBBoardOption, VerticalBoardOption, Viewport2ConfigOption, Viewport3ConfigOption, Viewport4ConfigOption, ViewportConfigOption } from "../UI/Store/BoardInterface";
import { BehindBoardOption, BehindHeightPositon, BoardProcessOption, BoardType, BrRelativePos, ClosingStripOption, ComposingType, CurtailType, FaceDirection, IBatchModifyPanelOption, IBoardBatchCurtailOption, LayerBoardOption, LayerNailOption, LinesType, ModifyTextsConfigOption, PointLightOption, RadioType, SideBoardOption, SingleBoardOption, StripType, TBBoardOption, VerticalBoardOption, Viewport2ConfigOption, Viewport3ConfigOption, Viewport4ConfigOption, ViewportConfigOption } from "../UI/Store/BoardInterface";
import { DoorPosType, HandleHorPos, HandleVePos, IDoorConfigOption, IDrawerConfigOption } from "../UI/Store/DoorInterface";
import { IHSOption } from "../UI/Store/HSInterface";
import { ELatticeArrayType, ILatticeOption } from "../UI/Store/LatticeInterface";
@ -188,6 +188,22 @@ export const DefaultModifyTextsOption: ModifyTextsConfigOption = {
};
Object.freeze(DefaultModifyTextsOption);
export const DefaultPointLightOption: PointLightOption = {
version: 1,
distance: 5000,
intensity: 100,
lightColor: "#FFFFFF",
temperature: 6500,
indirectLightingIntensity: 1,
showHelper: true,
specularScale: 1,
caseShado: true,
sourceRadius: 0,
softSourceRadius: 0,
sourceLength: 0,
};
Object.freeze(DefaultPointLightOption);
export const DefaultSingleBoardOption: SingleBoardOption = {
version: 1,
name: "层板",

@ -115,14 +115,14 @@ export class SelectControls implements EditorService
else
ocs = obj.matrixWorld.clone();
this._Editor.transCtrl.m_Ents = this.SelectSet.SelectEntityList;
this._Editor.transCtrl._Ents = this.SelectSet.SelectEntityList;
this._Editor.transCtrl.Matrix = ocs;
this._Editor.transCtrl.Mode = TransMode.Move;
this._Editor.transCtrl.Enable = true;
}
else
{
this._Editor.transCtrl.m_Ents = [];
this._Editor.transCtrl._Ents = [];
this._Editor.transCtrl.Enable = false;
}
}

@ -1,4 +1,4 @@
import * as THREE from 'three';
import { Matrix4, Vector3 } from 'three';
import { end } from 'xaop';
import { app } from '../../ApplicationServices/Application';
import { InputState } from '../../Common/InputState';
@ -27,17 +27,17 @@ export enum TransMode
//旋转 移动 控制器服务
export class TransformServicess implements EditorService
{
m_Ents: Entity[] = [];
private m_CurMode: TransMode = TransMode.Move;
private m_CtrlAxes: Array<TranslateAxex | RotateAxes> = [new TranslateAxex(), new RotateAxes()];
private m_Enable: boolean = true;
_Ents: Entity[] = [];
private _CurMode: TransMode = TransMode.Move;
private _CtrlAxes: Array<TranslateAxex | RotateAxes> = [new TranslateAxex(), new RotateAxes()];
private _Enable: boolean = true;
private m_Editor: Editor;
private _Editor: Editor;
private m_Matrix: THREE.Matrix4 = new THREE.Matrix4();
private _Matrix: Matrix4 = new Matrix4();
constructor(ed: Editor)
{
this.m_Editor = ed;
this._Editor = ed;
let app = ed.App;
let preView = app.Viewer.PreViewer;
@ -45,7 +45,7 @@ export class TransformServicess implements EditorService
end(ed.MouseCtrl, ed.MouseCtrl.onMouseMove, () =>
{
if (!this.m_Enable)
if (!this._Enable)
return;
let axes = this.CurAxes;
@ -69,11 +69,11 @@ export class TransformServicess implements EditorService
});
}
get IsReady()
{
return this.m_Enable && this.CurAxes.AxtiveIndex > 0 && this.m_Editor.InputState === InputState.None;
return this._Enable && this.CurAxes.AxtiveIndex > 0 && this._Editor.InputState === InputState.None;
}
async Doit(e: MouseEvent)
{
if (e.button !== MouseKey.Left)
@ -85,10 +85,10 @@ export class TransformServicess implements EditorService
await CommandWrap(async () =>
{
app.Viewer.GripScene.visible = false;
let jigEns = this.m_Ents.map(e => JigUtils.Draw(e));
let base = new THREE.Vector3().setFromMatrixColumn(this.m_Matrix, 3);
let jigEns = this._Ents.map(e => JigUtils.Draw(e));
let base = new Vector3().setFromMatrixColumn(this._Matrix, 3);
let ptRes = await this.m_Editor.GetPoint({
let ptRes = await this._Editor.GetPoint({
Msg: "请点击下一个点:",
BasePoint: base,
AllowDrawRubberBand: true,
@ -104,7 +104,7 @@ export class TransformServicess implements EditorService
if (ptRes.Status === PromptStatus.OK)
{
let m = MoveMatrix(ptRes.Point.sub(base));
for (let e of this.m_Ents)
for (let e of this._Ents)
e.ApplyMatrix(m);
}
@ -116,18 +116,18 @@ export class TransformServicess implements EditorService
private InitAxes(preView: PreViewer)
{
preView.Scene.add(...this.m_CtrlAxes);
preView.Scene.add(...this._CtrlAxes);
this.Mode = TransMode.Move;
this.m_CtrlAxes.forEach(c =>
for (let a of this._CtrlAxes)
{
c.visible = false;
c.scale.set(50, 50, 50);
});
a.visible = false;
a.scale.set(50, 50, 50);
}
}
get CurAxes()
{
return this.m_CtrlAxes[this.m_CurMode];
return this._CtrlAxes[this._CurMode];
}
set Mode(mode: TransMode)
@ -135,39 +135,39 @@ export class TransformServicess implements EditorService
let oldAxes = this.CurAxes;
oldAxes.visible = false;
this.m_CurMode = mode;
this._CurMode = mode;
let newAxes = this.CurAxes;
newAxes.visible = true;
this.m_Editor.App.Viewer.PreViewer.UpdateScreen();
this._Editor.App.Viewer.PreViewer.UpdateScreen();
}
set Matrix(mat: THREE.Matrix4)
set Matrix(mat: Matrix4)
{
this.m_Matrix.copy(mat);
this._Matrix.copy(mat);
this.UpdateAxesMatrix();
}
private UpdateAxesMatrix()
{
for (let a of this.m_CtrlAxes)
for (let a of this._CtrlAxes)
{
MatrixToPreViewMat(this.m_Matrix, this.m_Editor.App.Viewer, a, UCSPsotion.Origin);
MatrixToPreViewMat(this._Matrix, this._Editor.App.Viewer, a, UCSPsotion.Origin);
}
this.m_Editor.App.Viewer.PreViewer.UpdateScreen();
this._Editor.App.Viewer.PreViewer.UpdateScreen();
}
set Enable(e: boolean)
{
this.m_Enable = e;
this._Enable = e;
this.CurAxes.visible = e;
}
Cancel()
{
if (this.Enable)
{
this.m_Enable = false;
this.m_Editor.Canel();
this._Enable = false;
this._Editor.Canel();
}
}
}

@ -21,6 +21,7 @@ import { userConfig } from '../Editor/UserConfig';
import { equaln, equalv3, GetBox, GetBoxArr, isIntersect, isPerpendicularityTo, ZeroVec } from '../Geometry/GeUtils';
import { PlaneExt } from '../Geometry/Plane';
import { DownPanelStore } from '../UI/Store/DownPanelStore';
import { LightStore } from '../UI/Store/RightPanelStore/LightStore';
import { CameraUpdate } from './CameraUpdate';
import { GripScene } from './GripScene';
import { IViewer } from './IView';
@ -566,6 +567,8 @@ export class Viewer
//灯光
for (let l of db.Lights.Entitys)
this._Scene.add(l.DrawObject);
LightStore.GetInstance().UpdateDirLightShadowArea();//更新阴影
this.UpdateRender();
Entity.__ReadFileIng__ = false;

@ -62,6 +62,7 @@ export enum BoardModalType
Viewport4 = "Viewport4",//四视图
AutoHoleFaceSetting = "AutoHoleFaceSetting",//自动孔面设置
EditViewSetting = "EditViewSetting",//编辑视口配置
PointLight = "PointLight",//点灯光配置
}
export interface BoardModalProps
{

@ -1,66 +1,27 @@
import { Alignment, Button, Classes, Divider, H6, Icon, InputGroup, Intent, Label, NumericInput, Popover, PopoverPosition, Slider, Switch, UL } from '@blueprintjs/core';
import { Alignment, Icon, InputGroup, Intent, Label, NumericInput, Popover, PopoverPosition, Slider, Switch } from '@blueprintjs/core';
import { observable } from 'mobx';
import { inject, observer } from 'mobx-react';
import { observer } from 'mobx-react';
import * as React from 'react';
import { ColorResult, SketchPicker } from 'react-color';
import { Color, MathUtils, Matrix4, Vector3 } from 'three';
import { Color } from 'three';
import { Entitys2Data } from '../../../Add-on/ExportData';
import { app } from '../../../ApplicationServices/Application';
import { safeEval } from '../../../Common/eval';
import { DirectionalLight } from '../../../DatabaseServices/Lights/DirectionalLight';
import { Light } from '../../../DatabaseServices/Lights/Light';
import { RectAreaLight } from '../../../DatabaseServices/Lights/RectAreaLight';
import { SpotLight } from '../../../DatabaseServices/Lights/SpotLight';
import { commandMachine, CommandWrap } from '../../../Editor/CommandMachine';
import { CommandState } from '../../../Editor/CommandState';
import { PromptStatus } from '../../../Editor/PromptResult';
import { userConfig } from '../../../Editor/UserConfig';
import { LightModalState } from '../../Store/RightPanelStore/LightStore';
import { RightPanelStore } from '../../Store/RightPanelStore/RightPanelStore';
import { DefaultDist } from '../RightPanel/ScenePanel';
import SunLightGui from '../RightPanel/SunLightGui';
import { AppToaster } from '../Toaster';
@inject("store")
@observer
export class LightModal extends React.Component<{ store?: RightPanelStore; }, {}> {
@observable isCollapse = false;
render()
{
const lightStore = this.props.store.lightStore;
let light = this.props.store.lightStore.currentSelectEnt;
return (
<>
<H6
style={{ cursor: "pointer" }}
onClick={() => this.isCollapse = !this.isCollapse}
>{lightStore.title + "设置"}
<Icon icon={this.isCollapse ? "chevron-right" : "chevron-down"} style={{ float: "right" }} />
</H6>
{
!this.isCollapse && <LightDataCom
data={lightStore.lightData}
light={light}
pars={lightStore.pars}
isShowPos={true}
isSelectTarget={light instanceof SpotLight || light instanceof RectAreaLight}
/>
}
<Divider />
</>
);
}
}
interface ILightComponentProps
{
data: LightModalState;
light: Light;
pars: [string, string][];
isShowPos: boolean;
isSelectTarget: boolean;
hideColor?: boolean;
hasApplyBtn?: boolean;
}
@ -69,114 +30,43 @@ interface ILightComponentProps
export class LightDataCom extends React.Component<ILightComponentProps, {}> {
@observable target: string = "0,0,0";
@observable showHelper: boolean = false;
handleSelectTarget = async () =>
{
await app.Editor.ModalManage.EndExecingCmd();
CommandWrap(async () =>
{
app.Editor.MaskManage.Clear();
this.UpdateTarget();
let ptRes = await app.Editor.GetPoint({
Msg: "选择照射目标"
});
if (ptRes.Status === PromptStatus.OK)
{
(this.props.light as SpotLight | DirectionalLight).Target = ptRes.Point;
app.Editor.UpdateScreen();
this.target = ptRes.Point.clone().ceil().toArray().toString();
if (userConfig.synchronousEnable)
app.WebSocket.Send(JSON.stringify(Entitys2Data([this.props.light])));
}
}, "target");
};
private UpdateTarget = () =>
{
const dirTarge = (this.props.light as SpotLight | DirectionalLight).Target;
if (dirTarge)
this.target = dirTarge.ceil().toArray().toString();
};
HandleFocus = () =>
{
if (this.props.isSelectTarget)
this.UpdateTarget();
// if (this.props.isShowPos)
// {
// this.props.data.x = FixedNotZero(this.props.light.Position.x, 2);
// this.props.data.y = FixedNotZero(this.props.light.Position.y, 2);
// this.props.data.z = FixedNotZero(this.props.light.Position.z, 2);
// }
};
private applyChange = () =>
{
const light = this.props.light;
const lightData = this.props.data;
let pos: Vector3;
if (lightData.x !== undefined)
pos = new Vector3(safeEval(lightData.x), safeEval(lightData.y), safeEval(lightData.z));
else if (light instanceof DirectionalLight)
{
let elevation = MathUtils.degToRad(safeEval(lightData.Elevation));
let rotation = MathUtils.degToRad(safeEval(lightData.Rotation));
pos = new Vector3(DefaultDist.dist * Math.cos(elevation), 0, DefaultDist.dist * Math.sin(elevation));
pos.applyMatrix4(new Matrix4().makeRotationZ(rotation)).add(light.Target);
}
CommandWrap(() =>
{
if (pos)
light.Position = pos;
for (let key in lightData)
{
if (key === "x"
|| key === "y"
|| key === "z"
|| key === "Elevation"
|| key === "Rotation")
continue;
if (lightData.hasOwnProperty(key))
{
let val = lightData[key];
if (key === "Angle")
{
if (val > 90)
val = 90;
val = MathUtils.degToRad(val);
}
if (key === "Color" || key === "GroundColor")
{
light[key] = new Color(val);
}
else
light[key] = val;
}
};
app.Editor.UpdateScreen();
}, "修改灯光属性");
};
ChangeSkyLightIntensity = async (val: number) =>
ChangeSkyLightIntensity = (val: number, k?: string) =>
{
const KEY = "修改天光强度";
const KEY = (k === "IndirectLightingIntensity") ? "修改天光反弹" : "修改天光强度";
if (CommandState.CommandIng)
{
if (app.Database.hm.UndoData.CommandName !== KEY)
{
await app.Editor.ModalManage.EndExecingCmd();
AppToaster.show({
message: "命令正在执行中!无法修改天光强度!",
timeout: 5000,
intent: Intent.DANGER,
app.Editor.ModalManage.EndExecingCmd().then(() =>
{
if (CommandState.CommandIng)
{
AppToaster.show({
message: "命令正在执行中!无法" + KEY + "!",
timeout: 5000,
intent: Intent.DANGER,
});
return;
}
});
return;
}
}
else
{
commandMachine.CommandStart(KEY);
}
app.Database.HemisphereLight.Intensity = val;
if (k === "IndirectLightingIntensity")
app.Database.HemisphereLight.IndirectLightingIntensity = val;
else
app.Database.HemisphereLight.Intensity = val;
if (userConfig.synchronousEnable)
app.WebSocket.Send(JSON.stringify(Entitys2Data([app.Database.HemisphereLight])));
@ -192,26 +82,9 @@ export class LightDataCom extends React.Component<ILightComponentProps, {}> {
const lightData = this.props.data;
const pars = this.props.pars;
return (
<div tabIndex={-1} style={{ outline: "none" }} onFocus={this.HandleFocus}>
{
this.props.isSelectTarget ? <Label className={Classes.INLINE + " lg-target"}>
<InputGroup
className={Classes.INLINE}
value={this.target}
disabled
small
rightElement={
<Button
icon="select"
onClick={this.handleSelectTarget}
/>
}
/>
</Label> : null
}
<div tabIndex={-1} style={{ outline: "none", padding: 3 }} id={"LightDataComModel"} >
{
(light instanceof SpotLight || light instanceof DirectionalLight || light instanceof RectAreaLight) ? <Switch
light instanceof DirectionalLight ? <Switch
checked={this.showHelper}
label="显示灯光助手"
onChange={e =>
@ -228,17 +101,17 @@ export class LightDataCom extends React.Component<ILightComponentProps, {}> {
<div className="lg">
{
!this.props.hideColor &&
<div style={{ position: "relative" }}>
<span></span>
<div className={"color"}>
<Label>:</Label>
<Popover
position={PopoverPosition.TOP}
minimal
content={
<SketchPicker
color={lightData.Color}
color={lightData.Color.toUpperCase()}
onChange={async (e: ColorResult) =>
{
lightData.Color = e.hex;
lightData.Color = e.hex.toUpperCase();
const KEY = '修改天光颜色';
if (CommandState.CommandIng)
{
@ -254,9 +127,7 @@ export class LightDataCom extends React.Component<ILightComponentProps, {}> {
}
}
else
{
commandMachine.CommandStart(KEY);
}
app.Database.HemisphereLight.Color = new Color(e.hex.toString());
app.Viewer.UpdateRender();
if (userConfig.synchronousEnable)
@ -264,13 +135,15 @@ export class LightDataCom extends React.Component<ILightComponentProps, {}> {
}}
onChangeComplete={() =>
{
commandMachine.CommandEnd();
const KEY = '修改天光颜色';
if (CommandState.CommandIng && app.Database.hm.UndoData.CommandName === KEY)
commandMachine.CommandEnd();
}}
/>
}>
<InputGroup
style={{ width: "100px" }}
value={lightData.Color.toString()}
style={{ width: "100px", height: "27px" }}
value={lightData.Color.toString().toUpperCase()}
small
leftIcon={
<Icon
@ -282,47 +155,41 @@ export class LightDataCom extends React.Component<ILightComponentProps, {}> {
</div>
}
{
!(light instanceof SpotLight || light instanceof DirectionalLight || light instanceof RectAreaLight)
!(light instanceof DirectionalLight)
? pars.map(([k, v]) =>
{
let min: number = 0;
let max: number = 200;
let max: number = 10;
let step: number = 1;
switch (k)
{
case "Decay":
max = 2;
step = 0.1;
break;
case "Penumbra":
max = 1;
step = 0.1;
case "IndirectLightingIntensity":
max = 6;
break;
case "Angle":
case "Elevation":
max = 90;
break;
case "Rotation":
max = 360;
default:
break;
}
return <div className='SkyLightIntensity'>
<span>{v}</span>
<Label>{v}:</Label>
<NumericInput
clampValueOnBlur
min={min}
max={max}
stepSize={step}
minorStepSize={0.01}
value={lightData[k]} onValueChange={async (num, str) =>
value={lightData[k]}
onValueChange={async (num, str) =>
{
if (isNaN(num) || num < min || num > max) return;
this.ChangeSkyLightIntensity(num);
commandMachine.CommandEnd();
this.ChangeSkyLightIntensity(num, k);
lightData[k] = str;
}}
onBlur={() =>
{
const KEY = "修改天光" + v;
if (CommandState.CommandIng && app.Database.hm.UndoData.CommandName === KEY)
commandMachine.CommandEnd();
}}
onFocus={(e) =>
{
e.target.select();
@ -340,47 +207,21 @@ export class LightDataCom extends React.Component<ILightComponentProps, {}> {
value={parseInt(lightData[k])}
onChange={(val) =>
{
this.ChangeSkyLightIntensity(val);
this.ChangeSkyLightIntensity(val, k);
lightData[k] = val;
app.Viewer.UpdateRender();
if (userConfig.synchronousEnable)
app.WebSocket.Send(JSON.stringify(Entitys2Data([app.Database.HemisphereLight])));
}}
onRelease={() =>
{
commandMachine.CommandEnd();
const KEY = "修改天光" + v;
if (CommandState.CommandIng && app.Database.hm.UndoData.CommandName === KEY)
commandMachine.CommandEnd();
}}
/>
</div>;
})
: <SunLightGui />
}
{
this.props.isShowPos ? <Label className="lg-pos">
<UL className={Classes.LIST_UNSTYLED}>
{
["x", "y", "z"].map(v =>
{
return (
<li >
<Label className={Classes.INLINE}>
{v}
<input
className={Classes.INPUT}
value={lightData[v]}
onChange={(e) =>
{
lightData[v] = e.target.value;
}} />
</Label>
</li>
);
})
}
</UL>
</Label> : null
}
</div>
</div>
);

@ -13,20 +13,25 @@ import { AppToaster } from "../Toaster";
@observer
export class ExposureUI extends React.Component<{ store: LightStore; }, {}>
{
async SetExposureCompensation(val: number)
SetExposureCompensation(val: number)
{
const KEY = '修改曝光补偿';
if (CommandState.CommandIng)
{
if (app.Database.hm.UndoData.CommandName !== KEY)
{
await app.Editor.ModalManage.EndExecingCmd();
AppToaster.show({
message: "命令正在执行中!无法修改曝光补偿!",
timeout: 5000,
intent: Intent.DANGER
app.Editor.ModalManage.EndExecingCmd().then(() =>
{
if (CommandState.CommandIng)
{
AppToaster.show({
message: "命令正在执行中!无法修改曝光补偿!",
timeout: 5000,
intent: Intent.DANGER
});
return;
}
});
return;
}
}
else
@ -43,10 +48,10 @@ export class ExposureUI extends React.Component<{ store: LightStore; }, {}>
return (
<div id='ExposureUI'>
<Checkbox
style={{ width: 80 }}
style={{ width: 135 }}
checked={this.props.store.hemisphereLightData.AutoExposure}
alignIndicator={"right"}
label={"自动曝光"}
label={"自动曝光(眼球适应)"}
onClick={async () =>
{
const KEY = '修改自动曝光';
@ -89,7 +94,7 @@ export class ExposureUI extends React.Component<{ store: LightStore; }, {}>
onValueChange={async (e) =>
{
if (isNaN(e) || e < -3 || e > 6) return;
await this.SetExposureCompensation(e);
this.SetExposureCompensation(e);
const KEY = '修改曝光补偿';
if (CommandState.CommandIng && app.Database.hm.UndoData.CommandName === KEY)
{
@ -111,9 +116,9 @@ export class ExposureUI extends React.Component<{ store: LightStore; }, {}>
max={6}
stepSize={0.1}
value={parseFloat(this.props.store.hemisphereLightData.ExposureCompensation)}
onChange={async (val) =>
onChange={(val) =>
{
await this.SetExposureCompensation(val);
this.SetExposureCompensation(val);
}}
onRelease={() =>
{

@ -96,81 +96,66 @@
// align-items : center;
.bp3-label{
float : left;
width : 45px;
margin : 0;
margin-top : 8px;
line-height: unset;
}
.color{
width : 200px;
height: 34px;
}
.SkyLightIntensity
{
width: 100%;
width : 100%;
height : 34px;
display: flex;
>span
position: relative;
.bp3-button-group
{
line-height: 47px;
display: none;
}
.bp3-button-group
}
.bp3-slider{
width : 150px;
height : auto;
position : absolute;
margin-top : 7px;
margin-left: 108px;
.bp3-slider-axis
{
display: none;
}
.bp3-slider
.bp3-slider-handle
{
width : 100px;
box-sizing : border-box;
margin-left: 10px;
.bp3-slider-track
{
margin-top: 15px;
}
.bp3-slider-handle
{
margin-top: 15px;
.bp3-slider-label
{
display: none;
}
}
.bp3-slider-axis
.bp3-slider-label
{
display: none;
}
}
}
&>div,
&>label {
width: 50%;
}
&>div>span,
&>.bp3-label>span {
display : inline-block;
width : 2.5rem;
vertical-align: middle;
}
input {
height : @height;
line-height: @height;
width : @inputWidth;
}
label.bp3-label.bp3-inline {
line-height : @height;
margin-bottom: 10px;
.bp3-list.bp3-list-unstyled{
.pos{
display: flex;
}
}
.lg-pos {
width : 100%;
margin-bottom: 0;
ul {
display : flex;
justify-content: space-between;
flex-wrap : wrap;
li {
width: 50%;
}
}
.bp3-control-group.bp3-numeric-input {
float: left;
input {
width: 7rem;
.bp3-input{
height : 27px;
width : 50px;
padding: 10px;
}
}
@ -180,70 +165,36 @@
margin-left: 0;
}
.bp3-control-group {
align-items: center;
}
.bp3-inline>.bp3-control-group {
display: inline-flex;
}
.sun-light
{
width : 100%;
display : flex;
margin : 0;
flex-direction: column;
box-sizing : border-box;
padding : 0 20px 20px 0;
.bp3-form-group
{
margin-bottom: 5px;
}
.sun-light-intensity
{
display : flex;
justify-content: space-between;
.bp3-label
{
line-height: 40px;
margin : 0;
}
.bp3-numeric-input
{
width : 100%;
margin: 0;
.sun-light-intensity{
.bp3-numeric-input{
.bp3-button-group
{
display: none;
}
}
.bp3-slider
{
width : 100px;
box-sizing : border-box;
.bp3-slider-track
{
margin-top: 15px;
}
.bp3-slider-handle
{
margin-top: 15px;
.bp3-slider-label
{
display: none;
}
}
.bp3-slider-axis
{
display: none;
}
}
}
.bp3-button-group.bp3-vertical
{
.bp3-button-group.bp3-vertical.bp3-fixed{
margin-top: 2px;
}
.bp3-form-group
{
margin: 0;
height: 34px;
}
.bp3-input-group
{
width: 50px;
>input
{
width: 100%;
@ -258,6 +209,8 @@
}
.sun-light-elevation-contain
{
height: 150px;
.bp3-form-content
{
position: relative;
@ -303,6 +256,8 @@
}
.sun-light-color-temperature
{
height: 27px;
.bp3-button
{
margin-left: 35px;

@ -12,7 +12,7 @@ import { userConfig } from '../../../Editor/UserConfig';
import { equalv3 } from '../../../Geometry/GeUtils';
import { ETime } from '../../Store/RightPanelStore/LightStore';
import { RightPanelStore } from '../../Store/RightPanelStore/RightPanelStore';
import { LightDataCom, LightModal } from '../Modal/LightModal';
import { LightDataCom } from '../Modal/LightModal';
import { ExposureUI } from './ExposureUI';
import { SunLightStore } from './SunLightStore';
@ -25,6 +25,7 @@ export class ScenePanel extends React.Component<{ store?: RightPanelStore; }, {}
{
UNSAFE_componentWillMount()
{
this.props.store.lightStore.InitLightData(app.Database.HemisphereLight);
const sun = app.Database.SunLight;;
if (equalv3(sun.Position, new Vector3()))
this.handleSuntime();
@ -65,9 +66,8 @@ export class ScenePanel extends React.Component<{ store?: RightPanelStore; }, {}
<LightDataCom
data={lightStore.hemisphereLightData}
light={HemisphereLight}
pars={[["Intensity", "强度"]]}
pars={[["Intensity", "强度"], ["IndirectLightingIntensity", "反弹"]]}
isShowPos={false}
isSelectTarget={false}
/>
</div>
<Divider />
@ -78,30 +78,28 @@ export class ScenePanel extends React.Component<{ store?: RightPanelStore; }, {}
onChange={e => this.triggleLightShow(e, SunLight)}
alignIndicator={Alignment.RIGHT}
/>
<div style={{ display: lightStore.ShowSunLight ? "block" : "none" }}>
<HTMLSelect
options={[ETime.Default, ETime.Morning, ETime.Noon, ETime.Afternoon, ETime.Evening]}
value={lightStore.sunLightData.time}
style={{ marginBottom: 10 }}
onChange={e =>
{
lightStore.sunLightData.time = e.currentTarget.value as ETime;
this.handleSuntime();
}}
/>
<div style={{ display: lightStore.ShowSunLight ? "block" : "none", position: "relative" }}>
<div style={{ position: "absolute", right: 30, marginTop: 166, zIndex: 2 }}>
<HTMLSelect
options={[ETime.Default, ETime.Morning, ETime.Noon, ETime.Afternoon, ETime.Evening]}
value={lightStore.sunLightData.time}
style={{ marginBottom: 10 }}
onChange={e =>
{
lightStore.sunLightData.time = e.currentTarget.value as ETime;
this.handleSuntime();
}}
/>
</div>
<LightDataCom
data={lightStore.sunLightData}
hideColor
light={SunLight}
pars={[["Elevation", "仰角"], ["Rotation", "旋转"], ["Intensity", "强度"]]}
pars={[["Elevation", "仰角"], ["Rotation", "旋转"], ["IndirectLightingIntensity", "反弹"], ["Intensity", "强度"]]}
isShowPos={false}
isSelectTarget={false}
/>
</div>
<Divider />
{
lightStore.currentSelectEnt && <LightModal />
}
<Switch
large
checked={lightStore.ShowExposure}
@ -113,7 +111,8 @@ export class ScenePanel extends React.Component<{ store?: RightPanelStore; }, {}
<ExposureUI store={lightStore} />
</div>
<Divider />
</div>);
</div >
);
}
private SetSunProps(angle: number, rotation: number, intensity: number)
{

@ -10,6 +10,7 @@ import { ResourcesCDN_HOST } from '../../../Common/HostUrl';
import { commandMachine } from '../../../Editor/CommandMachine';
import { CommandState } from '../../../Editor/CommandState';
import { userConfig } from '../../../Editor/UserConfig';
import { LightStore } from '../../Store/RightPanelStore/LightStore';
import { AppToaster } from '../Toaster';
import { DefaultDist } from './ScenePanel';
import { SunLightStore } from './SunLightStore';
@ -29,12 +30,15 @@ export default class SunLightGui extends Component
if (CommandState.CommandIng)
{
await app.Editor.ModalManage.EndExecingCmd();
AppToaster.show({
message: "命令正在执行中!无法修改灯光角度!",
timeout: 5000,
intent: Intent.DANGER,
});
return;
if (CommandState.CommandIng)
{
AppToaster.show({
message: "命令正在执行中!无法修改灯光角度!",
timeout: 5000,
intent: Intent.DANGER,
});
return;
}
}
const CommandKey = "修改太阳光仰角角度";
@ -79,12 +83,16 @@ export default class SunLightGui extends Component
if (CommandState.CommandIng)
{
await app.Editor.ModalManage.EndExecingCmd();
AppToaster.show({
message: "命令正在执行中!无法修改灯光角度!",
timeout: 5000,
intent: Intent.DANGER,
});
return;
if (CommandState.CommandIng)
{
AppToaster.show({
message: "命令正在执行中!无法修改灯光角度!",
timeout: 5000,
intent: Intent.DANGER,
});
return;
}
}
const CommandKey = "修改太阳光旋转角度";
@ -116,20 +124,25 @@ export default class SunLightGui extends Component
};
};
SetSunLightIntensity = async (val: number) =>
SetSunLightIntensity = (val: number) =>
{
const KEY = '修改太阳光强度';
if (CommandState.CommandIng)
{
if (app.Database.hm.UndoData.CommandName !== KEY)
{
await app.Editor.ModalManage.EndExecingCmd();
AppToaster.show({
message: "命令正在执行中!无法修改太阳光强度!",
timeout: 5000,
intent: Intent.DANGER
app.Editor.ModalManage.EndExecingCmd().then(() =>
{
if (CommandState.CommandIng)
{
AppToaster.show({
message: "命令正在执行中!无法修改太阳光强度!",
timeout: 5000,
intent: Intent.DANGER
});
return;
}
});
return;
}
}
else
@ -141,6 +154,37 @@ export default class SunLightGui extends Component
this.SyncSunLight();
};
SetSunLightIndirectIntensity = async (val: number) =>
{
const KEY = '修改太阳间接光强度';
if (CommandState.CommandIng)
{
if (app.Database.hm.UndoData.CommandName !== KEY)
{
await app.Editor.ModalManage.EndExecingCmd().then(() =>
{
if (CommandState.CommandIng)
{
AppToaster.show({
message: "命令正在执行中!无法修改太阳间接光强度!",
timeout: 5000,
intent: Intent.DANGER
});
return;
}
});
}
}
else
{
commandMachine.CommandStart(KEY);
}
app.Database.SunLight.IndirectLightingIntensity = val;
this.store.sunLightIndirectLightingIntensity = val;
this.SyncSunLight();
};
SetSunLightPosition = (rotate: number, elevation: number): void =>
{
let pos: Vector3;
@ -149,8 +193,9 @@ export default class SunLightGui extends Component
pos = new Vector3(DefaultDist.dist * Math.cos(elevation), 0, DefaultDist.dist * Math.sin(elevation));
pos.applyMatrix4(new Matrix4().makeRotationZ(rotate)).add(app.Database.SunLight.Target);
app.Database.SunLight.Position = pos;
app.Viewer.UpdateRender();
LightStore.GetInstance().UpdateDirLightShadowArea();
app.Viewer.UpdateRender();
this.SyncSunLight();
};
@ -216,14 +261,18 @@ export default class SunLightGui extends Component
<Label>:</Label>
<NumericInput
min={0}
max={200}
max={150}
allowNumericCharactersOnly={false}
value={this.store.sunLightIntensity}
onKeyDown={(e) => { e.stopPropagation(); }}
onValueChange={async (e) =>
{
if (isNaN(e) || e < 0 || e > 200) return;
if (isNaN(e) || e < 0 || e > 150) return;
await this.SetSunLightIntensity(e);
}}
onBlur={() =>
{
const KEY = '修改太阳光强度';
if (CommandState.CommandIng && app.Database.hm.UndoData.CommandName === KEY)
{
@ -237,7 +286,7 @@ export default class SunLightGui extends Component
/>
<Slider
min={0}
max={200}
max={150}
stepSize={1}
labelStepSize={20}
value={this.store.sunLightIntensity}
@ -258,6 +307,55 @@ export default class SunLightGui extends Component
/>
</div>
</FormGroup>
<FormGroup>
<div className='sun-light-intensity'>
<Label>:</Label>
<NumericInput
min={0}
max={6}
allowNumericCharactersOnly={false}
value={this.store.sunLightIndirectLightingIntensity}
onKeyDown={(e) => { e.stopPropagation(); }}
onValueChange={async (e) =>
{
if (isNaN(e) || e < 0 || e > 6) return;
this.SetSunLightIndirectIntensity(e);
}}
onBlur={() =>
{
const KEY = '修改太阳间接光强度';
if (CommandState.CommandIng && app.Database.hm.UndoData.CommandName === KEY)
{
commandMachine.CommandEnd();
}
}}
onFocus={(e) =>
{
e.target.select();
}}
/>
<Slider
min={0}
max={6}
stepSize={1}
value={this.store.sunLightIndirectLightingIntensity}
onChange={async (val) =>
{
await this.SetSunLightIndirectIntensity(val);
app.Viewer.UpdateRender();
this.SyncSunLight();
}}
onRelease={() =>
{
const KEY = '修改太阳间接光强度';
if (CommandState.CommandIng && app.Database.hm.UndoData.CommandName === KEY)
{
commandMachine.CommandEnd();
}
}}
/>
</div>
</FormGroup>
<FormGroup
label='颜色:'
inline
@ -305,6 +403,7 @@ export default class SunLightGui extends Component
}>
<InputGroup
value={this.store.sunLightColor.toUpperCase()}
style={{ height: "27px" }}
small
leftIcon={
<Icon
@ -433,13 +532,10 @@ export default class SunLightGui extends Component
className='sun-light-elevation-contain'>
<div style={{
display: 'flex',
marginBottom: "-20px"
marginBottom: "-20px",
marginTop: "8px",
}}>
<Label
style={{
lineHeight: "35px",
margin: "0 5px 0 0",
}}>
<Label>
°C:
</Label>
<NumericInput

@ -9,6 +9,7 @@ import { DirectionalLight } from "../../../DatabaseServices/Lights/DirectionalLi
export class SunLightStore
{
@observable sunLightIntensity: number = 50;
@observable sunLightIndirectLightingIntensity: number = 1;
@observable sunLightElevationDeg: number = 45;
@observable sunLightRotateDeg: number = 235;
@observable sunLightColor: string = '#FFFFFF';
@ -55,6 +56,7 @@ export class SunLightStore
{
let light = app.Database.SunLight;
this.sunLightIntensity = light.Intensity;
this.sunLightIndirectLightingIntensity = light.IndirectLightingIntensity;
this.sunLightColorTemperature = light.Temperature;
this.sunLightColor = `#${light.Color.getHexString()}`;

@ -1092,3 +1092,101 @@ img {
}
}
}
#SpotLightModel{
width : 300px;
font-size: 13px;
.bp3-dialog-body{
padding: 5px;
.bp3-control.bp3-switch.bp3-align-right {
padding-left : 14px;
padding-right: 47px;
}
>div{
height: 32px;
}
input{
width : 100px;
height : 27px;
margin-left: 10px;
}
.bp3-label{
float : left;
width : 56px;
margin-top: 5px;
text-align: center;
}
.bp3-form-group{
margin: 0;
}
.bp3-input-group.bp3-disabled.bp3-small.bp3-inline{
width: 130px;
}
.bp3-popover-wrapper{
.bp3-icon.bp3-icon-stop{
margin-left: 13px;
margin-top : 4px;
}
.bp3-input{
width : 100px;
height : 27px;
margin-left: 10px;
text-indent: 18px;
}
}
.bp3-control-group.bp3-numeric-input {
float: left;
.bp3-input{
height : 27px;
width : 50px;
margin-left: 10px;
padding : 10px;
}
}
.lg-pos{
.bp3-button{
height: 30px;
}
}
.bp3-slider{
min-width : none;
width : 130px;
height : auto;
position : absolute;
margin-top : 5px;
margin-left: 130px;
.bp3-slider-axis
{
display: none;
}
.bp3-slider-handle
{
.bp3-slider-label
{
display: none;
}
}
}
.bp3-list.bp3-list-unstyled{
.pos{
display: flex;
}
}
}
}

@ -131,6 +131,26 @@ export interface BoardConfigOption extends IBaseOption
width?: number;
}
export interface LightConfigOption extends IBaseOption
{
distance: number;
intensity: number;
lightColor: string;
temperature: number;
indirectLightingIntensity: number;
showHelper: boolean;
specularScale: number;
caseShado: boolean;
}
export interface PointLightOption extends LightConfigOption
{
sourceRadius: number;
softSourceRadius: number;
sourceLength: number;
}
export interface ModifyTextsConfigOption
{
changeTexts: [string, string][];

@ -14,7 +14,11 @@ import { PointLight } from "../../../DatabaseServices/Lights/PointLight";
import { RectAreaLight } from "../../../DatabaseServices/Lights/RectAreaLight";
import { SpotLight } from "../../../DatabaseServices/Lights/SpotLight";
import { ObjectId } from "../../../DatabaseServices/ObjectId";
import { TemplateRecord } from "../../../DatabaseServices/Template/TemplateRecord";
import { angle, equalv3, ZeroVec } from "../../../Geometry/GeUtils";
import { IConfigOption } from "../../Components/Board/UserConfig";
import { AnyObject } from "../BoardInterface";
import { IConfigStore } from "../BoardStore";
export interface LightModalState
{
@ -38,6 +42,18 @@ export interface LightModalState
Rotation?: string;
AutoExposure?: boolean;//自动曝光
ExposureCompensation?: string;//曝光补偿
LightIndirectLightingIntensity?: string;//间接光强度
IndirectLightingIntensity?: string;//间接光强度
InnerConeAngle?: string;//射灯内角度
OuterConeAngle?: string;//射灯外角度
SourceRadius?: string;//射灯源半径
SoftSourceRadius?: string;//射灯软源半径
SourceLength?: string;//射灯源长度
SpecularScale?: string;//高光
Temperature?: string;//色温
AttenuationRadius?: string;//射灯衰减半径
BarnDoorAngle?: string;//挡光板角度
BarnDoorLength?: string;//挡光板长度
}
export enum ETime
{
@ -47,8 +63,18 @@ export enum ETime
Afternoon = "下午",
Evening = "傍晚",
}
export class LightStore
export class LightStore implements IConfigStore
{
configName: string;
configsNames: string[];
InitOption: () => void;
SaveConfig: () => IConfigOption<AnyObject>;
UpdateOption: Function;
HasInvailValue?: () => string;
EditorTemplate?: TemplateRecord;
InitConfigs?: () => { [key: string]: IConfigOption<AnyObject>; };
GetOtherConfig?: (conf: any) => AnyObject;
HandleImportConfig?: (conf: any) => void;
@observable ShowAmbientLight = true;
@observable ShowSunLight = true;
@observable ShowHemiLight = true;
@ -66,19 +92,30 @@ export class LightStore
Color: "#" + app.Database.HemisphereLight.Color.getHexString(),
Intensity: app.Database.HemisphereLight.Intensity.toString(),
ExposureCompensation: app.Database.HemisphereLight.ExposureCompensation.toString(),
AutoExposure: app.Database.HemisphereLight.AutoExposure
AutoExposure: app.Database.HemisphereLight.AutoExposure,
IndirectLightingIntensity: app.Database.HemisphereLight.IndirectLightingIntensity.toString()
};
@observable sunLightData = {
Intensity: app.Database.SunLight.Intensity.toString(),
IndirectLightingIntensity: app.Database.SunLight.IndirectLightingIntensity.toString(),
time: ETime.Default,
Elevation: "0",
Rotation: "0"
};
@observable isShowShadow = false;
constructor()
private constructor()
{
this.WatchLightEvent();
}
private static _SingleInstance: LightStore;
static GetInstance(): LightStore
{
if (this._SingleInstance) return this._SingleInstance;
this._SingleInstance = new LightStore;
return this._SingleInstance;
}
InitSunLightData()
{
let light = app.Database.SunLight;
@ -86,6 +123,7 @@ export class LightStore
let vec2 = light.Position.sub(light.Target);
Object.assign(this.sunLightData, {
Intensity: app.Database.SunLight.Intensity.toString(),
IndirectLightingIntensity: app.Database.SunLight.IndirectLightingIntensity.toString(),
Rotation: equalv3(vec, ZeroVec) ? "0" : FixedNotZero(MathUtils.radToDeg(angle(vec)), 0),
Elevation: equalv3(vec, ZeroVec) ? "0" : FixedNotZero(MathUtils.radToDeg(vec.angleTo(vec2)), 0)
});
@ -104,6 +142,9 @@ export class LightStore
z: FixedNotZero(light.Position.z, 2),
Intensity: light.Intensity.toString(),
Color: "#" + light.Color.getHexString(),
IndirectLightingIntensity: light.IndirectLightingIntensity.toString(),
SpecularScale: light.SpecularScale.toString(),
Temperature: light.Temperature.toString(),
};
this.pars.length = 0;
}
@ -111,30 +152,36 @@ export class LightStore
if (light instanceof PointLight)
{
this.title = "点光源";
this.pars.push(["Intensity", "强度"], ["Distance", "距离"], ["Decay", "衰减"]);
this.pars.push(["Intensity", "强度"], ["IndirectLightingIntensity", "反弹"], ["SpecularScale", "高光"], ["SourceLength", "源长度"], ["SourceRadius", "源半径"], ["SoftSourceRadius", "软源半径"]);
Object.assign(newState, {
Distance: light.Distance.toString(),
Decay: light.Decay.toString(),
SourceLength: light.SourceLength.toString(),
SourceRadius: light.SourceRadius.toString(),
SoftSourceRadius: light.SoftSourceRadius.toString(),
});
}
else if (light instanceof SpotLight)
{
this.title = "射灯";
this.pars.push(["Intensity", "强度"], ["Distance", "距离"], ["Decay", "衰减"], ["Angle", "角度"], ["Penumbra", "衰减比"]);
this.pars.push(["Intensity", "强度"], ["IndirectLightingIntensity", "反弹"], ["SpecularScale", "高光"], ["Angle", "角度"], ["InnerConeAngle", "内角度"], ["SourceLength", "源长度"], ["SourceRadius", "源半径"], ["SoftSourceRadius", "软源半径"], ["AttenuationRadius", "衰减半径"]);
Object.assign(newState, {
Distance: light.Distance.toString(),
Decay: light.Decay.toString(),
Angle: FixedNotZero(MathUtils.radToDeg(light.Angle), 2),
Penumbra: light.Penumbra.toString(),
InnerConeAngle: light.InnerConeAngle.toString(),
SourceLength: light.SourceLength.toString(),
SourceRadius: light.SourceRadius.toString(),
SoftSourceRadius: light.SoftSourceRadius.toString(),
AttenuationRadius: light.AttenuationRadius.toString(),
});
}
else if (light instanceof RectAreaLight)
{
this.title = "矩形光";
this.pars.push(["Intensity", "强度"], ["Height", "高度"], ["Width", "宽度"]);
this.pars.push(["Intensity", "强度"], ["IndirectLightingIntensity", "反弹"], ["SpecularScale", "高光"], ["Width", "宽度"], ["Height", "长度"], ["BarnDoorAngle", "挡板角度"], ["BarnDoorLength", "挡板长度"], ["AttenuationRadius", "衰减半径"]);
Object.assign(newState, {
Height: light.Height.toString(),
Width: light.Width.toString(),
BarnDoorAngle: light.BarnDoorAngle.toString(),
BarnDoorLength: light.BarnDoorLength.toString(),
AttenuationRadius: light.AttenuationRadius.toString(),
});
}
else if (light instanceof DirectionalLight)
@ -152,10 +199,11 @@ export class LightStore
{
Object.assign(this.hemisphereLightData, {
GroundColor: "#" + light.GroundColor.getHexString(),
Color: "#" + light.Color.getHexString(),
Intensity: light.Intensity.toString(),
ExposureCompensation: light.ExposureCompensation.toString(),
AutoExposure: light.AutoExposure,
IndirectLightingIntensity: light.IndirectLightingIntensity.toString(),
Intensity: light.Intensity.toString(),
Color: "#" + light.Color.getHexString(),
});
}
@ -186,6 +234,7 @@ export class LightStore
this.ShowAmbientLight = app.Database.AmbientLight.Visible;
this.ShowHemiLight = app.Database.HemisphereLight.Visible;
this.ShowSunLight = app.Database.SunLight.Visible;
this.InitLightData(app.Database.HemisphereLight);
});
app.CommandReactor.OnCommandEnd((name, changeo, creawteo) =>
{
@ -220,9 +269,10 @@ export class LightStore
handleHistory(historyRec.HistoryList);
});
}
private UpdateDirLightShadowArea()
UpdateDirLightShadowArea()
{
if (HostApplicationServices.UseShadow && !app.Database.SunLight.IsErase)
if (HostApplicationServices.UseShadow && !app.Database.SunLight.IsErase && app.Database.SunLight.Intensity)
DirLightShadowArea(app.Database.SunLight);
}
}

@ -21,7 +21,7 @@ export class RightPanelStore
@observable currentTemplateIndex: number;
@observable templateParamInputRefs: HTMLInputElement[] = [];
modelingStore = new ModelingStore();
lightStore = new LightStore();
lightStore = LightStore.GetInstance();
sealingStore = new SealingStore();
drillingStore = new DrillingStore();
modeling2Store = new Modeling2Store();

@ -0,0 +1,487 @@
import { Alignment, Button, Classes, FormGroup, Icon, InputGroup, Intent, Label, NumericInput, Popover, PopoverPosition, Position, Slider, Switch, Tooltip, UL } from "@blueprintjs/core";
import { observable } from "mobx";
import { observer } from "mobx-react";
import React from "react";
import { ColorResult, SketchPicker } from "react-color";
import { Color, MathUtils } from "three";
import { Entitys2Data } from "../../../Add-on/ExportData";
import { app } from "../../../ApplicationServices/Application";
import { ResourcesCDN_HOST } from "../../../Common/HostUrl";
import { FixedNotZero } from "../../../Common/Utils";
import { DirectionalLight } from "../../../DatabaseServices/Lights/DirectionalLight";
import { Light } from "../../../DatabaseServices/Lights/Light";
import { RectAreaLight } from "../../../DatabaseServices/Lights/RectAreaLight";
import { SpotLight } from "../../../DatabaseServices/Lights/SpotLight";
import { commandMachine, CommandWrap } from "../../../Editor/CommandMachine";
import { CommandState } from "../../../Editor/CommandState";
import { PromptStatus } from "../../../Editor/PromptResult";
import { userConfig } from "../../../Editor/UserConfig";
import { AppToaster } from "../../Components/Toaster";
import { LightStore } from "./LightStore";
@observer
export class SpotLightModel extends React.Component<{ store: LightStore; isPointLight: boolean; }, {}>
{
@observable _Target: string = this.props.isPointLight ? (this.props.store.currentSelectEnt as SpotLight | RectAreaLight).Target.sub(this.props.store.currentSelectEnt.Position).normalize().ceil().toArray().toString() : "";
@observable _Position: string = this.props.store.currentSelectEnt.Position.ceil().toArray().toString();
@observable _ShowHelper: boolean = this.props.store.currentSelectEnt.ShowHelper;
@observable _CaseShadow: boolean = this.props.store.currentSelectEnt.CaseShadow;
handleSelectTarget = async (light: Light, isDirection?: boolean, isPosition?: boolean) =>
{
await app.Editor.ModalManage.EndExecingCmd();
let model = app.Editor.ModalManage.CurrentModal;
model.Minimize();
CommandWrap(async () =>
{
app.Editor.MaskManage.Clear();
let ptRes = await app.Editor.GetPoint({
Msg: "选择目标"
});
if (ptRes.Status === PromptStatus.OK)
{
if (isDirection)
{
(light as SpotLight | DirectionalLight).Target = ptRes.Point;
app.Editor.UpdateScreen();
this._Target = ptRes.Point.clone().sub(this.props.store.currentSelectEnt.Position).normalize().ceil().toArray().toString();
if (userConfig.synchronousEnable)
app.WebSocket.Send(JSON.stringify(Entitys2Data([light])));
}
if (isPosition)
{
light.WriteAllObjectRecord();
this.props.store.lightData.x = ptRes.Point.x.toString();
this.props.store.lightData.y = ptRes.Point.y.toString();
this.props.store.lightData.z = ptRes.Point.z.toString();
light.Position = ptRes.Point;
this._Position = ptRes.Point.ceil().toArray().toString();;
}
}
}, "target");
};
//同步数据
private SyncLight()
{
if (userConfig.synchronousEnable)
app.WebSocket.Send(JSON.stringify(Entitys2Data([this.props.store.currentSelectEnt])));
}
render()
{
let lightData = this.props.store.lightData;
let light = this.props.store.currentSelectEnt;
return (
<div id="SpotLightModel" className={Classes.DIALOG_CONTAINER}>
<div className={Classes.DIALOG} style={{ height: "100%" }}>
<div className={Classes.DIALOG_HEADER} data-id="dragArea">
<Icon icon="flash" iconSize={18} />
<h4 className={Classes.HEADING}>{this.props.store.title}</h4>
<Button
icon="cross"
aria-label="Close"
minimal={true}
onClick={() => { app.Editor.ModalManage.Destory(); }}
/>
</div>
<div className={Classes.DIALOG_BODY}>
{
!this.props.isPointLight || <div style={{ height: 25 }}>
<Switch
checked={this._ShowHelper}
label="显示灯光助手"
onChange={e =>
{
CommandWrap(() =>
{
this._ShowHelper = !this._ShowHelper;
light.ShowHelper = !light.ShowHelper;
}, "灯光助手显示/隐藏");
}}
alignIndicator={Alignment.RIGHT}
/>
</div>
}
<div style={{ height: 25 }}>
<Switch
checked={this._CaseShadow}
label="阴影"
onChange={e =>
{
CommandWrap(() =>
{
this._CaseShadow = !this._CaseShadow;
light.CaseShadow = !light.CaseShadow;
}, "阴影显示/隐藏");
}}
alignIndicator={Alignment.RIGHT}
/>
</div>
{
!this.props.isPointLight || <div>
<div>
<Label style={{ float: "left" }}>:</Label>
<input
className={Classes.INPUT}
style={{ height: 27, marginLeft: 10 }}
value={this._Target}
disabled
/>
<div style={{ position: "absolute", right: "48px", marginTop: "-28.5px" }}>
<Tooltip
content="选择照射方向"
position="top"
>
<Button
icon="select"
onClick={() => { this.handleSelectTarget(light, true); }}
/>
</Tooltip>
</div>
</div>
<div style={{ float: "left", position: "absolute", right: "4%" }}>
<Tooltip
content="同时选择照射方向和位置"
position="right"
>
<Button
style={{ marginTop: "-29.5px", height: "65px" }}
icon="select"
onClick={() => { this.handleSelectTarget(light, true, true); }}
/>
</Tooltip>
</div>
</div>
}
<div className="lg-pos">
<Label style={{ float: "left" }}>:</Label>
<UL className={Classes.LIST_UNSTYLED}>
<div className="pos">
<input
className={Classes.INPUT}
style={{ height: 27, marginLeft: 10 }}
value={this._Position}
disabled
/>
<div style={{ position: "absolute", right: this.props.isPointLight ? 48 : 11, marginTop: "-1.5px" }}>
<Tooltip content="选择位置">
<Button
icon="select"
onClick={() => { this.handleSelectTarget(light, false, true); }}
/>
</Tooltip>
</div>
</div>
</UL>
</div>
<div>
<Label style={{ float: "left" }}>:</Label>
<Popover
position={PopoverPosition.TOP}
minimal
content={
<SketchPicker
color={lightData.Color.toUpperCase()}
onChange={(e: ColorResult) =>
{
const KEY = '修改颜色';
if (CommandState.CommandIng)
{
if (app.Database.hm.UndoData.CommandName !== KEY)
{
app.Editor.ModalManage.EndExecingCmd().then(() =>
{
AppToaster.show({
message: "命令正在执行中!无法修改天光颜色!",
timeout: 5000,
intent: Intent.DANGER
});
});
return;
}
}
else
{
commandMachine.CommandStart(KEY);
}
this.props.store.currentSelectEnt.Color = new Color(e.hex.toString());
lightData.Color = e.hex;
app.Viewer.UpdateRender();
this.SyncLight();
}}
onChangeComplete={() =>
{
const KEY = '修改颜色';
if (CommandState.CommandIng && app.Database.hm.UndoData.CommandName === KEY)
{
commandMachine.CommandEnd();
}
}}
/>
}>
<InputGroup
value={lightData.Color.toUpperCase()}
small
leftIcon={
<Icon
icon='stop'
size={20}
color={this.props.store.lightData["Color"]} />
}
/>
</Popover>
</div>
<div>
<Label style={{ float: "left" }}>:</Label>
<Popover
position={Position.TOP_LEFT}
minimal
>
<InputGroup
value={this.props.store.lightData.Temperature.toString() + 'K'}
/>
<div className='sun-colortemp'>
<img alt='色温' draggable={false} src={`${ResourcesCDN_HOST}/colortemperature.webp`} />
<Slider
min={1800}
max={16000}
stepSize={1}
labelStepSize={1775}
showTrackFill={false}
labelRenderer={() => (`${this.props.store.lightData.Temperature}K`)}
value={parseInt(this.props.store.lightData.Temperature)}
onChange={async (val) =>
{
const KEY = "修改射灯色温";
if (CommandState.CommandIng)
{
if (app.Database.hm.UndoData.CommandName !== KEY)
{
await app.Editor.ModalManage.EndExecingCmd();
AppToaster.show({
message: "命令正在执行中!无法修改射灯色温!",
timeout: 5000,
intent: Intent.DANGER,
});
return;
}
}
else
{
commandMachine.CommandStart(KEY);
}
this.props.store.currentSelectEnt.Temperature = val;
this.props.store.lightData.Temperature = val.toString();
if (userConfig.synchronousEnable)
app.WebSocket.Send(JSON.stringify(Entitys2Data([this.props.store.currentSelectEnt])));
}}
onRelease={() =>
{
const KEY = "修改射灯色温";
if (CommandState.CommandIng && app.Database.hm.UndoData.CommandName === KEY)
commandMachine.CommandEnd();
}}
/>
</div>
</Popover>
</div>
{
this.props.store.pars.map(([k, v]) =>
{
let max: number = 200;
let min: number = 0;
let isFloat: boolean = false; //stepsize 是否为0.1
let noLim: boolean = false;
switch (k)
{
case "Intensity":
max = 2000;
break;
case "IndirectLightingIntensity":
max = 6;
break;
case "Angle":
case "InnerConeAngle":
case "BarnDoorAngle":
max = 90;
break;
case "SpecularScale":
max = 1;
isFloat = true;
break;
case "SourceLength":
max = 1000;
break;
case "SourceRadius":
case "SoftSourceRadius":
max = 300;
break;
case "AttenuationRadius":
min = 10;
max = 1000;
break;
case "Width":
case "Height":
min = 1;
max = 5000;
noLim = true;
break;
case "BarnDoorLength":
max = 100;
break;
default:
break;
}
return <InputAndSlider
pars={[k, v]}
store={this.props.store}
max={max}
min={min}
isFloat={isFloat}
noLim={noLim}
/>;
})
}
</div>
</div>
</div >
);
}
}
@observer
export class InputAndSlider extends React.Component<{ pars: string[], store: LightStore; max: number; isFloat: boolean; min: number; noLim: boolean; }, {}>
{
@observable _InputEl = React.createRef<NumericInput>();
SetValue(value: string)
{
const KEY = "修改灯光" + this.props.pars[1];;
if (CommandState.CommandIng)
{
if (app.Database.hm.UndoData.CommandName !== KEY)
{
app.Editor.ModalManage.EndExecingCmd().then(() =>
{
if (CommandState.CommandIng)
{
AppToaster.show({
message: "命令正在执行中!无法修改灯光" + this.props.pars[1] + "!",
timeout: 5000,
intent: Intent.DANGER,
});
return;
}
});
}
}
else
{
commandMachine.CommandStart(KEY);
}
switch (this.props.pars[0])
{
case "InnerConeAngle":
this.props.store.lightData.InnerConeAngle = value;
this.props.store.currentSelectEnt[this.props.pars[0]] = parseInt(value);
if (parseInt(value) > parseInt(this.props.store.lightData.Angle))
{
this.props.store.lightData.Angle = value;
this.props.store.currentSelectEnt["Angle"] = MathUtils.degToRad(parseInt(value));
}
break;
case "Angle":
this.props.store.lightData.Angle = value;
this.props.store.currentSelectEnt["Angle"] = MathUtils.degToRad(parseInt(value));
if (parseInt(value) < parseInt(this.props.store.lightData.InnerConeAngle))
{
this.props.store.lightData.InnerConeAngle = value;
this.props.store.currentSelectEnt["InnerConeAngle"] = parseInt(value);
}
break;
case "SpecularScale":
this.props.store.lightData.SpecularScale = value;
this.props.store.currentSelectEnt.SpecularScale = parseFloat(value);
break;
default:
this.props.store.lightData[this.props.pars[0]] = value;
this.props.store.currentSelectEnt[this.props.pars[0]] = parseInt(value);
break;
}
this.props.store.currentSelectEnt.Update();
app.Editor.UpdateScreen();
}
private SyncLight()
{
if (userConfig.synchronousEnable)
app.WebSocket.Send(JSON.stringify(Entitys2Data([this.props.store.currentSelectEnt])));
}
render()
{
return (
<FormGroup>
<div className='light'>
<Label style={{ float: "left", width: 56, marginTop: 5 }}>{this.props.pars[1]}:</Label>
<NumericInput
min={this.props.min}
max={this.props.noLim ? 10e6 : this.props.max}
ref={this._InputEl}
buttonPosition={"none"}
value={this.props.store.lightData[this.props.pars[0]]}
onKeyDown={(e) =>
{
e.stopPropagation();
}}
onValueChange={(num) =>
{
if (isNaN(num) || num < this.props.min || num > (this.props.noLim ? 10e6 : this.props.max)) return;
this.SetValue(FixedNotZero(num, 1));
this.SyncLight();
app.Viewer.UpdateRender();
}}
onBlur={() =>
{
const KEY = '修改灯光' + this.props.pars[1];;
if (CommandState.CommandIng && app.Database.hm.UndoData.CommandName === KEY)
{
commandMachine.CommandEnd();
}
}}
onFocus={(e) =>
{
e.target.select();
}}
/>
<Slider
min={this.props.min}
max={this.props.max}
stepSize={this.props.isFloat ? 0.1 : 1}
value={parseFloat(this.props.store.lightData[this.props.pars[0]]) >= this.props.max ? this.props.max : parseFloat(this.props.store.lightData[this.props.pars[0]])}
onChange={(e) =>
{
this.SetValue((FixedNotZero(e, this.props.isFloat ? 1 : 0)));
this.SyncLight();
app.Viewer.UpdateRender();
}}
onRelease={() =>
{
const KEY = '修改灯光' + this.props.pars[1];
if (CommandState.CommandIng && app.Database.hm.UndoData.CommandName === KEY)
{
commandMachine.CommandEnd();
}
}}
/>
</div>
</FormGroup>
);
}
}
Loading…
Cancel
Save