Draw Model
这个实例主要展示了 webgl
基础类型的渲染,以及相机,Mesh,Geometry 的使用,是常规的最简单用例。
一个简单的示例
Result
Loading...
Live Editor
function render(props) { const drawModelVertex = ` attribute vec2 uv; attribute vec3 position; uniform mat4 modelViewMatrix; uniform mat4 projectionMatrix; varying vec2 vUv; void main() { vUv = uv; gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); // gl_PointSize only applicable for gl.POINTS draw mode gl_PointSize = 5.0; } `; const drawModelFragment = ` precision highp float; uniform float uTime; varying vec2 vUv; void main() { gl_FragColor.rgb = 0.5 + 0.3 * sin(vUv.yxx + uTime) + vec3(0.2, 0.0, 0.1); gl_FragColor.a = 1.0; } `; const refDom = useRef(null); const store = leva.useCreateStore(); const { name, aNumber } = leva.useControls({ name: 'World1', aNumber: 2 }, { store }); const init = () => { const canvas = refDom.current; canvas.width = canvas.clientWidth; canvas.height = canvas.clientHeight; const renderer = new Renderer(canvas, { alpha: true, }); const fov = 15; const nearZ = 0.1; const farZ = 100; const camera = new PerspectiveCamera(fov, canvas.width / canvas.height, nearZ, farZ); camera.position.z = 15; function resize(target) { const { width, height } = target.getBoundingClientRect(); renderer.setSize(width, height); camera.aspect = width / height; } const scene = new Scene(); const geometry = new Geometry(renderer, { position: { size: 3, data: new Float32Array([ -0.5, 0.5, 0, -0.5, -0.5, 0, 0.5, 0.5, 0, 0.5, -0.5, 0 ]) }, uv: { size: 2, data: new Float32Array([0, 1, 1, 1, 0, 0, 1, 0]) }, index: { data: new Uint16Array([0, 1, 2, 1, 3, 2]) }, }); const program = new Program(renderer, { vertexShader: drawModelVertex, fragmentShader: drawModelFragment, uniforms: { uTime: { value: 0 }, }, }); const points = new Mesh(renderer, { mode: renderer.gl.POINTS, geometry, program }); points.setParent(scene); points.position.set(-1, 1, 0); const lineStrip = new Mesh(renderer, { mode: renderer.gl.LINES, geometry, program }); lineStrip.setParent(scene); lineStrip.position.set(1, 1, 0); const lineLoop = new Mesh(renderer, { mode: renderer.gl.LINE_LOOP, geometry, program }); lineLoop.setParent(scene); lineLoop.position.set(-1, -1, 0); const triangles = new Mesh(renderer, { mode: renderer.gl.TRIANGLES, geometry, program }); triangles.setParent(scene); triangles.position.set(1, -1, 0); const raf = new Raf((t) => { program.setUniform('uTime', t); renderer.render({ scene, camera }); }); return { canvas, resize, } } useEffect(() => { const { canvas, resize } = init(); observe(canvas, resize); return () => { unobserve(canvas, resize); }; }, []); return ( <div className="live-wrap"> <div className="leva-wrap"> <Leva fill ></Leva> <LevaPanel store={store} fill></LevaPanel> </div> <canvas className="scene-canvas" ref={refDom}></canvas> </div> ); }
- React Components
import React, { useRef, useEffect } from 'react';
import { useControls, Leva, useCreateStore, LevaPanel } from 'leva';
import vertex from 'raw-loader!glslify-loader!./shaders/draw-modes.vert.glsl';
import fragment from 'raw-loader!glslify-loader!./shaders/draw-modes.frag.glsl';
import { observe, unobserve } from '../utils/observer';
import { Renderer, Mesh, Raf, Scene, Program, PerspectiveCamera, Geometry } from '@sakitam-gis/vis-engine';
export default function DrawModel(props) {
const refDom = useRef(null);
const cameraRef = useRef(null);
const pointRef = useRef(null);
const lineStripRef = useRef(null);
const lineLoopRef = useRef(null);
const trianglesRef = useRef(null);
const store = useCreateStore();
useControls({
fov: {
value: 15,
min: -50,
max: 50,
step: 1,
onChange: (fov) => {
if (cameraRef.current) {
cameraRef.current.fov = fov;
}
},
},
nearZ: {
value: 0.1,
min: -50,
max: 50,
step: 0.1,
onChange: (nearZ) => {
if (cameraRef.current) {
cameraRef.current.near = nearZ;
}
},
},
farZ: {
value: 100,
min: -500,
max: 500,
step: 1,
onChange: (farZ) => {
if (cameraRef.current) {
cameraRef.current.far = farZ;
}
},
},
cameraPosition: {
value: [0, 0, 15],
onChange: (p) => {
if (cameraRef.current) {
cameraRef.current.position.set(...p);
}
},
},
pointsPosition: {
value: [-1, 1, 0],
onChange: (p) => {
if (pointRef.current) {
pointRef.current.position.set(...p);
}
},
},
lineStripPosition: {
value: [1, 1, 0],
onChange: (p) => {
if (lineStripRef.current) {
lineStripRef.current.position.set(...p);
}
},
},
lineLoopPosition: {
value: [-1, -1, 0],
onChange: (p) => {
if (lineLoopRef.current) {
lineLoopRef.current.position.set(...p);
}
},
},
trianglesPosition: {
value: [1, -1, 0],
onChange: (p) => {
if (trianglesRef.current) {
trianglesRef.current.position.set(...p);
}
},
},
}, {
store: store,
});
const init = () => {
const canvas = refDom.current;
canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;
const renderer = new Renderer(canvas, {
alpha: true,
});
const fov = 15;
const nearZ = 0.1;
const farZ = 100;
const camera = new PerspectiveCamera(fov, canvas.width / canvas.height, nearZ, farZ);
camera.position.z = 15;
cameraRef.current = camera;
function resize(target) {
const { width, height } = target.getBoundingClientRect();
renderer.setSize(width, height);
camera.aspect = width / height;
}
const scene = new Scene();
const geometry = new Geometry(renderer, {
position: {
size: 3,
data: new Float32Array([
-0.5, 0.5, 0,
-0.5, -0.5, 0,
0.5, 0.5, 0,
0.5, -0.5, 0
])
},
uv: {
size: 2,
data: new Float32Array([0, 1, 1, 1, 0, 0, 1, 0])
},
index: {
data: new Uint16Array([0, 1, 2, 1, 3, 2])
},
});
const program = new Program(renderer, {
vertexShader: vertex as string,
fragmentShader: fragment as string,
uniforms: {
uTime: { value: 0 },
},
});
const points = new Mesh(renderer, { mode: renderer.gl.POINTS, geometry, program });
points.setParent(scene);
points.position.set(-1, 1, 0);
pointRef.current = points;
const lineStrip = new Mesh(renderer, { mode: renderer.gl.LINES, geometry, program });
lineStrip.setParent(scene);
lineStrip.position.set(1, 1, 0);
lineStripRef.current = lineStrip;
const lineLoop = new Mesh(renderer, { mode: renderer.gl.LINE_LOOP, geometry, program });
lineLoop.setParent(scene);
lineLoop.position.set(-1, -1, 0);
const triangles = new Mesh(renderer, { mode: renderer.gl.TRIANGLES, geometry, program });
triangles.setParent(scene);
triangles.position.set(1, -1, 0);
const raf = new Raf((t) => {
program.setUniform('uTime', t);
renderer.render({ scene, camera });
});
return { canvas, resize };
}
useEffect(() => {
const { canvas, resize } = init();
observe(canvas, resize);
return () => {
unobserve(canvas, resize);
};
}, []);
return (
<div className="live-wrap">
<div className="leva-wrap">
<Leva
fill
></Leva>
<LevaPanel store={store} fill></LevaPanel>
</div>
<canvas className="scene-canvas" ref={refDom}></canvas>
</div>
);
}