Implement classic renderer
This commit is contained in:
parent
3efb691601
commit
e188fc83bd
@ -1,7 +1,7 @@
|
||||
import { BasicsShader } from "./BasicShader";
|
||||
import { DisplayObject } from "./DisplayObject";
|
||||
|
||||
class Axis extends DisplayObject{
|
||||
class Axis extends DisplayObject<BasicsShader>{
|
||||
|
||||
/**
|
||||
* 坐标轴数据
|
||||
@ -24,6 +24,10 @@ class Axis extends DisplayObject{
|
||||
this.gl.bufferData(this.gl.ARRAY_BUFFER, Axis.AXIS_VER_DATA, this.gl.STATIC_DRAW);
|
||||
}
|
||||
|
||||
public clean(): void {
|
||||
this.gl.deleteBuffer(this.axisVertexBuffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* 绘制半径
|
||||
*/
|
||||
@ -34,39 +38,39 @@ class Axis extends DisplayObject{
|
||||
/**
|
||||
* 绘制坐标轴
|
||||
*/
|
||||
public draw(shader: BasicsShader){
|
||||
public draw(){
|
||||
|
||||
// 使用程序
|
||||
shader.use();
|
||||
this.shader.use();
|
||||
|
||||
// 绑定缓冲区
|
||||
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.axisVertexBuffer);
|
||||
|
||||
// 指定指针数据
|
||||
this.gl.vertexAttribPointer(
|
||||
shader.attribLocate("aPosition"),
|
||||
this.shader.attribLocate("aPosition"),
|
||||
3, this.gl.FLOAT, false, 0, 0);
|
||||
|
||||
// mvp参数传递
|
||||
shader.mvp(this.camera.transformMat);
|
||||
this.shader.mvp(this.camera.transformMat);
|
||||
|
||||
// 半径传递
|
||||
shader.radius([this.r, this.r, this.r]);
|
||||
shader.position(this.pos);
|
||||
this.shader.radius([this.r, this.r, this.r]);
|
||||
this.shader.position(this.pos);
|
||||
|
||||
shader.fogColor(this.renderer.fogColor);
|
||||
shader.fogDensity(this.renderer.fogDensity);
|
||||
this.shader.fogColor(this.renderer.fogColor);
|
||||
this.shader.fogDensity(this.renderer.fogDensity);
|
||||
|
||||
// 绘制 X 轴
|
||||
shader.color([1, 0, 0]);
|
||||
this.shader.color([1, 0, 0]);
|
||||
this.gl.drawArrays(this.gl.LINES, 0, 2);
|
||||
|
||||
// 绘制 Y 轴
|
||||
shader.color([0, 1, 0]);
|
||||
this.shader.color([0, 1, 0]);
|
||||
this.gl.drawArrays(this.gl.LINES, 2, 2);
|
||||
|
||||
// 绘制 Z 轴
|
||||
shader.color([0, 0, 1]);
|
||||
this.shader.color([0, 0, 1]);
|
||||
this.gl.drawArrays(this.gl.LINES, 4, 2);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { DisplayObject } from "./DisplayObject";
|
||||
import { BasicsShader } from "./BasicShader";
|
||||
|
||||
class BaseCube extends DisplayObject{
|
||||
class BasicCube extends DisplayObject<BasicsShader>{
|
||||
|
||||
/**
|
||||
* 立方体数据
|
||||
@ -28,10 +28,15 @@ class BaseCube extends DisplayObject{
|
||||
|
||||
// 绑定缓冲区
|
||||
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.cubeVertexBuffer);
|
||||
this.gl.bufferData(this.gl.ARRAY_BUFFER, BaseCube.CUBE_VER_DATA, this.gl.STATIC_DRAW);
|
||||
this.gl.bufferData(this.gl.ARRAY_BUFFER, BasicCube.CUBE_VER_DATA, this.gl.STATIC_DRAW);
|
||||
|
||||
this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, this.cubeElementBuffer);
|
||||
this.gl.bufferData(this.gl.ELEMENT_ARRAY_BUFFER, BaseCube.CUBE_ELE_DATA, this.gl.STATIC_DRAW);
|
||||
this.gl.bufferData(this.gl.ELEMENT_ARRAY_BUFFER, BasicCube.CUBE_ELE_DATA, this.gl.STATIC_DRAW);
|
||||
}
|
||||
|
||||
public clean(): void {
|
||||
this.gl.deleteBuffer(this.cubeElementBuffer);
|
||||
this.gl.deleteBuffer(this.cubeVertexBuffer);
|
||||
}
|
||||
|
||||
private cubeVertexBuffer: WebGLBuffer | null = null;
|
||||
@ -40,7 +45,7 @@ class BaseCube extends DisplayObject{
|
||||
/**
|
||||
* 绘制半径
|
||||
*/
|
||||
private r:[number,number,number] = [1, 1, 1];
|
||||
public r:[number,number,number] = [1, 1, 1];
|
||||
|
||||
/**
|
||||
* 坐标
|
||||
@ -55,10 +60,10 @@ class BaseCube extends DisplayObject{
|
||||
/**
|
||||
* 绘制立方体
|
||||
*/
|
||||
public draw(shader: BasicsShader){
|
||||
public draw(){
|
||||
|
||||
// 使用程序
|
||||
shader.use();
|
||||
this.shader.use();
|
||||
|
||||
// 绑定缓冲区
|
||||
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.cubeVertexBuffer);
|
||||
@ -66,26 +71,32 @@ class BaseCube extends DisplayObject{
|
||||
|
||||
// 指定指针数据
|
||||
this.gl.vertexAttribPointer(
|
||||
shader.attribLocate("aPosition"),
|
||||
this.shader.attribLocate("aPosition"),
|
||||
3, this.gl.FLOAT, false, 0, 0);
|
||||
|
||||
// mvp参数传递
|
||||
shader.mvp(this.camera.transformMat);
|
||||
this.shader.mvp(this.camera.transformMat);
|
||||
|
||||
// 半径传递
|
||||
shader.radius(this.r);
|
||||
shader.position(this.position);
|
||||
this.shader.radius(this.r);
|
||||
this.shader.position(this.position);
|
||||
|
||||
// 指定颜色
|
||||
shader.color(this.color);
|
||||
this.shader.color(this.color);
|
||||
|
||||
shader.fogColor(this.renderer.fogColor);
|
||||
shader.fogDensity(this.renderer.fogDensity);
|
||||
this.shader.fogColor(this.renderer.fogColor);
|
||||
this.shader.fogDensity(this.renderer.fogDensity);
|
||||
|
||||
// 开始绘制
|
||||
this.gl.drawElements(this.gl.LINES, 24, this.gl.UNSIGNED_SHORT, 0);
|
||||
}
|
||||
|
||||
public isCube: boolean = true;
|
||||
|
||||
public static isCube(object: DisplayObject): object is BasicCube {
|
||||
return !!(object as BasicCube).isCube;
|
||||
}
|
||||
}
|
||||
|
||||
export default BaseCube;
|
||||
export { BaseCube };
|
||||
export default BasicCube;
|
||||
export { BasicCube };
|
@ -2,7 +2,7 @@ import { DisplayObject } from "./DisplayObject";
|
||||
import { GroupShader } from "./GroupShader";
|
||||
import { ObjectData } from "@Model/Renderer";
|
||||
|
||||
class BasicGroup extends DisplayObject{
|
||||
class BasicGroup extends DisplayObject<GroupShader> {
|
||||
|
||||
private pointVertexBuffer: WebGLBuffer | null = null;
|
||||
private pointVecMaxCount: number = 100 * 3;
|
||||
@ -18,6 +18,10 @@ class BasicGroup extends DisplayObject{
|
||||
this.gl.bufferData(this.gl.ARRAY_BUFFER, this.pointVecMaxCount, this.gl.DYNAMIC_DRAW);
|
||||
}
|
||||
|
||||
public clean(): void {
|
||||
this.gl.deleteBuffer(this.pointVertexBuffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* 向 GPU 上传数据
|
||||
*/
|
||||
@ -43,34 +47,40 @@ class BasicGroup extends DisplayObject{
|
||||
/**
|
||||
* 绘制立方体
|
||||
*/
|
||||
public draw(shader: GroupShader){
|
||||
public draw(){
|
||||
|
||||
// 使用程序
|
||||
shader.use();
|
||||
this.shader.use();
|
||||
|
||||
// 绑定缓冲区
|
||||
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.pointVertexBuffer);
|
||||
|
||||
// 指定指针数据
|
||||
this.gl.vertexAttribPointer(
|
||||
shader.attribLocate("aPosition"),
|
||||
this.shader.attribLocate("aPosition"),
|
||||
3, this.gl.FLOAT, false, 0, 0);
|
||||
|
||||
// mvp参数传递
|
||||
shader.mvp(this.camera.transformMat);
|
||||
this.shader.mvp(this.camera.transformMat);
|
||||
|
||||
// 半径传递
|
||||
shader.radius(this.size);
|
||||
this.shader.radius(this.size);
|
||||
|
||||
// 指定颜色
|
||||
shader.color(this.color);
|
||||
this.shader.color(this.color);
|
||||
|
||||
shader.fogColor(this.renderer.fogColor);
|
||||
shader.fogDensity(this.renderer.fogDensity);
|
||||
this.shader.fogColor(this.renderer.fogColor);
|
||||
this.shader.fogDensity(this.renderer.fogDensity);
|
||||
|
||||
// 开始绘制
|
||||
this.gl.drawArrays(this.gl.POINTS, 0, this.pointVecCount);
|
||||
}
|
||||
|
||||
public isGroup: boolean = true;
|
||||
|
||||
public static isGroup(object: DisplayObject): object is BasicGroup {
|
||||
return !!(object as BasicGroup).isGroup;
|
||||
}
|
||||
}
|
||||
|
||||
export default BasicGroup;
|
||||
|
@ -2,11 +2,19 @@ import { ObjectID, ObjectData, ICommonParam } from "@Model/Renderer";
|
||||
import { BasicRenderer } from "./BasicRenderer";
|
||||
import { BasicsShader } from "./BasicShader";
|
||||
import { Axis } from "./Axis";
|
||||
import { BaseCube } from "./BasicCube";
|
||||
import { BasicCube } from "./BasicCube";
|
||||
import { GroupShader } from "./GroupShader";
|
||||
import { BasicGroup } from "./BasicGroup";
|
||||
import DisplayObject from "./DisplayObject";
|
||||
|
||||
interface IClassicRendererParams {}
|
||||
interface IClassicRendererParams {
|
||||
point: {
|
||||
size: number;
|
||||
}
|
||||
cube: {
|
||||
radius: number[];
|
||||
}
|
||||
}
|
||||
|
||||
class ClassicRenderer extends BasicRenderer<{}, IClassicRendererParams> {
|
||||
|
||||
@ -22,14 +30,9 @@ class ClassicRenderer extends BasicRenderer<{}, IClassicRendererParams> {
|
||||
private readonly farFogLine = 2.5;
|
||||
|
||||
/**
|
||||
* 点存储池数组
|
||||
* 对象储池数组
|
||||
*/
|
||||
private groupPool = new Map<ObjectID, BasicGroup>();
|
||||
|
||||
/**
|
||||
* 立方体储池数组
|
||||
*/
|
||||
private cubePool = new Map<ObjectID, BaseCube>();
|
||||
private objectPool = new Map<ObjectID, DisplayObject>();
|
||||
|
||||
public onLoad(): void {
|
||||
|
||||
@ -38,19 +41,7 @@ class ClassicRenderer extends BasicRenderer<{}, IClassicRendererParams> {
|
||||
|
||||
this.basicShader = new BasicsShader().bindRenderer(this);
|
||||
this.groupShader = new GroupShader().bindRenderer(this);
|
||||
this.axisObject = new Axis().bindRenderer(this);
|
||||
|
||||
// 测试渲染器
|
||||
if (true) {
|
||||
let cubeObject = new BaseCube().bindRenderer(this);
|
||||
let basicGroup = new BasicGroup().bindRenderer(this);
|
||||
|
||||
// 生成随机数据测试
|
||||
basicGroup.upLoadData(new Array(1000 * 3).fill(0).map(() => (Math.random() - .5) * 2));
|
||||
|
||||
this.cubePool.set("1", cubeObject);
|
||||
this.groupPool.set("1", basicGroup);
|
||||
}
|
||||
this.axisObject = new Axis().bindRenderer(this).bindShader(this.basicShader);
|
||||
|
||||
this.canvas.on("mousemove", () => {
|
||||
|
||||
@ -99,16 +90,35 @@ class ClassicRenderer extends BasicRenderer<{}, IClassicRendererParams> {
|
||||
|
||||
this.cleanCanvas();
|
||||
|
||||
// 绘制全部立方体
|
||||
this.cubePool.forEach((cube) => {
|
||||
if (cube.isDraw) cube.draw(this.basicShader);
|
||||
else cube.drawEmptyFrame ++;
|
||||
// 绘制全部物体
|
||||
// 对象清理实现自动内存释放
|
||||
let cleanArray: undefined | Set<ObjectID>;
|
||||
this.objectPool.forEach((object, key) => {
|
||||
if (object.drawEmptyFrame > this.maxDrawEmptyFrame) {
|
||||
|
||||
// 加入清除列表
|
||||
if (!cleanArray) cleanArray = new Set<string>();
|
||||
cleanArray.add(key);
|
||||
|
||||
// 释放显存
|
||||
object.clean();
|
||||
}
|
||||
});
|
||||
|
||||
// 绘制全部点
|
||||
this.groupPool.forEach((group) => {
|
||||
if (group.isDraw) group.draw(this.groupShader);
|
||||
else group.drawEmptyFrame ++;
|
||||
if (cleanArray) {
|
||||
cleanArray.forEach((key) => {
|
||||
this.objectPool.delete(key);
|
||||
console.log(`Renderer: Automatically clear objects ${key}`);
|
||||
});
|
||||
}
|
||||
|
||||
// 遍历绘制
|
||||
this.objectPool.forEach((object) => {
|
||||
if (object.isDraw) {
|
||||
object.draw();
|
||||
object.drawEmptyFrame = 0;
|
||||
}
|
||||
else object.drawEmptyFrame ++;
|
||||
});
|
||||
|
||||
// 右上角绘制坐标轴
|
||||
@ -119,19 +129,137 @@ class ClassicRenderer extends BasicRenderer<{}, IClassicRendererParams> {
|
||||
position * this.camera.ratio,
|
||||
position
|
||||
);
|
||||
this.axisObject.draw(this.basicShader);
|
||||
this.axisObject.draw();
|
||||
}
|
||||
|
||||
/**
|
||||
* 最大不活动帧数
|
||||
*/
|
||||
private maxDrawEmptyFrame = 5000;
|
||||
|
||||
clean(id?: ObjectID | ObjectID[]): this {
|
||||
throw new Error("Method not implemented.");
|
||||
if (id) {
|
||||
if (Array.isArray(id)) {
|
||||
id.forEach((key) => {
|
||||
let object = this.objectPool.get(key);
|
||||
if (object) object.isDraw = false;
|
||||
});
|
||||
} else {
|
||||
let object = this.objectPool.get(id);
|
||||
if (object) object.isDraw = false;
|
||||
}
|
||||
} else {
|
||||
this.objectPool.forEach((object) => {
|
||||
object.isDraw = false;
|
||||
});
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
points(id: ObjectID, position: ObjectData, param?: ICommonParam): this {
|
||||
throw new Error("Method not implemented.");
|
||||
points(
|
||||
id: ObjectID, position?: ObjectData,
|
||||
param?: Readonly<Partial<ICommonParam & IClassicRendererParams["point"]>>
|
||||
): this {
|
||||
let object = this.objectPool.get(id);
|
||||
let group: BasicGroup;
|
||||
if (object) {
|
||||
if (BasicGroup.isGroup(object)) {
|
||||
group = object;
|
||||
|
||||
// 数据上传
|
||||
if (position) {
|
||||
object.upLoadData(position);
|
||||
}
|
||||
} else {
|
||||
throw new Error("Renderer: Use duplicate ObjectID when drawing different types of objects");
|
||||
}
|
||||
} else {
|
||||
group = new BasicGroup().bindRenderer(this).bindShader(this.groupShader);
|
||||
|
||||
// 数据上传
|
||||
group.upLoadData(position ?? []);
|
||||
|
||||
this.objectPool.set(id, group);
|
||||
console.log(`Renderer: Create new group object with id ${id}`);
|
||||
}
|
||||
|
||||
// 开启绘制
|
||||
group.isDraw = true;
|
||||
|
||||
// 参数传递
|
||||
if (param) {
|
||||
|
||||
// 颜色数据
|
||||
if (param.color) {
|
||||
group.color[0] = param.color[0] ?? group.color[0]
|
||||
group.color[1] = param.color[1] ?? group.color[1]
|
||||
group.color[2] = param.color[2] ?? group.color[2]
|
||||
}
|
||||
|
||||
// 半径数据
|
||||
if (param.size) {
|
||||
group.size = param.size;
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
cube(id: ObjectID, position: ObjectData, param?: ICommonParam): this {
|
||||
throw new Error("Method not implemented.");
|
||||
cube(
|
||||
id: ObjectID, position?: ObjectData,
|
||||
param?: Readonly<Partial<ICommonParam & IClassicRendererParams["cube"]>>
|
||||
): this {
|
||||
let object = this.objectPool.get(id);
|
||||
let cube: BasicCube;
|
||||
if (object) {
|
||||
if (BasicCube.isCube(object)) {
|
||||
cube = object;
|
||||
|
||||
// 坐标数据上传
|
||||
if (position) {
|
||||
cube.position[0] = position[0] ?? cube.position[0];
|
||||
cube.position[1] = position[1] ?? cube.position[1];
|
||||
cube.position[2] = position[2] ?? cube.position[2];
|
||||
}
|
||||
} else {
|
||||
throw new Error("Renderer: Use duplicate ObjectID when drawing different types of objects");
|
||||
}
|
||||
} else {
|
||||
cube = new BasicCube().bindRenderer(this).bindShader(this.basicShader);
|
||||
|
||||
// 数据上传
|
||||
if (position) {
|
||||
cube.position[0] = position[0] ?? cube.position[0];
|
||||
cube.position[1] = position[1] ?? cube.position[1];
|
||||
cube.position[2] = position[2] ?? cube.position[2];
|
||||
}
|
||||
|
||||
this.objectPool.set(id, cube);
|
||||
console.log(`Renderer: Create new cube object with id ${id}`);
|
||||
}
|
||||
|
||||
// 开启绘制
|
||||
cube.isDraw = true;
|
||||
|
||||
// 参数传递
|
||||
if (param) {
|
||||
|
||||
// 颜色数据
|
||||
if (param.color) {
|
||||
cube.color[0] = param.color[0] ?? cube.color[0]
|
||||
cube.color[1] = param.color[1] ?? cube.color[1]
|
||||
cube.color[2] = param.color[2] ?? cube.color[2]
|
||||
}
|
||||
|
||||
// 半径数据
|
||||
if (param.radius) {
|
||||
cube.r[0] = param.radius[0] ?? cube.r[0];
|
||||
cube.r[1] = param.radius[1] ?? cube.r[1];
|
||||
cube.r[2] = param.radius[2] ?? cube.r[2];
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,9 @@
|
||||
import { EventType } from "@Model/Emitter";
|
||||
import { GLContextObject } from "./GLContext";
|
||||
import { GLShader } from "./GLShader";
|
||||
|
||||
abstract class DisplayObject<
|
||||
S extends GLShader = GLShader,
|
||||
E extends Record<EventType, any> = {}
|
||||
> extends GLContextObject<E> {
|
||||
|
||||
@ -14,6 +16,30 @@ abstract class DisplayObject<
|
||||
* 绘制帧数
|
||||
*/
|
||||
public drawEmptyFrame: number = 0;
|
||||
|
||||
/**
|
||||
* 绑定的 shader
|
||||
*/
|
||||
protected shader: S = undefined as any;
|
||||
|
||||
/**
|
||||
* 绑定着色器
|
||||
*/
|
||||
public bindShader(shader: S) {
|
||||
this.shader = shader;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 绘制函数
|
||||
*/
|
||||
abstract draw(): void;
|
||||
|
||||
/**
|
||||
* 销毁时调用
|
||||
* 用于释放显存
|
||||
*/
|
||||
abstract clean(): void;
|
||||
}
|
||||
|
||||
export { DisplayObject }
|
||||
|
@ -30,11 +30,6 @@ interface ICommonParam {
|
||||
* 颜色
|
||||
*/
|
||||
color?: ObjectData;
|
||||
|
||||
/**
|
||||
* 半径
|
||||
*/
|
||||
radius?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -108,7 +103,7 @@ abstract class AbstractRenderer<
|
||||
* @param id 使用的标识符
|
||||
* @param position 做标集合
|
||||
*/
|
||||
abstract points(id: ObjectID, position: ObjectData, param?: P["points"] & ICommonParam): this;
|
||||
abstract points(id: ObjectID, position?: ObjectData, param?: Readonly<P["points"] & ICommonParam>): this;
|
||||
|
||||
/**
|
||||
* @function cube 绘制立方体
|
||||
@ -118,7 +113,7 @@ abstract class AbstractRenderer<
|
||||
*
|
||||
* 注意: 这里的半径指的是立方体重心与立方体任意一面几何中心的距离
|
||||
*/
|
||||
abstract cube(id: ObjectID, position: ObjectData, param?: P["cube"] & ICommonParam): this;
|
||||
abstract cube(id: ObjectID, position?: ObjectData, param?: Readonly<P["cube"] & ICommonParam>): this;
|
||||
}
|
||||
|
||||
export default AbstractRenderer;
|
||||
|
@ -28,7 +28,27 @@ class Laboratory extends Component {
|
||||
|
||||
renderer.onLoad();
|
||||
|
||||
console.log(renderer);
|
||||
// 测试渲染器
|
||||
if (true) {
|
||||
renderer.points("0");
|
||||
renderer.points("1", new Array(100 * 3).fill(0).map(() => (Math.random() - .5) * 2));
|
||||
renderer.points("2", new Array(100 * 3).fill(0).map(() => (Math.random() - .5) * 2), {
|
||||
size: 100,
|
||||
color: [1, 0, 1]
|
||||
});
|
||||
renderer.points("3", new Array(100 * 3).fill(0).map(() => (Math.random() - .5) * 2), {
|
||||
size: 80,
|
||||
color: [0, 1, 1]
|
||||
});
|
||||
renderer.points("2");
|
||||
renderer.cube("4");
|
||||
renderer.cube("5", new Array(3).fill(0).map(() => (Math.random() - .5) * 2), {
|
||||
radius: new Array(3).fill(0).map(() => Math.random() * 1.2),
|
||||
color: [1, 1, 0]
|
||||
})
|
||||
}
|
||||
|
||||
(window as any).renderer = renderer;
|
||||
|
||||
this.canvasContRef.current.appendChild(renderer.canvas.dom);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user