Commit 8382b873 authored by wjf's avatar wjf

2.0.22

parent 5acaa1b1
......@@ -14,4 +14,5 @@ rollup.config.js
record.txt
test
examples
docs
\ No newline at end of file
docs
aaa.html
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -71,7 +71,7 @@
1624,//设计高度
sysInfo && sysInfo.windowWidth || document.body.clientWidth,
sysInfo && sysInfo.windowHeight || document.body.clientHeight,
FYGE.RENDERER_TYPE.WEBGL,
FYGE.RENDERER_TYPE.CANVAS,
);
//监听窗口缩放,按需,一般移动端的不需要
window.addEventListener('resize', () => { stage.resize() });
......@@ -239,15 +239,24 @@
// s.drawRoundedRect(300, 100, 200, 100, 1111)
// s.endFill()
//画线
var s = stage.addChild(new FYGE.Shape())
s.beginStroke(0, 3)
s.moveTo(10, 10);
s.lineTo(10, 500);
s.lineTo(200, 500);
s.lineTo(200, 10);
s.lineTo(10, 10);
// var s = stage.addChild(new FYGE.Shape())
// s.beginStroke(0, 3)
// s.moveTo(10, 10);
// s.lineTo(10, 500);
// s.lineTo(200, 500);
// s.lineTo(200, 10);
// s.lineTo(10, 10);
// s.endStroke()
var s = stage.addChild(new FYGE.Graphics())
s.lineStyle(5,0,1,1)
s.arc(100,100,40,0,Math.PI*2)
s.endStroke()
//测试svga蒙版
SvgaParser.loadSvga("./res/测蒙版.svga", (v) => {
stage.addChild(new FYGE.MovieClip(v)).y -= 100
})
// console.log( FYGE.toDisplayDataURL(stage,null,{type: "jpeg"}))
}, this);
......
{
"name": "fyge",
"version": "2.0.21",
"version": "2.0.22",
"description": "canvas渲染引擎",
"main": "./build/fyge.min.js",
"types": "./build/types.d.ts",
......
......@@ -268,6 +268,38 @@
getCusShader添加了很多关于fog的
GLFramebuffers的静态方法createRGBA打开注释fbo.enableStencil()
2.0.22 Graphics的_renderCanvas方法里加回this.parent判断,并执行updateTransform,否则canvas模式会出现一帧闪烁,因为下一帧位置信息才修正,待测试
AnimationClip的gotoAndStop方法添加第二个参数force,传入true确保必刷新动画,主要为了time传0时和lastTime相等就不刷新了
MovieClip添加遮罩相关方法updateMask,后续考虑矢量图也能加
Object3D添加castShadow和receiveShadow方法
Object3D的lookAt添加判断加一个OrthographicCamera
Object3D的updateWorldMatrix方法执行父级的方法时判断下父级的updateWorldMatrix方法是否存在
PerspectiveCamera的clone方法添加
PerspectiveCamera的copy里执行updateProjectionMatrix
加了几个几何类CylinderGeometry,RingGeometry,TorusGeometry
Matrix4的setOrtho和ortho方法的参数top和bottom替换下顺序,先top再bottom
getCusShader着色器里预乘传入的材质和透明度 color.rgb *= color.a;
getCusShader着色器雾化里雾化颜色乘透明uFogColor*color.a
D3Renderer的start方法先去掉了setBlendMode,让着色器里预乘
D3Renderer的flush方法里glVaoBuffer用generateVaoBuffer
3d影子添加修改
D3Renderer添加viewport,为了绘制阴影深度后还原视窗,
D3Renderer添加shadowType
D3Renderer里加了getShadowMap,等等很多东西
Scene3D添加shadowType
Scene3D添加setViewport
Scene3D的getBounds方法修改
Scene3D的getLightConfig修改
DirectionalLightConfig接口添加很多参数
新增OrthographicCamera方法
新增LightShadow DirectionalLightShadow类
基类Light里添加shadow
getCusShader添加参数shadow,parameters添加useShadow和shadowType,相应预处理宏修改,着色器修改 #ifdef USE_SHADOW',
新增着色器ShadowShader
现在不改,索引数据过大时得用Uint32Array,同时开扩展gl.getExtension( "OES_element_index_uint" )和drawElements改参数类型为gl.UNSIGNED_INT
......@@ -279,6 +311,14 @@
检查spine变形动画切换不回默认
FloatDisplay的updateStyle方法并不会在父级visible改变时修改,考虑如何解决
3d的灯光应该遍历整个scene
到时手动排序,透明和不透明分开,然后根据材质
影子,先确定那些物体能投射影子
以后要改成和three一样的几何数据处理方式,为了数据能修改
以后光照要改成和three一样的处理方式
......
......@@ -147,12 +147,15 @@ export class AnimationClip extends EventDispatcher {
/**
* 停在指定时间
* @param time
* @param force 是否强制更新,默认false,如果发现没stop在指定位置,可以试试设置true
*/
public gotoAndStop(time: number): void {
public gotoAndStop(time: number, force: boolean = false): void {
this._isPlaying = false;
if (time > this.totalTime) time = this.totalTime;
if (time < 0) time = 0;
this.curTime = time;;
this.curTime = time;
//这样会强制更新
if (force) this.lastTime = null
}
private startAniRangeFun;
......
......@@ -7,7 +7,7 @@
* @name VERSION
* @type {string}
*/
export const VERSION = "2.0.21";
export const VERSION = "2.0.22";
/**
......
This diff is collapsed.
......@@ -121,7 +121,7 @@ export default class Transform extends HashObject {
const lt = this.localMatrix;
if (this._localID !== this._currentLocalID) {
// get the matrix values of the displayobject based on its transform properties..
//根据基础属性计算本地矩阵
lt.a = this._cx * this.scale._x;
lt.b = this._sx * this.scale._x;
lt.c = this._cy * this.scale._y;
......@@ -146,7 +146,7 @@ export default class Transform extends HashObject {
//先确定local是否需要更新
if (this._localID !== this._currentLocalID) {
// get the matrix values of the displayobject based on its transform properties..
//根据基础属性计算本地矩阵
lt.a = this._cx * this.scale._x;
lt.b = this._sx * this.scale._x;
lt.c = this._cy * this.scale._y;
......
......@@ -7,6 +7,7 @@ import { TextureCache, createImage, createCanvas } from "../utils";
import { RAD_TO_DEG } from "../const";
import { Matrix } from "../math";
import { BaseTexture } from "../texture";
import { Shape } from "../graphics";
/**
* 用于播放动画
......@@ -615,6 +616,18 @@ export class MovieClip extends Container {
child.transform.localMatrix.copy(frame.transform)
child.transform._parentID = -1;
}
//遮罩
if (frame.maskPath) {
if (!child["cusMask"]) child["cusMask"] = new Shape();
//@ts-ignore ,需要记载child里
if (!child.mask) child.mask = child.addChild(child["cusMask"]);
let mask = child.mask;
this.updateMask(mask, frame.maskPath);
} else if (child.mask) {
//@ts-ignore移除
child.removeChild(child.mask)
child.mask = null;
}
}
}
}
......@@ -702,6 +715,141 @@ export class MovieClip extends Container {
super.destroy();
}
private updateMask(mask: Shape, data: { _d: string, _style: any, _transform: any }) {
mask.clear();
//会用到的,再说TODO
if (data._transform) {
}
let currentPoint = { x: 0, y: 0, x1: 0, y1: 0, x2: 0, y2: 0 }
//暂时不需要绘制的东西
mask.beginFill();
const validMethods = 'MLHVCSQRZmlhvcsqrz'
const d = data._d.replace(/([a-zA-Z])/g, '|||$1 ').replace(/,/g, ' ');
d.split('|||').forEach(segment => {
if (segment.length == 0) return;
const firstLetter = segment.substr(0, 1);
if (validMethods.indexOf(firstLetter) >= 0) {
const args = segment.substr(1).trim().split(" ");
switch (firstLetter) {
case 'M':
currentPoint.x = Number(args[0]);
currentPoint.y = Number(args[1]);
mask.moveTo(currentPoint.x, currentPoint.y);
break;
case 'm':
currentPoint.x += Number(args[0]);
currentPoint.y += Number(args[1]);
mask.moveTo(currentPoint.x, currentPoint.y);
break;
case 'L':
currentPoint.x = Number(args[0]);
currentPoint.y = Number(args[1]);
mask.lineTo(currentPoint.x, currentPoint.y);
break;
case 'l':
currentPoint.x += Number(args[0]);
currentPoint.y += Number(args[1]);
mask.lineTo(currentPoint.x, currentPoint.y);
break;
case 'H':
currentPoint.x = Number(args[0]);
mask.lineTo(currentPoint.x, currentPoint.y);
break;
case 'h':
currentPoint.x += Number(args[0]);
mask.lineTo(currentPoint.x, currentPoint.y);
break;
case 'V':
currentPoint.y = Number(args[0]);
mask.lineTo(currentPoint.x, currentPoint.y);
break;
case 'v':
currentPoint.y += Number(args[0]);
mask.lineTo(currentPoint.x, currentPoint.y);
break;
case 'C':
currentPoint.x1 = Number(args[0]);
currentPoint.y1 = Number(args[1]);
currentPoint.x2 = Number(args[2]);
currentPoint.y2 = Number(args[3]);
currentPoint.x = Number(args[4]);
currentPoint.y = Number(args[5]);
mask.bezierCurveTo(currentPoint.x1, currentPoint.y1, currentPoint.x2, currentPoint.y2, currentPoint.x, currentPoint.y);
break;
case 'c':
currentPoint.x1 = currentPoint.x + Number(args[0]);
currentPoint.y1 = currentPoint.y + Number(args[1]);
currentPoint.x2 = currentPoint.x + Number(args[2]);
currentPoint.y2 = currentPoint.y + Number(args[3]);
currentPoint.x += Number(args[4]);
currentPoint.y += Number(args[5]);
mask.bezierCurveTo(currentPoint.x1, currentPoint.y1, currentPoint.x2, currentPoint.y2, currentPoint.x, currentPoint.y);
break;
case 'S':
if (currentPoint.x1 && currentPoint.y1 && currentPoint.x2 && currentPoint.y2) {
currentPoint.x1 = currentPoint.x - currentPoint.x2 + currentPoint.x;
currentPoint.y1 = currentPoint.y - currentPoint.y2 + currentPoint.y;
currentPoint.x2 = Number(args[0]);
currentPoint.y2 = Number(args[1]);
currentPoint.x = Number(args[2]);
currentPoint.y = Number(args[3]);
mask.bezierCurveTo(currentPoint.x1, currentPoint.y1, currentPoint.x2, currentPoint.y2, currentPoint.x, currentPoint.y);
} else {
currentPoint.x1 = Number(args[0]);
currentPoint.y1 = Number(args[1]);
currentPoint.x = Number(args[2]);
currentPoint.y = Number(args[3]);
mask.quadraticCurveTo(currentPoint.x1, currentPoint.y1, currentPoint.x, currentPoint.y);
}
break;
case 's':
if (currentPoint.x1 && currentPoint.y1 && currentPoint.x2 && currentPoint.y2) {
currentPoint.x1 = currentPoint.x - currentPoint.x2 + currentPoint.x;
currentPoint.y1 = currentPoint.y - currentPoint.y2 + currentPoint.y;
currentPoint.x2 = currentPoint.x + Number(args[0]);
currentPoint.y2 = currentPoint.y + Number(args[1]);
currentPoint.x += Number(args[2]);
currentPoint.y += Number(args[3]);
mask.bezierCurveTo(currentPoint.x1, currentPoint.y1, currentPoint.x2, currentPoint.y2, currentPoint.x, currentPoint.y);
} else {
currentPoint.x1 = currentPoint.x + Number(args[0]);
currentPoint.y1 = currentPoint.y + Number(args[1]);
currentPoint.x += Number(args[2]);
currentPoint.y += Number(args[3]);
mask.quadraticCurveTo(currentPoint.x1, currentPoint.y1, currentPoint.x, currentPoint.y);
}
break;
case 'Q':
currentPoint.x1 = Number(args[0]);
currentPoint.y1 = Number(args[1]);
currentPoint.x = Number(args[2]);
currentPoint.y = Number(args[3]);
mask.quadraticCurveTo(currentPoint.x1, currentPoint.y1, currentPoint.x, currentPoint.y);
break;
case 'q':
currentPoint.x1 = currentPoint.x + Number(args[0]);
currentPoint.y1 = currentPoint.y + Number(args[1]);
currentPoint.x += Number(args[2]);
currentPoint.y += Number(args[3]);
mask.quadraticCurveTo(currentPoint.x1, currentPoint.y1, currentPoint.x, currentPoint.y);
break;
case 'A':
break;
case 'a':
break;
case 'Z':
case 'z':
mask.closePath();
break;
default:
break;
}
}
})
//暂时没有其他绘制,直接endFill
mask.endFill();
}
/**
* 用源数据拷贝一份,用相应参数
* @param frames 源数据
......
This diff is collapsed.
......@@ -23,6 +23,14 @@ export class Object3D extends EventDispatcher {
public mouseEnable: boolean = true;
public mouseChildren: boolean = true;
/**
* 是否投射影子,针对光源和物体
*/
public castShadow: boolean = false;
/**
* 是否接收影子,针对物体,考虑包括光感与非光感吗?
*/
public receiveShadow: boolean = false;
/**
* 场景
*/
......@@ -195,7 +203,7 @@ export class Object3D extends EventDispatcher {
position.setFromMatrixPosition(this._worldMatrix);
if (this._instanceType == "Camera" || this._instanceType == "PerspectiveCamera") {
if (this._instanceType == "Camera" || this._instanceType == "PerspectiveCamera" || this._instanceType == "OrthographicCamera") {
m1.lookAt(position, target, this.up);
} else {
m1.lookAt(target, position, this.up);
......@@ -259,8 +267,8 @@ export class Object3D extends EventDispatcher {
var parent = this.parent;
if (updateParents === true && parent !== null) {
//先往父级递归计算矩阵
parent.updateWorldMatrix(true, false);
//先往父级递归计算矩阵,判断一次是否2d的父级
parent.updateWorldMatrix && parent.updateWorldMatrix(true, false);
}
//更新本地矩阵先,后续优化加标记
......
......@@ -13,14 +13,18 @@ import { MouseEvent } from "../2d/events";
import { Raycaster } from "./Raycaster";
import { Filter } from "../2d/filter";
import { hex2rgb } from "../2d/utils";
import { DirectionalLightShadow } from "./lights/DirectionalLightShadow";
export enum ShadowType {
basic = "SHADOWMAP_TYPE_BASIC",
pcf = "SHADOWMAP_TYPE_PCF",
}
/**
* 作为3D的顶级容器,不能被object3D添加,自身不能添加其他2D元素
* 带透明度的融合有问题,尽量自行调整渲染顺序
*/
export class Scene3D extends Object3D {
private _viewId: number = 0;
private _viewId: number = -1;
/**
* gl的视窗数据记录,是左下角开始,以防混淆不用Rectangle
*/
......@@ -103,7 +107,10 @@ export class Scene3D extends Object3D {
camera: Camera;
private raycaster: Raycaster = new Raycaster();
/**
* 阴影类型
*/
public shadowType: ShadowType = ShadowType.basic;
/**
* 滤镜数组
*/
......@@ -141,35 +148,17 @@ export class Scene3D extends Object3D {
plugin.lightsConfig = this.getLightConfig();
//雾化
plugin.fog = this._fog || null;
//阴影类型
plugin.shadowType = this.shadowType;
//设置插件,会调用start,如果是两个场景,会有问题,因为是同一个插件不会flush上一个,到时注意修改
renderer.batchManager.setObjectRenderer(plugin);
//自己的位置
if (this._viewId !== this.parent.transform._worldID) {
this._viewId = this.parent.transform._worldID;
var pt = this.parent.transform.worldMatrix;
var x = (this.viewX * pt.a) + (this.viewY * pt.c) + pt.tx;
var y = (this.viewX * pt.b) + (this.viewY * pt.d) + pt.ty;
//计算实际的viewWidth和viewHeight,简单点直接是父级的缩放,还是要全局的缩放,如果只在舞台
var scaleX = Math.sqrt((pt.a * pt.a) + (pt.b * pt.b));
var scaleY = Math.sqrt((pt.c * pt.c) + (pt.d * pt.d));
//记录
this._viewport = {
x,
y: renderer.height - y - this.viewHeight * scaleY,
width: this.viewWidth * scaleX,
height: this.viewHeight * scaleY
}
}
//修改视窗,每次都要执行
this._viewport && renderer.gl.viewport(
this._viewport.x,
this._viewport.y,
this._viewport.width,
this._viewport.height
);
this.setViewport(renderer);
plugin.viewport = this._viewport;
//处理子级东西
if (this.filters && this.filters.length) {
//估计没必要
......@@ -196,8 +185,35 @@ export class Scene3D extends Object3D {
}
}
setViewport(renderer: WebglRenderer) {
if (this._viewId !== this.parent.transform._worldID) {
this._viewId = this.parent.transform._worldID;
var pt = this.parent.transform.worldMatrix;
var x = (this.viewX * pt.a) + (this.viewY * pt.c) + pt.tx;
var y = (this.viewX * pt.b) + (this.viewY * pt.d) + pt.ty;
//计算实际的viewWidth和viewHeight,简单点直接是父级的缩放,还是要全局的缩放,如果只在舞台
var scaleX = Math.sqrt((pt.a * pt.a) + (pt.b * pt.b));
var scaleY = Math.sqrt((pt.c * pt.c) + (pt.d * pt.d));
//记录
this._viewport = {
x,
y: renderer.height - y - this.viewHeight * scaleY,
width: this.viewWidth * scaleX,
height: this.viewHeight * scaleY
}
}
this._viewport && renderer.gl.viewport(
this._viewport.x,
this._viewport.y,
this._viewport.width,
this._viewport.height
);
}
getBounds() {
return new Rectangle(this._viewX, this._viewY, this._viewWidth, this._viewHeight)
var pt = this.parent.transform.worldMatrix;
var y = (this.viewX * pt.b) + (this.viewY * pt.d) + pt.ty;
return new Rectangle(this._viewport.x, y, this._viewport.width, this._viewport.height)
}
getLightConfig(
con: Object3D = this,
......@@ -206,31 +222,64 @@ export class Scene3D extends Object3D {
var viewMatrix = this.camera.worldMatrixInverse;
for (var i = 0; i < con.children.length; i++) {
var c = con.children[i] as Light;
if (!(c instanceof Light)) continue;
var color: number[] = c.colorVec3.clone().multiplyScalar(c.intensity).toArray();
if (c.instanceType == "AmbientLight") {
arr.ambientLightColor[0] += color[0];
arr.ambientLightColor[1] += color[1];
arr.ambientLightColor[2] += color[2];
}
else if (c.instanceType == "PointLight") {
var position: Vector3 = new Vector3().setFromMatrixPosition(c._worldMatrix);
position.applyMatrix4(viewMatrix);//这步是否需要,待测试
arr.pointLights.push({
color: color,
position: position.toArray(),
distance: c["distance"],
decay: c["distance"] === 0 ? 0.0 : c["decay"],
})
}
else if (c.instanceType == "DirectionalLight") {
var direction: Vector3 = new Vector3().setFromMatrixPosition(c._worldMatrix);
direction.sub(new Vector3().setFromMatrixPosition(c["target"]._worldMatrix));
direction.transformDirection(viewMatrix);
arr.directionalLights.push({
color: color,
direction: direction.normalize().toArray()
})
if (c instanceof Light) {
var color: number[] = c.colorVec3.clone().multiplyScalar(c.intensity).toArray();
if (c.instanceType == "AmbientLight") {
arr.ambientLightColor[0] += color[0];
arr.ambientLightColor[1] += color[1];
arr.ambientLightColor[2] += color[2];
}
else if (c.instanceType == "PointLight") {
var position: Vector3 = new Vector3().setFromMatrixPosition(c._worldMatrix);
position.applyMatrix4(viewMatrix);//这步是否需要,待测试
arr.pointLights.push({
color: color,
position: position.toArray(),
distance: c["distance"],
decay: c["distance"] === 0 ? 0.0 : c["decay"],
})
}
else if (c.instanceType == "DirectionalLight") {
var direction: Vector3 = new Vector3().setFromMatrixPosition(c._worldMatrix);
direction.sub(new Vector3().setFromMatrixPosition(c["target"]._worldMatrix));
direction.transformDirection(viewMatrix);
var shadowMatrixDepth: number[];
if (c.castShadow) {//这里直接计算了灯光的相机吧
if (!c.shadow.map) {
//暂时不用这个map。因为现在就一个
}
var shadowCamera = c.shadow.camera,
shadowMatrix = c.shadow.matrix,
lightP = c._worldMatrix.elements.slice(12, 15),
lightTargetP = c["target"]._worldMatrix.elements.slice(12, 15);
shadowCamera.position.set(lightP[0], lightP[1], lightP[2]);
shadowCamera.lookAt(lightTargetP[0], lightTargetP[1], lightTargetP[2]);
shadowCamera.updateWorldMatrix();
//利用shadowMatrix算一次
shadowMatrixDepth = shadowMatrix.setIdentity()
.multiply(shadowCamera.projectionMatrix)
.multiply(shadowCamera.worldMatrixInverse).toArray();
//重算几次
shadowMatrix.set(//这里为了减少着色器里的计算
0.5, 0.0, 0.0, 0.5,
0.0, 0.5, 0.0, 0.5,
0.0, 0.0, 0.5, 0.5,
0.0, 0.0, 0.0, 1.0
);
shadowMatrix.multiply(shadowCamera.projectionMatrix);
shadowMatrix.multiply(shadowCamera.worldMatrixInverse);
}
arr.directionalLights.push({
color: color,
direction: direction.normalize().toArray(),
castShadow: c.castShadow,
shadowMatrixDepth,
shadowMatrix: c.shadow.matrix.toArray(),
bias: c.shadow.bias,
radius: c.shadow.radius,
mapSize: [c.shadow.mapSize.x, c.shadow.mapSize.y]
})
}
}
if (c.children && c.children.length) this.getLightConfig(c, arr);
}
......@@ -539,6 +588,18 @@ interface PointLightConfig {
interface DirectionalLightConfig {
direction: number[],
color: number[],
castShadow: boolean,
/**
* 生成深度图的矩阵
*/
shadowMatrixDepth: number[],
/**
* 传入正常场景的光照矩阵
*/
shadowMatrix: number[],
bias: number,
radius: number,
mapSize: [number, number]
}
......
import { Camera } from "./Camera";
export class OrthographicCamera extends Camera {
zoom: number;
constructor(
private left: number = -1,
private right: number = 1,
private top: number = 1,
private bottom: number = -1,
private near: number = 0.1,
private far: number = 2000,
) {
super();
this._instanceType = 'OrthographicCamera';
this.zoom = 1;
this.updateProjectionMatrix();
}
set(
left: number,
right: number,
top: number,
bottom: number,
near: number = 0.1,
far: number = 2000,
) {
this.zoom = 1;
this.left = left;
this.right = right;
this.top = top;
this.bottom = bottom;
this.near = near;
this.far = far;
this.updateProjectionMatrix();
}
copy(source: OrthographicCamera, recursive: boolean = true) {
super.copy(source, recursive)
this.left = source.left;
this.right = source.right;
this.top = source.top;
this.bottom = source.bottom;
this.near = source.near;
this.far = source.far;
this.zoom = source.zoom;
this.updateProjectionMatrix();
return this;
}
clone() {
return new OrthographicCamera().copy(this)
}
updateProjectionMatrix() {
var dx = (this.right - this.left) / (2 * this.zoom);
var dy = (this.top - this.bottom) / (2 * this.zoom);
var cx = (this.right + this.left) / 2;
var cy = (this.top + this.bottom) / 2;
var left = cx - dx;
var right = cx + dx;
var top = cy + dy;
var bottom = cy - dy;
this.projectionMatrix.setOrtho(left, right, top, bottom, this.near, this.far);
this.projectionMatrixInverse.setInverseOf(this.projectionMatrix);
}
}
......@@ -55,9 +55,13 @@ export class PerspectiveCamera extends Camera {
this.aspect = source.aspect;
this.updateProjectionMatrix();
return this;
}
clone() {
return new PerspectiveCamera().copy(this)
}
/**
* 更新
*/
......
import { Geometry } from "../Geometry";
import { Vector2 } from "../math/Vector2";
import { Vector3 } from "../math/Vector3";
export class CylinderGeometry extends Geometry {
constructor(
/**
* 上圆半径,默认1
*/
radiusTop: number = 1,
/**
* 下圆半径,默认1
*/
radiusBottom: number = 1,
/**
* 高度,默认1
*/
height: number = 1,
/**
* 径向分段数,整数,默认8
*/
radialSegments: number = 8,
/**
* 高度分段数,整数,默认1
*/
heightSegments: number = 1,
/**
* 是否开口,默认false
*/
openEnded = false,
/**
* 圆柱开始角度,默认0
*/
thetaStart: number = 0,
/**
* 圆柱结束角度,默认Math.PI * 2
*/
thetaLength: number = Math.PI * 2
) {
//避免小数和0
radialSegments = Math.floor(radialSegments) || 8;
heightSegments = Math.floor(heightSegments) || 1;
var indices = [];
var vertices = [];
var normals = [];
var uvs = [];
var index = 0;
var indexArray = [];
var halfHeight = height / 2;
var groupStart = 0;
// generate geometry
generateTorso();
if (!openEnded) {
if (radiusTop > 0) generateCap(true);
if (radiusBottom > 0) generateCap(false);
}
// build geometry
// this.setIndex(indices);
// this.addAttribute('position', new Float32BufferAttribute(vertices, 3));
// this.addAttribute('normal', new Float32BufferAttribute(normals, 3));
// this.addAttribute('uv', new Float32BufferAttribute(uvs, 2));
function generateTorso() {
var x, y;
var normal = new Vector3();
var vertex = new Vector3();
var groupCount = 0;
// this will be used to calculate the normal
var slope = (radiusBottom - radiusTop) / height;
// generate vertices, normals and uvs
for (y = 0; y <= heightSegments; y++) {
var indexRow = [];
var v = y / heightSegments;
// calculate the radius of the current row
var radius = v * (radiusBottom - radiusTop) + radiusTop;
for (x = 0; x <= radialSegments; x++) {
var u = x / radialSegments;
var theta = u * thetaLength + thetaStart;
var sinTheta = Math.sin(theta);
var cosTheta = Math.cos(theta);
// vertex
vertex.x = radius * sinTheta;
vertex.y = - v * height + halfHeight;
vertex.z = radius * cosTheta;
vertices.push(vertex.x, vertex.y, vertex.z);
// normal
normal.set(sinTheta, slope, cosTheta).normalize();
normals.push(normal.x, normal.y, normal.z);
// uv
// uvs.push(u, 1 - v);
uvs.push(u, v);
// save index of vertex in respective row
indexRow.push(index++);
}
// now save vertices of the row in our index array
indexArray.push(indexRow);
}
// generate indices
for (x = 0; x < radialSegments; x++) {
for (y = 0; y < heightSegments; y++) {
// we use the index array to access the correct indices
var a = indexArray[y][x];
var b = indexArray[y + 1][x];
var c = indexArray[y + 1][x + 1];
var d = indexArray[y][x + 1];
// faces
indices.push(a, b, d);
indices.push(b, c, d);
// update group counter
groupCount += 6;
}
}
// add a group to the geometry. this will ensure multi material support
//以后考虑每个面能各自改变
// scope.addGroup(groupStart, groupCount, 0);
// calculate new start value for groups
groupStart += groupCount;
}
function generateCap(top) {
var x, centerIndexStart, centerIndexEnd;
var uv = new Vector2();
var vertex = new Vector3();
var groupCount = 0;
var radius = (top === true) ? radiusTop : radiusBottom;
var sign = (top === true) ? 1 : - 1;
// save the index of the first center vertex
centerIndexStart = index;
// first we generate the center vertex data of the cap.
// because the geometry needs one set of uvs per face,
// we must generate a center vertex per face/segment
for (x = 1; x <= radialSegments; x++) {
// vertex
vertices.push(0, halfHeight * sign, 0);
// normal
normals.push(0, sign, 0);
// uv
uvs.push(0.5, 0.5);
// increase index
index++;
}
// save the index of the last center vertex
centerIndexEnd = index;
// now we generate the surrounding vertices, normals and uvs
for (x = 0; x <= radialSegments; x++) {
var u = x / radialSegments;
var theta = u * thetaLength + thetaStart;
var cosTheta = Math.cos(theta);
var sinTheta = Math.sin(theta);
// vertex
vertex.x = radius * sinTheta;
vertex.y = halfHeight * sign;
vertex.z = radius * cosTheta;
vertices.push(vertex.x, vertex.y, vertex.z);
// normal
normals.push(0, sign, 0);
// uv
uv.x = (cosTheta * 0.5) + 0.5;
uv.y = (sinTheta * 0.5 * sign) + 0.5;
uvs.push(uv.x, uv.y);
// increase index
index++;
}
// generate indices
for (x = 0; x < radialSegments; x++) {
var c = centerIndexStart + x;
var i = centerIndexEnd + x;
if (top === true) {
// face top
indices.push(i, i + 1, c);
} else {
// face bottom
indices.push(i + 1, i, c);
}
groupCount += 3;
}
// add a group to the geometry. this will ensure multi material support
// scope.addGroup(groupStart, groupCount, top === true ? 1 : 2);
// calculate new start value for groups
groupStart += groupCount;
}
super(vertices, indices, normals, null, uvs)
}
}
\ No newline at end of file
/*
* RingGeometry.ts
* Created by 还有醋v on 2021/4/15.
* Copyright © 2021 haiyoucuv. All rights reserved.
*/
import { Geometry } from "../Geometry";
import { Vector2 } from "../math/Vector2";
import { Vector3 } from "../math/Vector3";
export class RingGeometry extends Geometry {
constructor(
innerRadius = 0.5,
outerRadius = 1,
thetaSegments = 8,
phiSegments = 1,
thetaStart = 0,
thetaLength = Math.PI * 2
) {
thetaSegments = Math.max(3, thetaSegments);
phiSegments = Math.max(1, phiSegments)
// buffers
const indices = [];
const vertices = [];
const normals = [];
const uvs = [];
// some helper variables
let segment;
let radius = innerRadius;
const radiusStep = ((outerRadius - innerRadius) / phiSegments);
const vertex = new Vector3();
const uv = new Vector2();
let j, i;
// generate vertices, normals and uvs
for (j = 0; j <= phiSegments; j++) {
for (i = 0; i <= thetaSegments; i++) {
// values are generate from the inside of the ring to the outside
segment = thetaStart + i / thetaSegments * thetaLength;
// vertex
vertex.x = radius * Math.cos(segment);
vertex.y = radius * Math.sin(segment);
vertices.push(vertex.x, vertex.y, vertex.z);
// normal
normals.push(0, 0, 1);
// uv
uv.x = (vertex.x / outerRadius + 1) / 2;
uv.y = 1 - (vertex.y / outerRadius + 1) / 2;
uvs.push(uv.x, uv.y);
}
// increase the radius for next row of vertices
radius += radiusStep;
}
// indices
for (j = 0; j < phiSegments; j++) {
const thetaSegmentLevel = j * (thetaSegments + 1);
for (i = 0; i < thetaSegments; i++) {
segment = i + thetaSegmentLevel;
const a = segment;
const b = segment + thetaSegments + 1;
const c = segment + thetaSegments + 2;
const d = segment + 1;
// faces
indices.push(a, b, d);
indices.push(b, c, d);
}
}
super(vertices, indices, normals, null, uvs);
}
}
/**
* @author oosmoxiecode
* @author mrdoob / http://mrdoob.com/
* @author Mugen87 / https://github.com/Mugen87
*/
import { Geometry } from "../Geometry";
import { Vector3 } from "../math/Vector3";
export class TorusGeometry extends Geometry {
constructor(
radius = 1,
tube = 0.4,
radialSegments = 8,
tubularSegments = 6,
arc = Math.PI * 2
) {
radialSegments = Math.floor(radialSegments);
tubularSegments = Math.floor(tubularSegments);
// buffers
const indices = [];
const vertices = [];
const normals = [];
const uvs = [];
// helper variables
const center = new Vector3();
const vertex = new Vector3();
const normal = new Vector3();
let j, i;
// generate vertices, normals and uvs
for (j = 0; j <= radialSegments; j++) {
for (i = 0; i <= tubularSegments; i++) {
var u = i / tubularSegments * arc;
var v = j / radialSegments * Math.PI * 2;
// vertex
vertex.x = (radius + tube * Math.cos(v)) * Math.cos(u);
vertex.y = (radius + tube * Math.cos(v)) * Math.sin(u);
vertex.z = tube * Math.sin(v);
vertices.push(vertex.x, vertex.y, vertex.z);
// normal
center.x = radius * Math.cos(u);
center.y = radius * Math.sin(u);
normal.subVectors(vertex, center).normalize();
normals.push(normal.x, normal.y, normal.z);
// uv
uvs.push(i / tubularSegments);
uvs.push(1 - j / radialSegments);
}
}
// generate indices
for (j = 1; j <= radialSegments; j++) {
for (i = 1; i <= tubularSegments; i++) {
// indices
const a = (tubularSegments + 1) * j + i - 1;
const b = (tubularSegments + 1) * (j - 1) + i - 1;
const c = (tubularSegments + 1) * (j - 1) + i;
const d = (tubularSegments + 1) * j + i;
// faces
indices.push(a, b, d);
indices.push(b, c, d);
}
}
super(vertices, indices, normals, null, uvs);
}
}
......@@ -5,4 +5,10 @@ export * from "./BoxGeometry"
export * from "./PlaneGeometry"
export * from "./CircleGeometry"
\ No newline at end of file
export * from "./CircleGeometry"
export * from "./CylinderGeometry"
export * from "./RingGeometry"
export * from "./TorusGeometry"
\ No newline at end of file
......@@ -2,6 +2,7 @@
import { Object3D } from '../Object3D';
import { Light } from './Light';
import { Vector3 } from '../math/Vector3';
import { DirectionalLightShadow } from './DirectionalLightShadow';
......@@ -21,6 +22,8 @@ export class DirectionalLight extends Light {
this.updateLocalMatrix();
//目标默认一个,算方向用
this.target = new Object3D();
this.shadow = new DirectionalLightShadow();
}
copy(directionalLight: DirectionalLight) {
super.copy(directionalLight);
......
import { OrthographicCamera } from "../cameras/OrthographicCamera";
import { LightShadow } from "./LightShadow";
export class DirectionalLightShadow extends LightShadow {
constructor() {
super(new OrthographicCamera(- 5, 5, 5, - 5, 0.5, 500))
}
clone() {
return new DirectionalLightShadow().copy(this);
}
}
\ No newline at end of file
import { Object3D } from "../Object3D";
import { Vector3 } from "../math/Vector3";
import { rgb2hex, hex2rgb } from "../../2d/utils";
import { LightShadow } from "./LightShadow";
/**
* 光源基类,只有颜色和光源强度
......@@ -29,7 +30,10 @@ export class Light extends Object3D {
return this._colorVec3;
}
/**
* 阴影。为了阴影贴图
*/
shadow: LightShadow
/**
*
* @param color rgb三分量的矢量,每个分量0到1,颜色方面后续优化
......@@ -47,6 +51,7 @@ export class Light extends Object3D {
super.copy(light);
this.color = light.color;
this.intensity = light.intensity;
this.shadow = light.shadow.clone();
return this
}
}
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment