Simplify camera api (#140)

* wip: use camera.projection instead of different camera instances

Avoid switch camera projection needs to recreate the instance

* update examples

* release 2.0.0-alpha.35
This commit is contained in:
Yi Shen 2023-11-20 18:15:23 +08:00 committed by GitHub
parent f875a29f33
commit 4fd2569e7b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
70 changed files with 387 additions and 459 deletions

View File

@ -1,6 +1,5 @@
import {
Renderer,
PerspectiveCamera,
Scene,
loadGLTF,
OrbitControl,
@ -11,13 +10,14 @@ import {
AmbientLight,
StandardMaterial,
Skybox,
startTimeline
startTimeline,
Camera
} from 'claygl';
const renderer = new Renderer({
canvas: document.getElementById('main') as HTMLCanvasElement
});
renderer.resize(window.innerWidth, window.innerHeight);
const camera = new PerspectiveCamera({
const camera = new Camera('perspective', {
aspect: renderer.getViewportAspect()
});
camera.position.set(0, 0, 6);

View File

@ -1,7 +1,6 @@
import {
Renderer,
Scene,
PerspectiveCamera,
createUnlitShader,
Material,
Texture2D,
@ -10,7 +9,8 @@ import {
PlaneGeometry,
Mesh,
startTimeline,
constants
constants,
Camera
} from 'claygl';
const renderer = new Renderer({
@ -19,7 +19,7 @@ const renderer = new Renderer({
renderer.resize(window.innerWidth, window.innerHeight);
const scene = new Scene();
const camera = new PerspectiveCamera({
const camera = new Camera('perspective', {
aspect: renderer.getViewportAspect(),
far: 500
});

View File

@ -1,4 +1,4 @@
import { App3D, OrbitControl, PerspectiveCamera } from 'claygl';
import { App3D, Camera, OrbitControl } from 'claygl';
const app = new App3D('#main', {
lazyInit: true,
@ -8,7 +8,7 @@ const app = new App3D('#main', {
}
});
let camera: PerspectiveCamera;
let camera: Camera;
let control: OrbitControl;
app.init(() => {
// Create camera

View File

@ -7,7 +7,7 @@ const app = new App3D('#main', {
});
// Create camera
const camera = app.createCamera([100, 300, 800], [0, 100, 0]);
camera.far = 10000;
camera.projection.far = 10000;
// Load boombox model.
app.loadModel('./assets/models/SambaDancing/SambaDancing.gltf').then(function (result) {

View File

@ -1,4 +1,4 @@
import { App3D, PerspectiveCamera, OrbitControl } from 'claygl';
import { App3D, Camera, OrbitControl } from 'claygl';
const app = new App3D('#main', {
lazyInit: true,
graphic: {
@ -7,7 +7,7 @@ const app = new App3D('#main', {
}
});
let camera: PerspectiveCamera;
let camera: Camera;
let control: OrbitControl;
app.init(() => {

View File

@ -1,6 +1,5 @@
import {
Renderer,
PerspectiveCamera,
Scene,
Mesh,
Compositor,
@ -14,7 +13,8 @@ import {
Skybox,
SceneCompositeNode,
FilterCompositeNode,
createCompositeNodeInput
createCompositeNodeInput,
Camera
} from 'claygl';
import { blendCompositeFragment, composeCompositeFragment } from 'claygl/shaders';
import AlchemyAOCompositeNode from './common/HDComposite/AlchemyAONode';
@ -36,7 +36,7 @@ const renderer = new Renderer({
});
renderer.resize(window.innerWidth, window.innerHeight);
const camera = new PerspectiveCamera({
const camera = new Camera('perspective', {
aspect: renderer.getViewportAspect()
});
camera.position.set(0, 0, 6);

View File

@ -1,7 +1,6 @@
import {
Renderer,
Scene,
PerspectiveCamera,
Material,
createLambertShader,
SceneCompositeNode,
@ -11,7 +10,8 @@ import {
Mesh,
Vector3,
DirectionalLight,
startTimeline
startTimeline,
Camera
} from 'claygl';
import GaussianBlurCompositeNode from './common/HDComposite/GaussianBlurNode';
@ -23,7 +23,7 @@ const renderer = new Renderer({
});
//Create scene
const scene = new Scene();
const camera = new PerspectiveCamera({
const camera = new Camera('perspective', {
aspect: renderer.canvas.width / renderer.canvas.height,
far: 500
});

View File

@ -1,7 +1,6 @@
import {
Renderer,
Scene,
PerspectiveCamera,
Material,
createLambertShader,
Shader,
@ -13,7 +12,8 @@ import {
Mesh,
Vector3,
DirectionalLight,
startTimeline
startTimeline,
Camera
} from 'claygl';
import { colorAdjustCompositeFragment } from '../src/shader/source/compositor/coloradjust.glsl';
@ -25,7 +25,7 @@ const renderer = new Renderer({
});
//Create scene
const scene = new Scene();
const camera = new PerspectiveCamera({
const camera = new Camera('perspective', {
aspect: renderer.canvas.width / renderer.canvas.height,
far: 500
});

View File

@ -1,7 +1,6 @@
import {
Renderer,
Scene,
PerspectiveCamera,
Compositor,
Texture2D,
Mesh,
@ -10,7 +9,8 @@ import {
loadGLTF,
constants,
OrbitControl,
FilterCompositeNode
FilterCompositeNode,
Camera
} from 'claygl';
import GBufferCompositeNode from './common/HDComposite/GBufferNode';
import { outputTextureFragment } from 'claygl/shaders';
@ -22,7 +22,7 @@ const renderer = new Renderer({
});
renderer.resize(window.innerWidth, window.innerHeight);
const camera = new PerspectiveCamera({
const camera = new Camera('perspective', {
aspect: renderer.getViewportAspect()
});
camera.position.set(0, 0, 6);
@ -68,7 +68,7 @@ const control = new OrbitControl({
const availableDebugTypes = ['texture1', 'texture2', 'texture3', 'texture4'] as const;
const config: {
debugType: typeof availableDebugTypes[number];
debugType: (typeof availableDebugTypes)[number];
} = {
debugType: 'texture1'
};

View File

@ -1,7 +1,6 @@
import {
Renderer,
Scene,
PerspectiveCamera,
Compositor,
Texture2D,
Mesh,
@ -14,7 +13,8 @@ import {
SphereGeometry,
PointLight,
FilterCompositeNode,
Skybox
Skybox,
Camera
} from 'claygl';
import LightingCompositeNode from './common/HDComposite/LightingNode';
import { composeCompositeFragment } from 'claygl/shaders';
@ -29,7 +29,7 @@ const renderer = new Renderer({
});
renderer.resize(window.innerWidth, window.innerHeight);
const camera = new PerspectiveCamera({
const camera = new Camera('perspective', {
aspect: renderer.getViewportAspect()
});
camera.position.set(0, 0, 6);

View File

@ -1,7 +1,7 @@
import {
Renderer,
Scene,
PerspectiveCamera,
Camera,
Compositor,
Texture2D,
Mesh,
@ -27,7 +27,7 @@ const renderer = new Renderer({
});
renderer.resize(window.innerWidth, window.innerHeight);
const camera = new PerspectiveCamera({
const camera = new Camera('perspective', {
aspect: renderer.getViewportAspect()
});
camera.position.set(0, 0, 6);

View File

@ -1,7 +1,6 @@
import {
Renderer,
Scene,
PerspectiveCamera,
Compositor,
Mesh,
startTimeline,
@ -13,7 +12,8 @@ import {
AmbientSHLight,
textureUtil,
AmbientCubemapLight,
Skybox
Skybox,
Camera
} from 'claygl';
import { blendCompositeFragment, composeCompositeFragment } from 'claygl/shaders';
import { projectEnvironmentMap } from '../src/util/sh';
@ -26,7 +26,7 @@ const renderer = new Renderer({
});
renderer.resize(window.innerWidth, window.innerHeight);
const camera = new PerspectiveCamera({
const camera = new Camera('perspective', {
aspect: renderer.getViewportAspect()
});
camera.position.set(0, 0, 6);

View File

@ -1,6 +1,5 @@
import {
Renderer,
PerspectiveCamera,
Vector3,
Scene,
PlaneGeometry,
@ -14,7 +13,8 @@ import {
startTimeline,
Compositor,
SceneCompositeNode,
FilterCompositeNode
FilterCompositeNode,
Camera
} from 'claygl';
import { blendCompositeFragment } from 'claygl/shaders';
import GBufferNode from './common/HDComposite/GBufferNode';
@ -38,7 +38,7 @@ const renderer = new Renderer({
canvas: document.getElementById('main') as HTMLCanvasElement,
pixelRatio: 1.0
});
const camera = new PerspectiveCamera({
const camera = new Camera('perspective', {
aspect: renderer.getViewportAspect()
});
camera.position.set(0, 4, 4);
@ -130,7 +130,7 @@ startTimeline((deltaTime) => {
function resize() {
renderer.resize(window.innerWidth, window.innerHeight);
camera.aspect = renderer.getViewportAspect();
camera.projection.aspect = renderer.getViewportAspect();
}
window.onresize = resize;

View File

@ -1,6 +1,5 @@
import {
Renderer,
PerspectiveCamera,
Vector3,
Scene,
PlaneGeometry,
@ -17,7 +16,8 @@ import {
FilterCompositeNode,
Skybox,
textureUtil,
createCompositeNodeInput
createCompositeNodeInput,
Camera
} from 'claygl';
import { blendCompositeFragment, composeCompositeFragment } from 'claygl/shaders';
import GBufferNode from './common/HDComposite/GBufferNode';
@ -42,7 +42,7 @@ const renderer = new Renderer({
canvas: document.getElementById('main') as HTMLCanvasElement,
pixelRatio: 1.0
});
const camera = new PerspectiveCamera({
const camera = new Camera('perspective', {
aspect: renderer.getViewportAspect()
});
camera.position.set(0, 4, 4);
@ -160,7 +160,7 @@ startTimeline((deltaTime) => {
function resize() {
renderer.resize(window.innerWidth, window.innerHeight);
camera.aspect = renderer.getViewportAspect();
camera.projection.aspect = renderer.getViewportAspect();
}
window.onresize = resize;
resize();

View File

@ -1,6 +1,5 @@
import {
Renderer,
PerspectiveCamera,
Vector3,
Scene,
PlaneGeometry,
@ -15,7 +14,8 @@ import {
SceneCompositeNode,
FilterCompositeNode,
SphereGeometry,
createCompositeNodeInput
createCompositeNodeInput,
Camera
} from 'claygl';
import { blendCompositeFragment } from 'claygl/shaders';
import GBufferNode from './common/HDComposite/GBufferNode';
@ -40,7 +40,7 @@ const renderer = new Renderer({
canvas: document.getElementById('main') as HTMLCanvasElement,
pixelRatio: 1.0
});
const camera = new PerspectiveCamera({
const camera = new Camera('perspective', {
aspect: renderer.getViewportAspect()
});
camera.position.set(0, 4, 4);

View File

@ -1,6 +1,5 @@
import {
Renderer,
PerspectiveCamera,
Vector3,
Mesh,
OrbitControl,
@ -11,7 +10,8 @@ import {
loadGLTF,
SpotLight,
AmbientLight,
createCompositeNodeInput
createCompositeNodeInput,
Camera
} from 'claygl';
import { blendCompositeFragment } from 'claygl/shaders';
import GBufferNode from './common/HDComposite/GBufferNode';
@ -38,7 +38,7 @@ const renderer = new Renderer({
canvas: document.getElementById('main') as HTMLCanvasElement,
pixelRatio: 1.0
});
const camera = new PerspectiveCamera({
const camera = new Camera('perspective', {
aspect: renderer.getViewportAspect(),
far: 100
});

View File

@ -1,7 +1,6 @@
import {
Renderer,
Scene,
PerspectiveCamera,
Compositor,
Mesh,
startTimeline,
@ -16,7 +15,8 @@ import {
Skybox,
Node as ClayNode,
color,
createCompositeNodeInput
createCompositeNodeInput,
Camera
} from 'claygl';
import { blendCompositeFragment, composeCompositeFragment } from 'claygl/shaders';
import { projectEnvironmentMap } from '../src/util/sh';
@ -32,7 +32,7 @@ const renderer = new Renderer({
});
renderer.resize(window.innerWidth, window.innerHeight);
const camera = new PerspectiveCamera({
const camera = new Camera('perspective', {
aspect: renderer.getViewportAspect()
});
camera.position.set(0, 0, 6);

View File

@ -1,7 +1,6 @@
import {
CubeGeometry,
Material,
PerspectiveCamera,
Renderer,
Scene,
createStandardShader,
@ -10,7 +9,8 @@ import {
Mesh,
PointLight,
AmbientLight,
startTimeline
startTimeline,
Camera
} from 'claygl';
import Stats from 'stats.js';
@ -21,7 +21,7 @@ const renderer = new Renderer({
});
renderer.resize(window.innerWidth, window.innerHeight);
const scene = new Scene();
const camera = new PerspectiveCamera({
const camera = new Camera('perspective', {
aspect: renderer.getViewportAspect(),
far: 500
});

View File

@ -6,12 +6,12 @@ import {
Mesh,
Scene,
CubeGeometry,
PerspectiveCamera,
ShadowMapPass,
createLambertShader,
Node as ClayNode,
Vector3,
PointLight
PointLight,
Camera
} from 'claygl';
const renderer = new Renderer({
@ -22,7 +22,7 @@ renderer.resize(window.innerWidth, window.innerHeight);
const shadowMapPass = new ShadowMapPass();
const scene = new Scene();
const camera = new PerspectiveCamera({
const camera = new Camera('perspective', {
aspect: renderer.getViewportAspect(),
far: 500
});

View File

@ -3,7 +3,6 @@ import {
Renderer,
DeferredRenderer,
Scene,
PerspectiveCamera,
Mesh,
StandardMaterial,
SphereGeometry,
@ -13,7 +12,8 @@ import {
AmbientLight,
OrbitControl,
DirectionalLight,
startTimeline
startTimeline,
Camera
} from 'claygl';
const renderer = new Renderer({
@ -22,7 +22,7 @@ const renderer = new Renderer({
renderer.resize(window.innerWidth, window.innerHeight);
const deferredRenderer = new DeferredRenderer();
const camera = new PerspectiveCamera({
const camera = new Camera('perspective', {
far: 10000,
aspect: renderer.getViewportAspect()
});

View File

@ -1,7 +1,6 @@
import {
Renderer,
DeferredRenderer,
PerspectiveCamera,
Scene,
loadGLTF,
Mesh,
@ -12,7 +11,8 @@ import {
SphereGeometry,
OrbitControl,
startTimeline,
constants
constants,
Camera
} from 'claygl';
import Stats from 'stats.js';
@ -25,7 +25,7 @@ const renderer = new Renderer({
renderer.resize(window.innerWidth, window.innerHeight);
const deferredRenderer = new DeferredRenderer();
const camera = new PerspectiveCamera({
const camera = new Camera('perspective', {
far: 10000,
aspect: renderer.getViewportAspect()
});

View File

@ -1,6 +1,5 @@
import {
Renderer,
PerspectiveCamera,
DeferredRenderer,
Scene,
loadGLTF,
@ -13,13 +12,14 @@ import {
Mesh,
OrbitControl,
startTimeline,
constants
constants,
Camera
} from 'claygl';
const renderer = new Renderer({
canvas: document.getElementById('main') as HTMLCanvasElement
});
renderer.resize(window.innerWidth, window.innerHeight);
const camera = new PerspectiveCamera({
const camera = new Camera('perspective', {
aspect: renderer.getViewportAspect()
});
camera.position.set(0, 0, 6);
@ -96,5 +96,5 @@ startTimeline((deltaTime) => {
window.onresize = function () {
renderer.resize(window.innerWidth, window.innerHeight);
camera.aspect = renderer.getViewportAspect();
camera.projection.aspect = renderer.getViewportAspect();
};

View File

@ -3,14 +3,14 @@ import {
startTimeline,
ShadowMapPass,
DeferredRenderer,
PerspectiveCamera,
Scene,
Mesh,
StandardMaterial,
CubeGeometry,
SphereGeometry,
OrbitControl,
PointLight
PointLight,
Camera
} from 'claygl';
import Stats from 'stats.js';
@ -25,7 +25,7 @@ renderer.resize(window.innerWidth, window.innerHeight);
const deferredRenderer = new DeferredRenderer();
deferredRenderer.shadowMapPass = shadowMapPass;
const camera = new PerspectiveCamera({
const camera = new Camera('perspective', {
aspect: renderer.getViewportAspect()
});

View File

@ -1,13 +1,13 @@
import {
loadGLTF,
Renderer,
PerspectiveCamera,
ShadowMapPass,
DeferredRenderer,
startTimeline,
OrbitControl,
SpotLight,
PointLight
PointLight,
Camera
} from 'claygl';
const renderer = new Renderer({
@ -21,14 +21,14 @@ deferredRenderer.shadowMapPass = shadowMapPass;
loadGLTF('assets/models/basic_scene/scene.gltf').then((res) => {
const scene = res.scene!;
scene.rotation.rotateX(-Math.PI / 2);
const camera = new PerspectiveCamera({
const camera = new Camera('perspective', {
aspect: renderer.getViewportAspect(),
far: 500
});
camera.position.set(2, 2, 2);
camera.lookAt(scene.position);
camera.aspect = renderer.canvas.width / renderer.canvas.height;
camera.projection.aspect = renderer.canvas.width / renderer.canvas.height;
const control = new OrbitControl({
target: camera,

View File

@ -1,7 +1,6 @@
import {
Renderer,
ShadowMapPass,
PerspectiveCamera,
DeferredRenderer,
Scene,
CubeGeometry,
@ -11,7 +10,8 @@ import {
DirectionalLight,
startTimeline,
Vector3,
OrbitControl
OrbitControl,
Camera
} from 'claygl';
import Stats from 'stats.js';
@ -24,7 +24,7 @@ const shadowMapPass = new ShadowMapPass();
const deferredRenderer = new DeferredRenderer();
deferredRenderer.shadowMapPass = shadowMapPass;
const camera = new PerspectiveCamera({
const camera = new Camera('perspective', {
far: 1000,
aspect: renderer.getViewportAspect()
});

View File

@ -9,7 +9,6 @@ import {
createUnlitShader,
Mesh,
loadGLTF,
PerspectiveCamera,
Vector3,
OrbitControl,
DirectionalLight,
@ -17,7 +16,8 @@ import {
PlaneGeometry,
StandardMaterial,
startTimeline,
constants
constants,
Camera
} from 'claygl';
function createSkeletonDebugScene(skeleton: Skeleton) {
@ -75,14 +75,14 @@ loadGLTF('assets/models/whale/whale-anim.gltf').then((res) => {
const scene = res.scene!;
const skeleton = res.skeletons[0];
const animator = res.animators[0];
const camera = new PerspectiveCamera({
const camera = new Camera('perspective', {
aspect: renderer.getViewportAspect()
});
camera.position.set(0, 10, 30);
camera.lookAt(new Vector3(0, 2, 0));
camera.aspect = renderer.canvas.width / renderer.canvas.height;
camera.projection.aspect = renderer.canvas.width / renderer.canvas.height;
const control = new OrbitControl({
target: camera,

View File

@ -2,7 +2,6 @@ import {
Renderer,
DeferredRenderer,
Scene,
PerspectiveCamera,
Texture2D,
Mesh,
StandardMaterial,
@ -14,7 +13,8 @@ import {
startTimeline,
FullscreenQuadPass,
Shader,
constants
constants,
Camera
} from 'claygl';
import Stats from 'stats.js';
import { outputTextureFragment } from 'claygl/shaders';
@ -26,7 +26,7 @@ const renderer = new Renderer({
renderer.resize(window.innerWidth, window.innerHeight);
const deferredRenderer = new DeferredRenderer();
const camera = new PerspectiveCamera({
const camera = new Camera('perspective', {
far: 5000,
aspect: renderer.getViewportAspect()
});

View File

@ -1,7 +1,6 @@
import {
Renderer,
DeferredRenderer,
PerspectiveCamera,
Texture2D,
Scene,
Mesh,
@ -15,7 +14,8 @@ import {
OrbitControl,
startTimeline,
FullscreenQuadPass,
Shader
Shader,
Camera
} from 'claygl';
import { outputTextureFragment } from 'claygl/shaders';
import Stats from 'stats.js';
@ -27,7 +27,7 @@ const renderer = new Renderer({
renderer.resize(window.innerWidth, window.innerHeight);
const deferredRenderer = new DeferredRenderer();
const camera = new PerspectiveCamera({
const camera = new Camera('perspective', {
far: 10000,
aspect: renderer.getViewportAspect()
});

View File

@ -1,7 +1,5 @@
import {
Renderer,
PerspectiveCamera,
OrthographicCamera,
Material,
CubeGeometry,
PlaneGeometry,
@ -13,7 +11,8 @@ import {
Scene,
createStandardShader,
createUnlitShader,
startTimeline
startTimeline,
Camera
} from 'claygl';
const renderer = new Renderer({
@ -22,7 +21,7 @@ const renderer = new Renderer({
});
//Create scene
const scene = new Scene();
const camera = new PerspectiveCamera({
const camera = new Camera('perspective', {
aspect: renderer.getViewportAspect(),
far: 500
});
@ -56,7 +55,7 @@ rttMesh.material.set('diffuseMap', rtt);
const rttScene = new Scene();
rttScene.add(rttMesh);
const orthCamera = new OrthographicCamera();
const orthCamera = new Camera('orthographic');
startTimeline(() => {
renderer.render(scene, camera, frameBuffer);

View File

@ -1,7 +1,6 @@
import {
Renderer,
DeferredGBuffer,
PerspectiveCamera,
loadGLTF,
startTimeline,
Scene,
@ -9,7 +8,8 @@ import {
Mesh,
StandardMaterial,
Texture2D,
constants
constants,
Camera
} from 'claygl';
import * as dat from 'dat.gui';
@ -19,7 +19,7 @@ const renderer = new Renderer({
const gbuffer = new DeferredGBuffer({
enableTargetTexture4: true
});
const camera = new PerspectiveCamera({
const camera = new Camera('perspective', {
aspect: renderer.getViewportAspect()
});
camera.position.set(0, 0, 6);
@ -82,7 +82,7 @@ function resize() {
renderer.getWidth() * renderer.getPixelRatio(),
renderer.getHeight() * renderer.getPixelRatio()
);
camera.aspect = renderer.getViewportAspect();
camera.projection.aspect = renderer.getViewportAspect();
}
window.onresize = resize;
@ -98,7 +98,7 @@ const availableDebugTypes = [
'velocity'
] as const;
const config: {
debugType: typeof availableDebugTypes[number];
debugType: (typeof availableDebugTypes)[number];
} = {
debugType: 'normal'
};

View File

@ -1,6 +1,5 @@
import {
Renderer,
PerspectiveCamera,
Scene,
Mesh,
Material,
@ -12,7 +11,8 @@ import {
CylinderGeometry,
ParametricSurfaceGeometry,
OrbitControl,
startTimeline
startTimeline,
Camera
} from 'claygl';
const renderer = new Renderer({
@ -20,7 +20,7 @@ const renderer = new Renderer({
});
renderer.resize(window.innerWidth, window.innerHeight);
const scene = new Scene();
const camera = new PerspectiveCamera({
const camera = new Camera('perspective', {
aspect: renderer.getViewportAspect(),
far: 500
});

View File

@ -1,10 +1,10 @@
import {
AmbientLight,
Camera,
EnvironmentMapPass,
loadGLTF,
Mesh,
OrbitControl,
PerspectiveCamera,
Renderer,
ShadowMapPass,
SpotLight,
@ -28,14 +28,14 @@ loadGLTF('assets/models/basic_scene/scene.gltf').then((res) => {
const scene = res.scene!;
scene.rotation.rotateX(-Math.PI / 2);
const camera = new PerspectiveCamera({
const camera = new Camera('perspective', {
aspect: renderer.getViewportAspect(),
far: 100
});
camera.position.set(2, 2, 2);
camera.lookAt(scene.position);
camera.aspect = renderer.canvas.width / renderer.canvas.height;
camera.projection.aspect = renderer.canvas.width / renderer.canvas.height;
const control = new OrbitControl({
target: camera,

View File

@ -2,19 +2,19 @@ import {
Shader,
Renderer,
Scene,
PerspectiveCamera,
SphereGeometry,
Material,
createWireframeShader,
Mesh,
startTimeline
startTimeline,
Camera
} from 'claygl';
const renderer = new Renderer({
canvas: document.getElementById('main') as HTMLCanvasElement
});
const scene = new Scene();
const camera = new PerspectiveCamera({
const camera = new Camera('perspective', {
aspect: renderer.getViewportAspect(),
far: 500
});

View File

@ -2,7 +2,6 @@ import {
Renderer,
Shader,
Scene,
PerspectiveCamera,
Material,
Mesh,
CubeGeometry,
@ -11,7 +10,8 @@ import {
PointLight,
startTimeline,
AmbientLight,
createStandardShader
createStandardShader,
Camera
} from 'claygl';
import Stats from 'stats.js';
@ -21,7 +21,7 @@ const renderer = new Renderer({
});
renderer.resize(window.innerWidth, window.innerHeight);
const scene = new Scene();
const camera = new PerspectiveCamera({
const camera = new Camera('perspective', {
aspect: renderer.getViewportAspect(),
far: 500
});

View File

@ -5,7 +5,7 @@ const app = new App3D('#main');
app.renderer.logDepthBuffer = true;
// Create camera
const camera = app.createCamera([0, 3, 8], [0, 1, 0]);
camera.far = 10;
camera.projection.far = 10;
// Create lights
app.createDirectionalLight([-2, -1, -1], '#fff', 0.7);

View File

@ -3,7 +3,6 @@ import {
Shader,
Renderer,
Scene,
PerspectiveCamera,
Material,
Texture2D,
constants,
@ -15,7 +14,8 @@ import {
Mesh,
Vector3,
Node as ClayNode,
TextureCubeSource
TextureCubeSource,
Camera
} from 'claygl';
const renderer = new Renderer({
@ -25,7 +25,7 @@ const renderer = new Renderer({
renderer.resize(window.innerWidth, window.innerHeight);
const scene = new Scene();
const camera = new PerspectiveCamera({
const camera = new Camera('perspective', {
aspect: renderer.getViewportAspect(),
far: 500
});

View File

@ -1,21 +1,21 @@
import {
Renderer,
Scene,
PerspectiveCamera,
CubeGeometry,
createStandardShader,
Material,
Texture2D,
Mesh,
DirectionalLight,
Vector3
Vector3,
Camera
} from 'claygl';
const renderer = new Renderer({
canvas: document.getElementById('main') as HTMLCanvasElement
});
const scene = new Scene();
const camera = new PerspectiveCamera({
const camera = new Camera('perspective', {
aspect: renderer.getViewportAspect(),
far: 500
});

View File

@ -1,14 +1,14 @@
import {
Renderer,
Scene,
PerspectiveCamera,
CubeGeometry,
createStandardShader,
Material,
Texture2D,
Mesh,
DirectionalLight,
Vector3
Vector3,
Camera
} from 'claygl';
import dat from 'dat.gui';
@ -16,7 +16,7 @@ const renderer = new Renderer({
canvas: document.getElementById('main') as HTMLCanvasElement
});
const scene = new Scene();
const camera = new PerspectiveCamera({
const camera = new Camera('perspective', {
aspect: renderer.getViewportAspect(),
far: 500
});

View File

@ -1,7 +1,6 @@
import {
Renderer,
Scene,
PerspectiveCamera,
PlaneGeometry,
Material,
Texture2D,
@ -11,7 +10,8 @@ import {
ParticleRenderable,
ParticleEmitter,
startTimeline,
PointLight
PointLight,
Camera
} from 'claygl';
const renderer = new Renderer({
@ -39,7 +39,7 @@ particleRenderable.material.set(
);
const scene = new Scene();
const camera = new PerspectiveCamera({
const camera = new Camera('perspective', {
aspect: renderer.getViewportAspect(),
far: 1000,
near: 1

View File

@ -6,8 +6,8 @@ import {
Scene,
Mesh,
Material,
OrthographicCamera,
CubeGeometry
CubeGeometry,
Camera
} from 'claygl';
import Stats from 'stats.js';
@ -25,7 +25,7 @@ document.body.appendChild(stats.dom);
const cubeGeo = new CubeGeometry();
const scene = new Scene();
const camera = new OrthographicCamera({
const camera = new Camera('orthographic', {
left: -width / 2,
right: width / 2,
top: height / 2,

View File

@ -1,6 +1,5 @@
import {
Renderer,
PerspectiveCamera,
Scene,
loadGLTF,
OrbitControl,
@ -9,13 +8,14 @@ import {
DirectionalLight,
Vector3,
createStandardShader,
startTimeline
startTimeline,
Camera
} from 'claygl';
const renderer = new Renderer({
canvas: document.getElementById('main') as HTMLCanvasElement
});
renderer.resize(window.innerWidth, window.innerHeight);
const camera = new PerspectiveCamera({
const camera = new Camera('perspective', {
aspect: renderer.getViewportAspect()
});
camera.position.set(0, 0, 10);

View File

@ -1,6 +1,5 @@
import {
Renderer,
PerspectiveCamera,
Scene,
CubeGeometry,
Material,
@ -11,7 +10,8 @@ import {
startTimeline,
Vector3,
Plane,
pickByRay
pickByRay,
Camera
} from 'claygl';
import ClayNode from '../src/Node';
const renderer = new Renderer({
@ -20,8 +20,8 @@ const renderer = new Renderer({
});
renderer.resize(window.innerWidth, window.innerHeight);
const camera = new PerspectiveCamera();
camera.aspect = renderer.getViewportAspect();
const camera = new Camera('perspective');
camera.projection.aspect = renderer.getViewportAspect();
camera.position.z = 10;
const scene = new Scene();

View File

@ -1,6 +1,5 @@
import {
Renderer,
PerspectiveCamera,
Scene,
Material,
SphereGeometry,
@ -13,7 +12,8 @@ import {
Vector3,
OrbitControl,
loadGLTF,
pickByRay
pickByRay,
Camera
} from 'claygl';
const renderer = new Renderer({
@ -21,8 +21,8 @@ const renderer = new Renderer({
pixelRatio: 1.0
});
renderer.resize(window.innerWidth, window.innerHeight);
const camera = new PerspectiveCamera();
camera.aspect = renderer.getViewportAspect();
const camera = new Camera('perspective');
camera.projection.aspect = renderer.getViewportAspect();
camera.position.z = 3;
const control = new OrbitControl({

View File

@ -1,7 +1,6 @@
import {
Renderer,
ShadowMapPass,
PerspectiveCamera,
CubeGeometry,
Scene,
Mesh,
@ -11,7 +10,8 @@ import {
PointLight,
Vector3,
OrbitControl,
startTimeline
startTimeline,
Camera
} from 'claygl';
import Stats from 'stats.js';
@ -22,7 +22,7 @@ const renderer = new Renderer({
renderer.resize(window.innerWidth, window.innerHeight);
const shadowMapPass = new ShadowMapPass();
const camera = new PerspectiveCamera({
const camera = new Camera('perspective', {
far: 1000,
aspect: renderer.getViewportAspect()
});

View File

@ -4,14 +4,14 @@ import {
loadGLTF,
Mesh,
OrbitControl,
PerspectiveCamera,
Renderer,
ShadowMapPass,
DirectionalLight,
Node as ClayNode,
Timeline,
Scene,
startTimeline
startTimeline,
Camera
} from 'claygl';
import dat from 'dat.gui';
import halton from './common/halton';
@ -37,7 +37,7 @@ loadGLTF('assets/models/basic_scene/scene.gltf', {
const shadowMapPass = new ShadowMapPass();
shadowMapPass.kernelPCF = new Float32Array(pcfKernel);
const camera = new PerspectiveCamera({
const camera = new Camera('perspective', {
aspect: renderer.getViewportAspect(),
far: 100
});

View File

@ -1,7 +1,6 @@
import {
Renderer,
ShadowMapPass,
PerspectiveCamera,
CubeGeometry,
Scene,
Mesh,
@ -10,7 +9,8 @@ import {
SpotLight,
Vector3,
PlaneGeometry,
startTimeline
startTimeline,
Camera
} from 'claygl';
const renderer = new Renderer({
@ -21,7 +21,7 @@ const renderer = new Renderer({
const shadowMapPass = new ShadowMapPass();
const scene = new Scene();
const camera = new PerspectiveCamera({
const camera = new Camera('perspective', {
aspect: renderer.getViewportAspect(),
far: 100
});

View File

@ -1,19 +1,19 @@
import {
Renderer,
PerspectiveCamera,
Scene,
startTimeline,
TextureCube,
Skybox,
OrbitControl,
Vector3
Vector3,
Camera
} from 'claygl';
const renderer = new Renderer({
canvas: document.getElementById('Main') as HTMLCanvasElement
});
const scene = new Scene();
const camera = new PerspectiveCamera({
const camera = new Camera('perspective', {
aspect: renderer.getViewportAspect(),
far: 500
});

View File

@ -1,12 +1,4 @@
import {
Renderer,
PerspectiveCamera,
Scene,
startTimeline,
Texture2D,
Skybox,
OrbitControl
} from 'claygl';
import { Renderer, Scene, startTimeline, Texture2D, Skybox, OrbitControl, Camera } from 'claygl';
const renderer = new Renderer({
canvas: document.getElementById('main') as HTMLCanvasElement
@ -14,7 +6,7 @@ const renderer = new Renderer({
renderer.resize(window.innerWidth, window.innerHeight);
const scene = new Scene();
const camera = new PerspectiveCamera({
const camera = new Camera('perspective', {
aspect: renderer.getViewportAspect(),
far: 500
});

View File

@ -1,6 +1,5 @@
import {
Renderer,
PerspectiveCamera,
SphereGeometry,
Scene,
loadGLTF,
@ -11,7 +10,8 @@ import {
createStandardShader,
AmbientSHLight,
OrbitControl,
startTimeline
startTimeline,
Camera
} from 'claygl';
import { projectEnvironmentMap } from '../src/util/sh';
@ -20,7 +20,7 @@ const renderer = new Renderer({
pixelRatio: 1.0
});
renderer.resize(window.innerWidth, window.innerHeight);
const camera = new PerspectiveCamera({
const camera = new Camera('perspective', {
aspect: renderer.getViewportAspect()
});
camera.position.set(0, 0, 5);

View File

@ -5,11 +5,11 @@ import {
Material,
PlaneGeometry,
Scene,
OrthographicCamera,
Texture2D,
constants,
VertexShader,
glsl
glsl,
Camera
} from 'claygl';
import { outputTextureFragment } from 'claygl/shaders';
@ -57,7 +57,7 @@ function createRect(texture: Texture2D, x: number, y: number, width: number, hei
const renderer = new Renderer({ canvas });
const scene = new Scene();
const camera = new OrthographicCamera();
const camera = new Camera('orthographic');
let x = 0;
let y = 10;

View File

@ -1,12 +1,4 @@
import {
createUnlitShader,
Material,
Mesh,
OrthographicCamera,
Renderer,
Scene,
Geometry
} from 'claygl';
import { createUnlitShader, Material, Mesh, Renderer, Scene, Geometry, Camera } from 'claygl';
const TRIANGLE_POSITIONS = [
[-0.5, -0.5, 0],
@ -25,7 +17,7 @@ const renderer = new Renderer({
height: 400
});
const scene = new Scene();
const camera = new OrthographicCamera();
const camera = new Camera('orthographic');
const geometry = new Geometry({
dynamic: true
});

View File

@ -1,12 +1,4 @@
import {
createUnlitShader,
Material,
Mesh,
OrthographicCamera,
Renderer,
Scene,
Geometry
} from 'claygl';
import { createUnlitShader, Material, Mesh, Renderer, Scene, Geometry, Camera } from 'claygl';
const TRIANGLE_POSITIONS = [
[-0.5, -0.5, 0],
@ -24,7 +16,7 @@ const renderer = new Renderer({
});
renderer.resize(400, 400);
const scene = new Scene();
const camera = new OrthographicCamera();
const camera = new Camera('orthographic');
const geometry = new Geometry();
// Add triangle vertices to position attribute.

View File

@ -2,7 +2,6 @@ import {
Shader,
Renderer,
Scene,
PerspectiveCamera,
CubeGeometry,
Material,
Mesh,
@ -11,7 +10,8 @@ import {
startTimeline,
Compositor,
SceneCompositeNode,
FilterCompositeNode
FilterCompositeNode,
Camera
} from 'claygl';
import { unlitVertex, composeCompositeFragment } from 'claygl/shaders';
import { tronFragment } from './shader/tron.glsl';
@ -25,7 +25,7 @@ const renderer = new Renderer({
});
renderer.resize(window.innerWidth, window.innerHeight);
const scene = new Scene();
const camera = new PerspectiveCamera({
const camera = new Camera('perspective', {
aspect: renderer.getViewportAspect(),
far: 500
});

View File

@ -1,11 +1,11 @@
import {
Renderer,
DeferredGBuffer,
PerspectiveCamera,
Scene,
Mesh,
CubeGeometry,
StandardMaterial
StandardMaterial,
Camera
} from 'claygl';
const renderer = new Renderer({
@ -14,7 +14,7 @@ const renderer = new Renderer({
const gbuffer = new DeferredGBuffer({
enableTargetTexture4: true
});
const camera = new PerspectiveCamera({
const camera = new Camera('perspective', {
aspect: renderer.getViewportAspect()
});
camera.position.set(0, 0, 6);

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{
"name": "claygl-next",
"version": "2.0.0-alpha.34",
"version": "2.0.0-alpha.35",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "claygl-next",
"version": "2.0.0-alpha.34",
"version": "2.0.0-alpha.35",
"dependencies": {
"tslib": "^2.5.0"
},

View File

@ -1,6 +1,6 @@
{
"name": "claygl-next",
"version": "2.0.0-alpha.34",
"version": "2.0.0-alpha.35",
"description": "A 3D graphic library",
"keywords": [
"graphic",

View File

@ -15,8 +15,6 @@ import TextureCube, { CubeTarget, TextureCubeOpts } from './TextureCube';
import Texture, { TextureImageSource } from './Texture';
import Mesh from './Mesh';
import Material, { GeneralMaterialUniformObject, MaterialOpts } from './Material';
import PerspectiveCamera from './camera/Perspective';
import OrthographicCamera from './camera/Orthographic';
import Vector3 from './math/Vector3';
import { GLTFLoadResult, load as loadGLTF } from './loader/GLTF';
import ClayNode from './Node';
@ -373,8 +371,8 @@ class App3D extends Notifier {
if (this._autoUpdateCameraAspect) {
const camera = this._scene.getMainCamera();
if (camera instanceof PerspectiveCamera) {
camera.aspect = this._renderer.getViewportAspect();
if (camera.projection.type === 'perspective') {
camera.projection.aspect = this._renderer.getViewportAspect();
}
}
@ -887,31 +885,25 @@ class App3D extends Notifier {
target: Vector3 | Vector3['array'],
type: 'ortho' | 'orthographic',
extent?: Vector3 | Vector3['array']
): OrthographicCamera;
): Camera<'orthographic'>;
createCamera(
position: Vector3 | Vector3['array'],
target?: Vector3 | Vector3['array'],
type?: 'perspective'
): PerspectiveCamera;
): Camera<'perspective'>;
createCamera(
position: Vector3 | Vector3['array'],
target?: Vector3 | Vector3['array'],
type?: 'ortho' | 'orthographic' | 'perspective',
extent?: Vector3 | Vector3['array']
): PerspectiveCamera | OrthographicCamera {
let CameraCtor;
let isOrtho = false;
if (type === 'ortho' || type === 'orthographic') {
isOrtho = true;
CameraCtor = OrthographicCamera;
} else {
if (type && type !== 'perspective') {
console.error('Unkown camera type ' + type + '. Use default perspective camera');
}
CameraCtor = PerspectiveCamera;
): Camera {
// let CameraCtor;
// let isOrtho = false;
if (type === 'ortho') {
type = 'orthographic';
}
const camera = new CameraCtor();
const camera = new Camera(type);
if (position instanceof Vector3) {
camera.position.copy(position);
} else if (util.isArray(position)) {
@ -925,16 +917,17 @@ class App3D extends Notifier {
camera.lookAt(target);
}
if (extent && isOrtho) {
const projParams = camera.projection;
if (extent && projParams.type === 'orthographic') {
extent = (extent as Vector3).array || extent;
(camera as OrthographicCamera).left = -extent[0] / 2;
(camera as OrthographicCamera).right = extent[0] / 2;
(camera as OrthographicCamera).top = extent[1] / 2;
(camera as OrthographicCamera).bottom = -extent[1] / 2;
(camera as OrthographicCamera).near = 0;
(camera as OrthographicCamera).far = extent[2];
} else {
(camera as PerspectiveCamera).aspect = this._renderer.getViewportAspect();
projParams.left = -extent[0] / 2;
projParams.right = extent[0] / 2;
projParams.top = extent[1] / 2;
projParams.bottom = -extent[1] / 2;
projParams.near = 0;
projParams.far = extent[2];
} else if (projParams.type === 'perspective') {
projParams.aspect = this._renderer.getViewportAspect();
}
this._scene.add(camera);

View File

@ -11,8 +11,47 @@ export interface CameraOpts extends ClayNodeOpts {}
const v4Arr = vec4.create();
interface Camera extends ClayNodeOpts {}
class Camera extends ClayNode {
type CameraProjectionTypes = 'perspective' | 'orthographic';
export class CameraPerspectiveProjection {
type: 'perspective' = 'perspective';
/**
* Vertical field of view in degrees
*/
fov = 50;
/**
* Aspect ratio, typically viewport width / height
*/
aspect = 1;
/**
* Near bound of the frustum
*/
near = 0.1;
/**
* Far bound of the frustum
*/
far = 2000;
}
export class CameraOrthographicProjection {
type: 'orthographic' = 'orthographic';
left = -1;
right = 1;
near = -1;
far = 1;
top = 1;
bottom = -1;
}
type Projections = {
orthographic: CameraOrthographicProjection;
perspective: CameraPerspectiveProjection;
};
class Camera<T extends CameraProjectionTypes = CameraProjectionTypes> extends ClayNode {
/**
* Camera projection
*/
projection: Projections[T];
/**
* Camera projection matrix
*/
@ -36,6 +75,26 @@ class Camera extends ClayNode {
*/
offset = new Vector2();
/**
* @param type Default to be perspective
*/
constructor(type?: T, opts?: Omit<Partial<Projections[T]>, 'type'>) {
super();
// TODO
this.projection = (
type === 'orthographic'
? new CameraOrthographicProjection()
: new CameraPerspectiveProjection()
) as Projections[T];
Object.keys(opts || {}).forEach((key) => {
const val = (opts as any)[key];
if (!isNaN(val)) {
(this.projection as any)[key] = val;
}
});
}
update() {
super.update.call(this);
Matrix4.invert(this.viewMatrix, this.worldTransform);
@ -63,11 +122,6 @@ class Camera extends ClayNode {
this.decomposeWorldTransform();
}
/**
* Decompose camera projection matrix
*/
decomposeProjectionMatrix() {}
/**
* Set camera projection matrix
* @param {clay.Matrix4} projectionMatrix
@ -80,8 +134,44 @@ class Camera extends ClayNode {
/**
* Update projection matrix, called after update
*/
updateProjectionMatrix() {}
updateProjectionMatrix() {
const proj = this.projection;
if (proj.type === 'orthographic') {
this.projectionMatrix.ortho(
proj.left,
proj.right,
proj.bottom,
proj.top,
proj.near,
proj.far
);
} else {
const rad = (proj.fov / 180) * Math.PI;
this.projectionMatrix.perspective(rad, proj.aspect, proj.near, proj.far);
}
}
/**
* Decompose camera projection matrix
*/
decomposeProjectionMatrix() {
const proj = this.projection;
const m = this.projectionMatrix.array;
if (proj.type === 'orthographic') {
proj.left = (-1 - m[12]) / m[0];
proj.right = (1 - m[12]) / m[0];
proj.top = (1 - m[13]) / m[5];
proj.bottom = (-1 - m[13]) / m[5];
proj.near = -(-1 - m[14]) / m[10];
proj.far = -(1 - m[14]) / m[10];
} else {
const rad = Math.atan(1 / m[5]) * 2;
proj.fov = (rad / Math.PI) * 180;
proj.aspect = m[5] / m[0];
proj.near = m[14] / (m[10] - 1);
proj.far = m[14] / (m[10] + 1);
}
}
/**
* Cast a picking ray from camera near plane to far plane
* @function
@ -112,6 +202,15 @@ class Camera extends ClayNode {
return ray;
}
clone() {
const camera = super.clone.call(this);
camera.projection = {
...this.projection
};
return camera;
}
}
export default Camera;

View File

@ -24,7 +24,6 @@ import { Color, GLEnum } from './core/type';
import { assign, genGUID, optional, setCanvasSize } from './core/util';
import type Camera from './Camera';
import type ClayNode from './Node';
import type PerspectiveCamera from './camera/Perspective';
import { preZFragment, preZVertex } from './shader/source/prez.glsl';
import GLPipeline, {
ExtendedRenderableObject,
@ -671,14 +670,15 @@ class Renderer extends Notifier {
program.setSemanticUniform(gl, 'VIEWPORT', viewportUniform);
program.setSemanticUniform(gl, 'WINDOW_SIZE', windowSizeUniform);
if (camera) {
program.setSemanticUniform(gl, 'NEAR', (camera as PerspectiveCamera).near);
program.setSemanticUniform(gl, 'FAR', (camera as PerspectiveCamera).far);
const proj = camera.projection;
program.setSemanticUniform(gl, 'NEAR', proj.near);
program.setSemanticUniform(gl, 'FAR', proj.far);
if (logDepthBuffer) {
program.setSemanticUniform(
gl,
'LOG_DEPTH_BUFFER_FC',
2.0 / (Math.log((camera as PerspectiveCamera).far + 1.0) / Math.LN2)
2.0 / (Math.log(proj.far + 1.0) / Math.LN2)
);
}
}
@ -776,7 +776,7 @@ class Renderer extends Notifier {
if (this.logDepthBuffer) {
this._prezMaterial.set(
'logDepthBufFC',
2.0 / (Math.log((camera as PerspectiveCamera).far + 1.0) / Math.LN2)
2.0 / (Math.log(camera.projection.far + 1.0) / Math.LN2)
);
}

View File

@ -2,7 +2,6 @@
import Mesh, { MeshOpts } from './Mesh';
import CubeGeometry from './geometry/Cube';
import Material from './Material';
import PerspectiveCamera from './camera/Perspective';
import type Scene from './Scene';
import type TextureCube from './TextureCube';

View File

@ -1,57 +0,0 @@
import Camera, { CameraOpts } from '../Camera';
import { assign } from '../core/util';
export interface OrthographicCameraOpts extends CameraOpts {
left: number;
right: number;
near: number;
far: number;
top: number;
bottom: number;
}
interface OrthographicCamera extends OrthographicCameraOpts {}
/**
* @constructor clay.camera.Orthographic
* @extends clay.Camera
*/
class OrthographicCamera extends Camera {
left = -1;
right = 1;
near = -1;
far = 1;
top = 1;
bottom = -1;
constructor(opts?: Partial<OrthographicCameraOpts>) {
super(opts);
assign(this, opts || {});
this.update();
}
updateProjectionMatrix() {
this.projectionMatrix.ortho(this.left, this.right, this.bottom, this.top, this.near, this.far);
}
decomposeProjectionMatrix() {
const m = this.projectionMatrix.array;
this.left = (-1 - m[12]) / m[0];
this.right = (1 - m[12]) / m[0];
this.top = (1 - m[13]) / m[5];
this.bottom = (-1 - m[13]) / m[5];
this.near = -(-1 - m[14]) / m[10];
this.far = -(1 - m[14]) / m[10];
}
clone() {
const camera = super.clone.call(this);
camera.left = this.left;
camera.right = this.right;
camera.near = this.near;
camera.far = this.far;
camera.top = this.top;
camera.bottom = this.bottom;
return camera;
}
}
export default OrthographicCamera;

View File

@ -1,62 +0,0 @@
import Camera, { CameraOpts } from '../Camera';
import { assign } from '../core/util';
export interface PerspectiveCameraOpts extends CameraOpts {
/**
* Vertical field of view in degrees
*/
fov: number;
/**
* Aspect ratio, typically viewport width / height
*/
aspect: number;
/**
* Near bound of the frustum
*/
near: number;
/**
* Far bound of the frustum
*/
far: number;
}
interface PerspectiveCamera extends PerspectiveCameraOpts {}
class PerspectiveCamera extends Camera {
fov = 50;
aspect = 1;
near = 0.1;
far = 2000;
constructor(opts?: Partial<PerspectiveCameraOpts>) {
super(opts);
assign(this, opts);
this.update();
}
updateProjectionMatrix() {
const rad = (this.fov / 180) * Math.PI;
this.projectionMatrix.perspective(rad, this.aspect, this.near, this.far);
}
decomposeProjectionMatrix() {
const m = this.projectionMatrix.array;
const rad = Math.atan(1 / m[5]) * 2;
this.fov = (rad / Math.PI) * 180;
this.aspect = m[5] / m[0];
this.near = m[14] / (m[10] - 1);
this.far = m[14] / (m[10] + 1);
}
/**
* @return {clay.camera.Perspective}
*/
clone() {
const camera = super.clone.call(this);
camera.fov = this.fov;
camera.aspect = this.aspect;
camera.near = this.near;
camera.far = this.far;
return camera;
}
}
export default PerspectiveCamera;

View File

@ -1,4 +0,0 @@
import Orthographic from './Orthographic';
import Perspective from './Perspective';
export { Orthographic, Perspective };

View File

@ -46,12 +46,6 @@ export { setCanvasSize };
export * as constants from './core/constants';
// Camera
export {
Perspective as PerspectiveCamera,
Orthographic as OrthographicCamera
} from './camera/index';
// Light
export {
Ambient as AmbientLight,

View File

@ -26,8 +26,6 @@ import type DirectionalLight from '../light/Directional';
import * as mat4 from '../glmatrix/mat4';
import type TextureCube from '../TextureCube';
import type Light from '../Light';
import PerspectiveCamera from '../camera/Perspective';
import OrthographicCamera from '../camera/Orthographic';
import * as constants from '../core/constants';
import { preZFragment, preZVertex } from '../shader/source/prez.glsl';
import { outputFragment } from '../shader/source/compositor/output.glsl';
@ -386,7 +384,7 @@ class DeferredRenderer {
const shadowMapPass = this.shadowMapPass;
if (shadowMapPass && updateShadow) {
this._prepareLightShadow(renderer, scene, camera as PerspectiveCamera | OrthographicCamera);
this._prepareLightShadow(renderer, scene, camera);
}
const clearColor = renderer.clearColor;
@ -610,11 +608,7 @@ class DeferredRenderer {
}
}
private _prepareLightShadow(
renderer: Renderer,
scene: Scene,
camera: PerspectiveCamera | OrthographicCamera
) {
private _prepareLightShadow(renderer: Renderer, scene: Scene, camera: Camera) {
for (let i = 0; i < scene.lights.length; i++) {
const light = scene.lights[i] as DeferredLight;
const volumeMesh = light.volumeMesh || this._volumeMeshMap.get(light)!;
@ -642,7 +636,7 @@ class DeferredRenderer {
private _prepareSingleLightShadow(
renderer: Renderer,
scene: Scene,
camera: PerspectiveCamera | OrthographicCamera,
camera: Camera,
light: DeferredLight,
material?: Material
) {

View File

@ -17,8 +17,6 @@ import { TextureOpts } from '../Texture';
import Texture2D, { Texture2DOpts } from '../Texture2D';
import Skeleton from '../Skeleton';
import Joint from '../Joint';
import PerspectiveCamera from '../camera/Perspective';
import OrthographicCamera from '../camera/Orthographic';
import * as constants from '../core/constants';
import BoundingBox from '../math/BoundingBox';
@ -31,7 +29,7 @@ import Geometry from '../Geometry';
// Import builtin shader
import Shader from '../Shader';
import { createStandardShader } from '../shader/create';
import type Camera from '../Camera';
import Camera from '../Camera';
type GLTFFormat = any;
type GLTFNode = any;
@ -1124,28 +1122,26 @@ function parseMeshes(json: GLTFFormat, lib: ParsedLib, opts: Partial<GLTFLoadOpt
function instanceCamera(json: GLTFFormat, nodeInfo: GLTFNode) {
const cameraInfo = json.cameras[nodeInfo.camera];
const camera = new Camera(cameraInfo.type);
const proj = camera.projection;
camera.name = nodeInfo.name;
if (cameraInfo.type === 'perspective') {
if (proj.type === 'perspective') {
const perspectiveInfo = cameraInfo.perspective || {};
return new PerspectiveCamera({
name: nodeInfo.name,
aspect: perspectiveInfo.aspectRatio,
fov: (perspectiveInfo.yfov / Math.PI) * 180,
far: perspectiveInfo.zfar,
near: perspectiveInfo.znear
});
perspectiveInfo.yfov != null && (proj.fov = (perspectiveInfo.yfov / Math.PI) * 180);
perspectiveInfo.znear != null && (proj.near = perspectiveInfo.znear);
perspectiveInfo.zfar != null && (proj.far = perspectiveInfo.zfar);
perspectiveInfo.aspectRatio != null && (proj.aspect = perspectiveInfo.aspectRatio);
} else {
const orthographicInfo = cameraInfo.orthographic || {};
return new OrthographicCamera({
name: nodeInfo.name,
top: orthographicInfo.ymag,
right: orthographicInfo.xmag,
left: -orthographicInfo.xmag,
bottom: -orthographicInfo.ymag,
near: orthographicInfo.znear,
far: orthographicInfo.zfar
});
orthographicInfo.ymag != null && (proj.top = orthographicInfo.ymag);
orthographicInfo.xmag != null && (proj.right = orthographicInfo.xmag);
orthographicInfo.xmag != null && (proj.left = -orthographicInfo.xmag);
orthographicInfo.ymag != null && (proj.bottom = -orthographicInfo.ymag);
orthographicInfo.znear != null && (proj.near = orthographicInfo.znear);
orthographicInfo.zfar != null && (proj.far = orthographicInfo.zfar);
}
return camera;
}
function parseNodes(json: GLTFFormat, lib: ParsedLib, opts: Partial<GLTFLoadOpts>) {

View File

@ -2,15 +2,14 @@ import Vector2 from '../math/Vector2';
import Vector3 from '../math/Vector3';
import GestureMgr, { PinchEvent } from './GestureMgr';
import vendor from '../core/vendor';
import PerspectiveCamera from '../camera/Perspective';
import Notifier from '../core/Notifier';
import Timeline from '../Timeline';
import ClayNode from '../Node';
import type { vec3 } from '../glmatrix';
import type { AnimationEasing } from '../animation/easing';
import type ProceduralKeyframeAnimator from '../animation/ProceduralKeyframeAnimator';
import OrthographicCamera from '../camera/Orthographic';
import { assign, isArray } from '../core/util';
import Camera, { CameraOrthographicProjection } from '../Camera';
const addEvent = vendor.addEventListener;
const removeEvent = vendor.removeEventListener;
@ -41,7 +40,7 @@ type MouseButtonsWithSpecialKey =
`${ShiftKey}+${MouseButtons}` | MouseButtons;
interface OrbitControlOpts {
target: ClayNode;
target: Camera;
timeline?: Timeline;
domElement: HTMLElement;
@ -149,7 +148,7 @@ class OrbitControl extends Notifier {
disabled = false;
private _autoRotate: boolean = false;
private _target?: ClayNode;
private _target?: Camera;
private _center = new Vector3();
private _orthoSize?: number;
@ -244,11 +243,11 @@ class OrbitControl extends Notifier {
this._rotating = val;
}
get target(): ClayNode | undefined {
get target(): Camera | undefined {
return this._target;
}
set target(val: ClayNode | undefined) {
set target(val: Camera | undefined) {
if (val && val.target) {
this.setCenter(val.target.toArray());
}
@ -549,13 +548,14 @@ class OrbitControl extends Notifier {
// Override the aspect.
const aspect = this.aspect;
if (aspect) {
if (camera instanceof PerspectiveCamera) {
if (aspect && camera) {
const proj = camera.projection;
if (proj.type === 'perspective') {
// TODO may conflict with aspect updating in the App3D
this._needsUpdate ||= Math.abs(aspect - camera.aspect) > 1e-4;
camera.aspect = aspect;
} else if (camera instanceof OrthographicCamera) {
const oldAspect = (camera.right - camera.left) / (camera.top - camera.bottom);
this._needsUpdate ||= Math.abs(aspect - proj.aspect) > 1e-4;
proj.aspect = aspect;
} else {
const oldAspect = (proj.right - proj.left) / (proj.top - proj.bottom);
if (Math.abs(aspect - oldAspect) > 1e-4) {
this._needsUpdate = true;
}
@ -595,7 +595,7 @@ class OrbitControl extends Notifier {
}
_updateDistanceOrSize(deltaTime: number) {
if (!(this.target instanceof PerspectiveCamera)) {
if (this.target?.projection.type === 'orthographic') {
this._setOrthoSize((this._orthoSize as number) + (this._zoomSpeed * deltaTime) / 20);
} else {
this._setDistance(this._distance + (this._zoomSpeed * deltaTime) / 20);
@ -610,14 +610,14 @@ class OrbitControl extends Notifier {
_setOrthoSize(size: number) {
this._orthoSize = Math.max(Math.min(size, this.maxOrthographicSize), this.minOrthographicSize);
const camera = this.target as OrthographicCamera;
const proj = this.target!.projection as CameraOrthographicProjection;
const cameraHeight = this._orthoSize;
// TODO
const cameraWidth = cameraHeight * (this.aspect || 1);
camera.left = -cameraWidth / 2;
camera.right = cameraWidth / 2;
camera.top = cameraHeight / 2;
camera.bottom = -cameraHeight / 2;
proj.left = -cameraWidth / 2;
proj.right = cameraWidth / 2;
proj.top = cameraHeight / 2;
proj.bottom = -cameraHeight / 2;
}
_updatePan(deltaTime: number) {
@ -703,8 +703,9 @@ class OrbitControl extends Notifier {
this.setAlpha(this.getAlpha());
this._setDistance(this.target.position.dist(this._center));
if (this.target instanceof OrthographicCamera) {
this._setOrthoSize(this.target.top - this.target.bottom);
const proj = this.target?.projection;
if (proj.type === 'orthographic') {
this._setOrthoSize(proj.top - proj.bottom);
}
}
@ -844,7 +845,8 @@ class OrbitControl extends Notifier {
_zoomHandler(e: WheelEvent, delta: number) {
let speed;
if (this.target instanceof PerspectiveCamera) {
const proj = this.target?.projection;
if (proj && proj.type === 'perspective') {
speed = Math.max(
Math.max(Math.min(this._distance - this.minDistance, this.maxDistance - this._distance)) /
20,

View File

@ -1,5 +1,4 @@
import Vector3 from '../math/Vector3';
import PerspectiveCamera from '../camera/Perspective';
import FrameBuffer from '../FrameBuffer';
import TextureCube, { CubeTarget, cubeTargets } from '../TextureCube';
import * as constants from '../core/constants';
@ -8,6 +7,7 @@ import type ShadowMapPass from './ShadowMap';
import type Renderer from '../Renderer';
import type Scene from '../Scene';
import { assign } from '../core/util';
import Camera from '../Camera';
interface EnvironmentMapPassOpts {
/**
@ -77,16 +77,17 @@ class EnvironmentMapPass {
*/
shadowMapPass?: ShadowMapPass;
private _cameras: Record<CubeTarget, PerspectiveCamera>;
private _cameras: Record<CubeTarget, Camera<'perspective'>>;
private _frameBuffer: FrameBuffer;
constructor(opts?: Partial<EnvironmentMapPassOpts>) {
assign(this, opts);
const cameras = (this._cameras = cubeTargets.reduce((obj, target) => {
obj[target] = new PerspectiveCamera({ fov: 90 });
obj[target] = new Camera();
obj[target].projection.fov = 90;
return obj;
}, {} as Record<CubeTarget, PerspectiveCamera>));
}, {} as Record<CubeTarget, Camera<'perspective'>>));
cameras.px.lookAt(Vector3.POSITIVE_X, Vector3.NEGATIVE_Y);
cameras.nx.lookAt(Vector3.NEGATIVE_X, Vector3.NEGATIVE_Y);
@ -120,9 +121,9 @@ class EnvironmentMapPass {
const camera = this._cameras[target];
Vector3.copy(camera.position, this.position);
camera.far = this.far;
camera.near = this.near;
camera.fov = fov;
camera.projection.far = this.far;
camera.projection.near = this.near;
camera.projection.fov = fov;
if (this.shadowMapPass) {
camera.update();

View File

@ -10,8 +10,6 @@ import FrameBuffer from '../FrameBuffer';
import Texture from '../Texture';
import Texture2D from '../Texture2D';
import TextureCube, { CubeTarget, cubeTargets } from '../TextureCube';
import PerspectiveCamera from '../camera/Perspective';
import OrthoCamera from '../camera/Orthographic';
import TexturePool from '../composite/TexturePool';
import * as mat4 from '../glmatrix/mat4';
import type Renderable from '../Renderable';
@ -112,9 +110,9 @@ class ShadowMapPass extends Notifier {
private _lightsCastShadow: Light[] = [];
private _lightCameras: {
point?: Record<CubeTarget, PerspectiveCamera>;
directional?: OrthoCamera;
spot?: PerspectiveCamera;
point?: Record<CubeTarget, Camera<'perspective'>>;
directional?: Camera<'orthographic'>;
spot?: Camera<'perspective'>;
} = {};
private _lightMaterials: Record<string, Material> = {};
@ -264,7 +262,7 @@ class ShadowMapPass extends Notifier {
this.renderDirectionalLightShadow(
renderer,
scene,
sceneCamera as PerspectiveCamera | OrthoCamera,
sceneCamera,
light,
shadowCascadeClips,
directionalLightMatrices,
@ -378,7 +376,7 @@ class ShadowMapPass extends Notifier {
renderDirectionalLightShadow(
renderer: Renderer,
scene: Scene,
sceneCamera: PerspectiveCamera | OrthoCamera,
sceneCamera: Camera,
light: DirectionalLight,
shadowCascadeClips: number[],
directionalLightMatrices: mat4.Mat4Array[],
@ -407,10 +405,11 @@ class ShadowMapPass extends Notifier {
const boundingBox = scene.getBoundingBox();
scene.viewBoundingBoxLastFrame.copy(boundingBox).applyTransform(sceneCamera.viewMatrix);
}
const proj = sceneCamera.projection;
// Considering moving speed since the bounding box is from last frame
// TODO: add a bias
const clippedFar = Math.min(-scene.viewBoundingBoxLastFrame.min.z, sceneCamera.far);
const clippedNear = Math.max(-scene.viewBoundingBoxLastFrame.max.z, sceneCamera.near);
const clippedFar = Math.min(-scene.viewBoundingBoxLastFrame.min.z, proj.far);
const clippedNear = Math.max(-scene.viewBoundingBoxLastFrame.max.z, proj.near);
const lightCamera = this._getDirectionalLightCamera(light, scene, sceneCamera);
@ -421,10 +420,10 @@ class ShadowMapPass extends Notifier {
mat4.multiply(lvpMat4Arr, lightProjMatrix.array, lightViewMatrix.array);
const clipPlanes = [];
const isPerspective = sceneCamera instanceof PerspectiveCamera;
const isPerspective = proj.type === 'perspective';
const scaleZ = (sceneCamera.near + sceneCamera.far) / (sceneCamera.near - sceneCamera.far);
const offsetZ = (2 * sceneCamera.near * sceneCamera.far) / (sceneCamera.near - sceneCamera.far);
const scaleZ = (proj.near + proj.far) / (proj.near - proj.far);
const offsetZ = (2 * proj.near * proj.far) / (proj.near - proj.far);
for (let i = 0; i <= light.shadowCascade; i++) {
const clog = clippedNear * Math.pow(clippedFar / clippedNear, i / light.shadowCascade);
const cuni = clippedNear + ((clippedFar - clippedNear) * i) / light.shadowCascade;
@ -447,18 +446,18 @@ class ShadowMapPass extends Notifier {
if (isPerspective) {
mat4.perspective(
splitProjMatrix.array,
(sceneCamera.fov / 180) * Math.PI,
sceneCamera.aspect,
(proj.fov / 180) * Math.PI,
proj.aspect,
nearPlane,
farPlane
);
} else {
mat4.ortho(
splitProjMatrix.array,
sceneCamera.left,
sceneCamera.right,
sceneCamera.bottom,
sceneCamera.top,
proj.left,
proj.right,
proj.bottom,
proj.top,
nearPlane,
farPlane
);
@ -713,14 +712,15 @@ class ShadowMapPass extends Notifier {
const lightCameras = this._lightCameras;
if (!lightCameras.point) {
lightCameras.point = cubeTargets.reduce((obj, target) => {
obj[target] = new PerspectiveCamera();
obj[target] = new Camera('perspective');
return obj;
}, {} as Record<CubeTarget, PerspectiveCamera>);
}, {} as Record<CubeTarget, Camera<'perspective'>>);
}
const camera = lightCameras.point[target];
const proj = camera.projection;
camera.far = light.range;
camera.fov = 90;
proj.far = light.range;
proj.fov = 90;
camera.position.set(0, 0, 0);
switch (target) {
case 'px':
@ -750,13 +750,9 @@ class ShadowMapPass extends Notifier {
// Camera of directional light will be adjusted
// to contain the view frustum and scene bounding box as tightly as possible
_getDirectionalLightCamera(
light: DirectionalLight,
scene: Scene,
sceneCamera: PerspectiveCamera | OrthoCamera
) {
_getDirectionalLightCamera(light: DirectionalLight, scene: Scene, sceneCamera: Camera) {
if (!this._lightCameras.directional) {
this._lightCameras.directional = new OrthoCamera();
this._lightCameras.directional = new Camera('orthographic');
}
const camera = this._lightCameras.directional;
@ -793,19 +789,20 @@ class ShadowMapPass extends Notifier {
camera.position
.set((min.x + max.x) / 2, (min.y + max.y) / 2, max.z + nearDistance)
.transformMat4(camera.worldTransform);
camera.near = 0;
camera.far = max.z - min.z + nearDistance;
const proj = camera.projection;
proj.near = 0;
proj.far = max.z - min.z + nearDistance;
// Make sure receivers not in the frustum will stil receive the shadow.
if (isNaN(+this.lightFrustumBias)) {
camera.far *= 4;
proj.far *= 4;
} else {
camera.far += +this.lightFrustumBias;
proj.far += +this.lightFrustumBias;
}
// PENDING
camera.left = min.x - PCSSLightSize;
camera.right = max.x + PCSSLightSize;
camera.top = max.y + PCSSLightSize;
camera.bottom = min.y - PCSSLightSize;
proj.left = min.x - PCSSLightSize;
proj.right = max.x + PCSSLightSize;
proj.top = max.y + PCSSLightSize;
proj.bottom = min.y - PCSSLightSize;
camera.update();
return camera;
@ -813,12 +810,13 @@ class ShadowMapPass extends Notifier {
_getSpotLightCamera(light: SpotLight) {
if (!this._lightCameras.spot) {
this._lightCameras.spot = new PerspectiveCamera();
this._lightCameras.spot = new Camera('perspective');
}
const camera = this._lightCameras.spot;
const proj = camera.projection;
// Update properties
camera.fov = light.penumbraAngle * 2;
camera.far = light.range;
proj.fov = light.penumbraAngle * 2;
proj.far = light.range;
camera.worldTransform.copy(light.worldTransform);
camera.updateProjectionMatrix();
mat4.invert(camera.viewMatrix.array, camera.worldTransform.array);

View File

@ -9,12 +9,12 @@ import Mesh from '../Mesh';
import Material from '../Material';
import Geometry from '../Geometry';
import Shader from '../Shader';
import PerspectiveCamera from '../camera/Perspective';
import { Color } from '../core/type';
import type Renderer from '../Renderer';
import type Texture2D from '../Texture2D';
import { VRDistorterFragment, VRDistorterVertex } from './distorter';
import Camera from '../Camera';
function lerp(a: number, b: number, t: number) {
return a * (1 - t) + b * t;
@ -24,7 +24,7 @@ class CardboardDistorter {
clearColor: Color = [0, 0, 0, 1];
private _mesh: Mesh;
private _fakeCamera = new PerspectiveCamera();
private _fakeCamera = new Camera('perspective');
constructor() {
this._mesh = new Mesh(
new Geometry({