mirror of
https://github.com/visgl/luma.gl.git
synced 2026-01-18 14:03:42 +00:00
99 lines
3.3 KiB
Plaintext
99 lines
3.3 KiB
Plaintext
import {DeviceTabs} from '@site/src/react-luma';
|
|
import {HelloTriangleExample} from '@site/src/examples';
|
|
|
|
# Hello Triangle
|
|
|
|
This tutorial demonstrates how to draw a triangle using luma.gl's cross-platform rendering APIs.
|
|
|
|
:::caution
|
|
Tutorials are maintained on a best-effort basis and may not be fully up to date (contributions welcome).
|
|
:::
|
|
|
|
<DeviceTabs />
|
|
<HelloTriangleExample />
|
|
|
|
It is assumed you've set up your development environment as described in [Setup](/docs/tutorials).
|
|
|
|
We create a `Model` to render the triangle. This will be a recurring theme in all our tutorials. A `Model` can be thought of as gathering all the WebGL/WebGPU pieces necessary for a single draw call: render pipelines (shader programs), attribute buffers, uniforms, texture bindings etc.
|
|
|
|
The program uses a tiny vertex shader that relies on the built-in `vertex_index` to look up clip-space positions for the three vertices. A matching fragment shader fills the triangle with a solid color. Both WGSL and GLSL versions are provided so the example runs on WebGPU and WebGL without changes.
|
|
|
|
The complete source for this example is shown below. It creates a `Model` with both WGSL and GLSL shaders and renders it inside an `AnimationLoopTemplate`. The animation loop simply opens a render pass, draws the model and ends the pass each frame.
|
|
|
|
```typescript
|
|
import {AnimationLoopTemplate, AnimationProps, makeAnimationLoop, Model} from '@luma.gl/engine';
|
|
import {webgl2Adapter} from '@luma.gl/webgl';
|
|
import {webgpuAdapter} from '@luma.gl/webgpu';
|
|
|
|
const WGSL_SHADER = /* WGSL */ `
|
|
@vertex
|
|
fn vertexMain(@builtin(vertex_index) vertexIndex : u32) -> @builtin(position) vec4<f32> {
|
|
var positions = array<vec2<f32>, 3>(vec2(0.0, 0.5), vec2(-0.5, -0.5), vec2(0.5, -0.5));
|
|
return vec4<f32>(positions[vertexIndex], 0.0, 1.0);
|
|
}
|
|
|
|
@fragment
|
|
fn fragmentMain() -> @location(0) vec4<f32> {
|
|
return vec4<f32>(1.0, 0.0, 0.0, 1.0);
|
|
}
|
|
`;
|
|
|
|
const VS_GLSL = /* glsl */ `
|
|
#version 300 es
|
|
const vec2 pos[3] = vec2[3](vec2(0.0f, 0.5f), vec2(-0.5f, -0.5f), vec2(0.5f, -0.5f));
|
|
void main() {
|
|
gl_Position = vec4(pos[gl_VertexID], 0.0, 1.0);
|
|
}
|
|
`;
|
|
|
|
const FS_GLSL = /* glsl */ `
|
|
#version 300 es
|
|
precision highp float;
|
|
layout(location = 0) out vec4 outColor;
|
|
void main() {
|
|
outColor = vec4(1.0, 0.0, 0.0, 1.0);
|
|
}
|
|
`;
|
|
|
|
class AppAnimationLoopTemplate extends AnimationLoopTemplate {
|
|
model: Model;
|
|
|
|
constructor({device}: AnimationProps) {
|
|
super();
|
|
this.model = new Model(device, {
|
|
source: WGSL_SHADER,
|
|
vs: VS_GLSL,
|
|
fs: FS_GLSL,
|
|
topology: 'triangle-list',
|
|
vertexCount: 3,
|
|
shaderLayout: {
|
|
attributes: [],
|
|
bindings: []
|
|
},
|
|
parameters: {
|
|
depthFormat: 'depth24plus'
|
|
}
|
|
});
|
|
}
|
|
|
|
override onFinalize() {
|
|
this.model.destroy();
|
|
}
|
|
|
|
override onRender({device}: AnimationProps) {
|
|
const renderPass = device.beginRenderPass({clearColor: [1, 1, 1, 1]});
|
|
this.model.draw(renderPass);
|
|
renderPass.end();
|
|
}
|
|
}
|
|
|
|
const animationLoop = makeAnimationLoop(AnimationLoopTemplate, {adapters: [webgpuAdapter, webgl2Adapter]})
|
|
animationLoop.start();
|
|
```
|
|
|
|
The vertex shader uses built-in indices, so no vertex buffers are needed for this
|
|
minimal example. The render loop clears the canvas and draws the model every
|
|
frame.
|
|
|
|
When the application runs you should see a red triangle rendered on a white background.
|