const m4 = twgl.m4;
const gl = document.querySelector("canvas").getContext("webgl");
const ext = gl.getExtension("OES_standard_derivatives");
const vs = `
attribute vec4 position;
uniform mat4 u_worldViewProjection;
varying vec3 v_position;
void main() {
gl_Position = u_worldViewProjection * position;
v_position = position.xyz; // for fake lighting
}
`;
const fs = `
#extension GL_OES_standard_derivatives : enable
precision mediump float;
varying vec3 v_position;
uniform vec4 u_color;
void main() {
vec3 fdx = dFdx(v_position);
vec3 fdy = dFdy(v_position);
vec3 n = normalize(cross(fdx,fdy));
float l = dot(n, normalize(vec3(1,2,-3))) * .5 + .5;
gl_FragColor = u_color;
gl_FragColor.rgb *= l;
}
`;
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
const arrays = {
position: [
-1, 1, -1,
1, 1, -1,
1, -1, -1,
-1, -1, -1,
-1, 1, 1,
1, 1, 1,
1, -1, 1,
-1, -1, 1,
],
indices: [
0, 1, 1, 2, 2, 3, 3, 0,
4, 5, 5, 6, 6, 7, 7, 4,
0, 4, 1, 5, 2, 6, 3, 7,
],
};
const concat = twgl.primitives.concatVertices;
const reorient = twgl.primitives.reorientVertices;
const wireCubeBufferInfo = twgl.createBufferInfoFromArrays(gl, arrays);
const solidCubeBufferInfo = twgl.primitives.createCubeBufferInfo(gl, 2);
const cameraBufferInfo = twgl.createBufferInfoFromArrays(gl,
concat([
reorient(twgl.primitives.createCubeVertices(2),
m4.translation([0, 0, 1])),
reorient(twgl.primitives.createTruncatedConeVertices(0, 1, 2, 12, 1),
m4.rotationX(Math.PI * -.5)),
])
);
const black = [0, 0, 0, 1];
const blue = [0, 0, 1, 1];
function drawScene(viewProjection, clearColor) {
gl.clearColor(...clearColor);
gl.clear(gl.COLOR_BUFFER_BIT);
const numCubes = 10;
for (let i = 0; i < numCubes; ++i) {
const u = i/numCubes;
let mat = m4.rotationY(u * Math.PI * 2);
mat = m4.translate(mat, [0, 0, 10]);
mat = m4.scale(mat, [1, 1 + u * 23 % 1, 1]);
mat = m4.translate(mat, [0, .5, 0]);
mat = m4.multiply(viewProjection, mat);
drawModel(solidCubeBufferInfo, mat, [u, u * 3 % 1, u * 7 % 1,1]);
}
}
function drawModel(bufferInfo, worldViewProjection, color, mode) {
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
twgl.setUniforms(programInfo, {
u_worldViewProjection: worldViewProjection,
u_color: color,
});
twgl.drawBufferInfo(gl, bufferInfo, mode);
}
function render(time) {
time *= 0.001;
twgl.resizeCanvasToDisplaySize(gl.canvas);
const width = gl.canvas.width;
const height = gl.canvas.height;
const halfWidth = width/2;
gl.viewport(0, 0, width, height);
gl.disable(gl.SCISSOR_TEST);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.enable(gl.DEPTH_TEST);
let projectionToViewWith; // the projection on the right
{
const fov = 60 * Math.PI/180;
const aspect = gl.canvas.clientWidth/2/gl.canvas.clientHeight;
const zNear = 0.5;
const zFar = 100;
projectionToViewWith = m4.perspective(fov, aspect, zNear, zFar);
}
let projectionToBeViewed; // the projeciton on the left
{
const fov = 60 * Math.PI/180;
const aspect = gl.canvas.clientWidth/2/gl.canvas.clientHeight;
const zNear = 1.5;
const zFar = 15;
projectionToBeViewed = m4.perspective(fov, aspect, zNear, zFar);
}
const inverseProjectionToBeViewed = m4.inverse(projectionToBeViewed);
let cameraViewingScene; // camera for right view
{
const t1 = 0;
const radius = 30;
const eye = [Math.sin(t1) * radius, 4, Math.cos(t1) * radius];
const target = [0, 0, 0];
const up = [0, 1, 0];
cameraViewingScene = m4.lookAt(eye, target, up);
}
let cameraInScene; // camera for left view
{
const t1 = time;
const t2 = time + .4;
const r1 = 10 + Math.sin(t1);
const r2 = 10 + Math.sin(t2) * 2;
const eye = [Math.sin(t1) * r1, 0 + Math.sin(t1) * 4, Math.cos(t1) * r1];
const target = [Math.sin(t2) * r2, 1 + Math.sin(t2), Math.cos(t2) * r2];
const up = [0, 1, 0];
cameraInScene = m4.lookAt(eye, target, up);
}
// there's only one shader program so just set it once
gl.useProgram(programInfo.program);
// draw only on left half of canvas
gl.enable(gl.SCISSOR_TEST);
gl.scissor(0, 0, halfWidth, height);
gl.viewport(0, 0, halfWidth, height);
// draw the scene on the left using the camera inside the scene
{
const view = m4.inverse(cameraInScene);
const viewProjection = m4.multiply(projectionToBeViewed, view);
drawScene(viewProjection, [.9, 1, .9, 1]);
}
// draw only on right half of canvas
gl.scissor(halfWidth, 0, halfWidth, height);
gl.viewport(halfWidth, 0, halfWidth, height);
// draw the same scene on the right using the camera outside the scene
{
const view = m4.inverse(cameraViewingScene);
const viewProjection = m4.multiply(projectionToViewWith, view);
drawScene(viewProjection, [.9, 1, 1, 1]);
// draw the in scene camera's frustum
{
const world = m4.multiply(cameraInScene, inverseProjectionToBeViewed);
const worldViewProjection = m4.multiply(viewProjection, world);
drawModel(wireCubeBufferInfo, worldViewProjection, black, gl.LINES);
}
// draw the in scene camera's camera model
{
const worldViewProjection = m4.multiply(viewProjection, cameraInScene);
drawModel(cameraBufferInfo, worldViewProjection, blue);
}
}
requestAnimationFrame(render);
}
requestAnimationFrame(render);
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
<canvas></canvas>
うわーで追加する必要がある場所を示すために移動できるようにするには、どうもありがとうございました。それは実際には概念的に簡単です。 私はそれを実装しようとしましたが、私はいくつかの問題を考えています。私は2つのキャンバスを持っています。私はキャンバスに描画したいキャンバスのカメラの錐台です。私は次のことを試しました(私が間違っていれば私を修正してください): あなたが言ったように私は標準のキューブモデルを作成しました。次に、そのモデルの各点Vについて、I *にcanvasBのV * InverseProjectionMatrixを掛けます。それは私にcanvasBのビューボリュームの限界に対応する新しいポイントV "を与えます。私は今すべての正しい点を得て、私はそれらを頂点バッファに送ることができます。これは私に平行六面体のオブジェクトを与えました。 – alejandromumo
あなたはWで割りましたか? 'temp = V * inverseProjectionMatrix; newV = temp.xyz/temp.w' – gman
それは働いた!私は間違った順序で倍増していた。私は十分にあなたに感謝することはできません。 Btwちょっと面白いコメント、私はwebglのチュートリアルに従っています、そして、彼らは金です。 Tyvm! – alejandromumo