浏览代码

MeshLineMaterial alias, some fat lines docs, spiral mesh lines example

master
Palash Bansal 11 个月前
父节点
当前提交
2cb52b8b42
没有帐户链接到提交者的电子邮件

+ 37
- 0
examples/fat-line-spiral/index.html 查看文件

@@ -0,0 +1,37 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Fat Lines/Mesh Lines 2</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported -->
<script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

<script type="importmap">
{
"imports": {
"threepipe": "./../../dist/index.mjs",
"@threepipe/plugin-tweakpane": "./../../plugins/tweakpane/dist/index.mjs"
}
}

</script>
<style id="example-style">
html, body, #canvas-container, #mcanvas {
width: 100%;
height: 100%;
margin: 0;
overflow: hidden;
}
</style>
<script type="module" src="../examples-utils/global-loading.mjs"></script>
<script type="module" src="../examples-utils/simple-code-preview.mjs"></script>
<script id="example-script" type="module" src="./script.js" data-scripts="./script.ts;./script.js"></script>
</head>
<body>
<div id="canvas-container">
<canvas id="mcanvas"></canvas>
</div>

</body>

+ 88
- 0
examples/fat-line-spiral/script.ts 查看文件

@@ -0,0 +1,88 @@
import {
_testFinish,
_testStart,
Color, generateUiConfig,
LineGeometry2,
LineMaterial2,
LoadingScreenPlugin,
MeshLine,
PickingPlugin,
ThreeViewer,
} from 'threepipe'
import {TweakpaneUiPlugin} from '@threepipe/plugin-tweakpane'

// Read more about the example - https://threepipe.org/notes/fat-lines

async function init() {
const viewer = new ThreeViewer({
canvas: document.getElementById('mcanvas') as HTMLCanvasElement,
msaa: true,
plugins: [LoadingScreenPlugin, PickingPlugin],
dropzone: true,
})

viewer.scene.autoNearFarEnabled = false

viewer.scene.backgroundColor = new Color(0x333333)

const spiral = {
radius: 1,
height: 2,
loops: 10,
width: 5,
}

const line = new MeshLine(new LineGeometry2(), new LineMaterial2())
line.material.color = new Color(0xffffff)
line.material.vertexColors = true
line.material.linewidth = 5 // pixels
line.rotateX(Math.PI / 2)
function updateSpiral() {
const {positions, colors} = makeSpiral(spiral.radius, spiral.height, spiral.loops)
line.geometry.setPositions(positions)
line.geometry.setColors(colors)
line.material.linewidth = spiral.width
line.setDirty()
}
updateSpiral()

viewer.scene.addObject(line)

const ui = viewer.addPluginSync(new TweakpaneUiPlugin(true))
ui.setupPluginUi(PickingPlugin)
ui.appendChild({
type: 'folder',
label: 'Spiral',
children: generateUiConfig(spiral),
onChange: updateSpiral,
expanded: true,
})
ui.appendChild(line.uiConfig)

}

_testStart()
init().finally(_testFinish)

function makeSpiral(radius = 1, height = 2, loops = 10) {
const positions: number[] = []
const colors: number[] = []
const segments = 1000
const angleStep = Math.PI * 2 * loops / segments
const heightStep = height / segments

for (let i = 0; i <= segments; i++) {
const angle = i * angleStep
const x = radius * Math.cos(angle)
const y = radius * Math.sin(angle)
const z = i * heightStep - height / 2

positions.push(x, y, z)

// Color gradient from blue to red
const colorValue = i / segments
colors.push(colorValue, 0, 1 - colorValue) // RGB
}

return {positions, colors}
}

+ 2
- 0
examples/fat-lines/script.ts 查看文件

@@ -10,6 +10,8 @@ import {
} from 'threepipe'
import {TweakpaneUiPlugin} from '@threepipe/plugin-tweakpane'

// Read more about the example - https://threepipe.org/notes/gltf-mesh-lines

async function init() {

const viewer = new ThreeViewer({

+ 2
- 0
examples/gltf-mesh-lines/script.ts 查看文件

@@ -14,6 +14,8 @@ import {
} from 'threepipe'
import {TweakpaneUiPlugin} from '@threepipe/plugin-tweakpane'

// Read more about the example - https://threepipe.org/notes/gltf-mesh-lines

async function init() {

const viewer = new ThreeViewer({

+ 1
- 0
examples/index.html 查看文件

@@ -511,6 +511,7 @@
<li><a href="./3dm-to-glb/">Convert 3DM to GLB </a></li>
<li><a href="./hdr-to-exr/">Convert HDR to EXR </a></li>
<li><a href="./fat-lines/">Fat Lines <br/>(Mesh Lines) </a></li>
<li><a href="./fat-line-spiral/">Line Spiral<br/>(Mesh Lines) </a></li>
</ul>
<h2 class="category">Experiments</h2>
<ul>

+ 1
- 0
examples/msaa-ssaa/script.ts 查看文件

@@ -24,6 +24,7 @@ async function init() {
},
plugins: [LoadingScreenPlugin],
})

viewer.addPluginSync(new SSAAPlugin())

await Promise.all([

+ 1
- 1
src/core/index.ts 查看文件

@@ -7,7 +7,7 @@ export {ShaderMaterial2} from './material/ShaderMaterial2'
export {ObjectShaderMaterial} from './material/ObjectShaderMaterial'
export {UnlitMaterial, MeshBasicMaterial2} from './material/UnlitMaterial'
export {UnlitLineMaterial, LineBasicMaterial2} from './material/UnlitLineMaterial'
export {LineMaterial2} from './material/LineMaterial2'
export {LineMaterial2, MeshLineMaterial} from './material/LineMaterial2'
export {LegacyPhongMaterial} from './material/LegacyPhongMaterial'
export {Mesh2} from './object/Mesh2'
export {MeshLine} from './object/MeshLine'

+ 2
- 0
src/core/material/LineMaterial2.ts 查看文件

@@ -247,3 +247,5 @@ export class LineMaterial2<TE extends IMaterialEventMap = IMaterialEventMap> ext
}

}

export class MeshLineMaterial extends LineMaterial2 {}

+ 2
- 0
src/core/object/MeshLine.ts 查看文件

@@ -4,6 +4,7 @@ import {IObject3D, IObject3DEventMap, IObject3DUserData} from '../IObject'
import {Line2} from 'three/examples/jsm/lines/Line2'
import {iObjectCommons} from './iObjectCommons'
import {IMaterial} from '../IMaterial'
import {UiObjectConfig} from 'uiconfig.js'

export class MeshLine<
TGeometry extends LineGeometry2 = LineGeometry2,
@@ -18,6 +19,7 @@ export class MeshLine<
declare material: TMaterial
declare readonly materials: IMaterial[]
declare geometry: TGeometry
declare uiConfig: UiObjectConfig

/**
* @deprecated use `this` instead

+ 1
- 1
src/viewer/version.ts 查看文件

@@ -1 +1 @@
export const VERSION = '0.0.47'
export const VERSION = '0.0.48'

+ 8
- 0
website/.vitepress/config.ts 查看文件

@@ -41,6 +41,13 @@ export default defineConfig({
{text: 'Plugin System', link: 'guide/plugin-system'},
]
},
{
text: 'Articles', collapsed: false,
items: [
{text: 'Mesh Lines (Spiral)', link: 'notes/fat-lines'},
{text: 'glTF Mesh Lines', link: 'notes/gltf-mesh-lines'},
]
},
{
text: 'Core Plugins', collapsed: false,
items: [
@@ -164,6 +171,7 @@ export default defineConfig({
{
text: 'Packages', collapsed: false,
items: [
{text: 'WebGi Rendering Plugins', link: 'https://webgi.dev/'},
{text: 'Tweakpane Plugin', link: 'package/plugin-tweakpane'},
{text: 'Blueprint.js Plugin', link: 'package/plugin-blueprintjs'},
{text: 'Tweakpane Editor Plugin', link: 'package/plugin-tweakpane-editor'},

+ 90
- 0
website/notes/fat-lines.md 查看文件

@@ -0,0 +1,90 @@
---
next:
text: 'GLTF Fat/Mesh Lines'
link: './gltf-mesh-lines'

prev: false
aside: false
---

# Fat Lines: Spiral Example

<iframe src="https://threepipe.org/examples/fat-line-spiral/" style="width:100%;height:600px;border:none;"></iframe>

This example shows how to use ThreePipe's fat lines (MeshLine) to draw a thick, colorful spiral. The spiral's shape and color are generated in code, and you can adjust its parameters live using the UI.

**How it works:**
- The spiral is made by calculating 3D positions in a loop, using radius, height, and loops for shape.
- Each point gets a color, creating a gradient from blue to red.
- `MeshLine` (an extension of three.js Line2) is used to make the line thick and support per-vertex colors.
- The UI lets you change the spiral's radius, height, and loops, and see updates instantly.

**Key code:**

```typescript
function makeSpiral(radius = 1, height = 2, loops = 10) {
const positions = [], colors = []
for (let i = 0; i <= 1000; i++) {
const t = i / 1000, angle = t * Math.PI * 2 * loops
positions.push(radius * Math.cos(angle), radius * Math.sin(angle), t * height - height/2)
colors.push(t, 0, 1-t)
}
return {positions, colors}
}

const line = new MeshLine(new LineGeometry2(), new LineMaterial2())
line.material.vertexColors = true
line.material.linewidth = 5
function updateSpiral() {
const {positions, colors} = makeSpiral(spiral.radius, spiral.height, spiral.loops)
line.geometry.setPositions(positions)
line.geometry.setColors(colors)
line.material.setDirty()
}
```

The line and its controls are added to the UI with Tweakpane:

```typescript
ui.appendChild({
type: 'folder',
label: 'Spiral',
children: generateUiConfig(spiral),
onChange: updateSpiral,
})
ui.appendChild(line.uiConfig)
```

See the [full code here](https://github.com/repalash/threepipe/blob/master/examples/fat-line-spiral/script.ts), live example on [threepipe.org/examples](https://threepipe.org/examples/fat-line-spiral/).

::: warning
Fat lines (MeshLine) cannot be exported with glTF. If you want to create lines that can be exported as glTF lines, use three.js `Line` directly (for now).
:::

## Features of `MeshLine`

- **Adjustable thickness:** Unlike standard three.js lines, fat lines can be any width, not just 1 pixel.
- **Per-vertex color:** Supports gradients and color effects along the line.
- **UI integration:** Easily expose line and spiral parameters for live editing.
- **Performance:** Efficiently renders thousands of segments as a single mesh.

## How Fat Lines Work Under the Hood

ThreePipe's `MeshLine` is built on top of the three.js [Line2](https://threejs.org/docs/#examples/en/lines/Line2) addon. Instead of drawing a single-pixel line, it creates a mesh strip along the path, allowing for thick, anti-aliased lines. The geometry stores positions and colors, and the material handles width, color, and other effects. This approach works in all modern browsers and supports advanced features like dashes and transparency.

## When to Use `MeshLine`

Use fat lines when you need:
- Outlines, paths, or polylines with variable thickness
- Technical illustrations or stylized effects
- Color gradients or dashes along a line
- Interactive geometry that updates in real time
- Using as a viewer (not exporting as glTF)

For simple, single-pixel lines, the default three.js `Line` is still fastest, but for anything more advanced, `MeshLine` is the way to go.

## Using with glTF files

When importing glTF files with embedded line geometries and materials, `GLTFLoader2.UseMeshLines` feature can be used to automatically convert those lines to `MeshLine` instances. This allows you to take advantage of the advanced line rendering capabilities without needing to modify the original GLTF files.

Checkout the article on [GLTF Mesh Lines](https://threepipe.org/notes/gltf-mesh-lines) for more details on how to use this feature.

+ 63
- 0
website/notes/gltf-mesh-lines.md 查看文件

@@ -0,0 +1,63 @@
---
prev:
text: 'Fat Lines'
link: './fat-lines'

next: false
aside: false
---

# GLTF Mesh Lines: Fat Lines in glTF

[GLTF Mesh Lines Example](https://threepipe.org/examples/#gltf-mesh-lines/)
<iframe src="https://threepipe.org/examples/gltf-mesh-lines/" style="width:100%;min-height:600px;border:none;" loading="lazy" title="GLTF Mesh Lines Example"></iframe>

See Also: [Fat Lines Example](https://threepipe.org/examples/#fat-lines/)
See Also: [Fat Line Spiral Example](https://threepipe.org/examples/#fat-line-spiral/)

If you've ever tried to render thick ("fat") lines in three.js, especially when importing models from GLTF files, you know it can be surprisingly tricky. By default, three.js only supports 1-pixel wide lines due to WebGL limitations. This makes it difficult to achieve visually appealing, stylized, or technical line renderings directly from imported models.

The standard `THREE.Line` and `THREE.LineSegments` classes rely on basic WebGL line rendering, which is limited to a width of 1 pixel on most platforms. As a result, creating thick lines for wireframes, outlines, or technical illustrations is not possible out of the box.

To work around this, three.js provides the [Line2, LineMaterial](https://threejs.org/docs/#examples/en/lines/Line2) classes in three.js addons.
These render lines as thin meshes, allowing for customizable widths, colors, and other properties.
The `threepipe` framework extends this further by providing an option to automatically use these advanced line types for all lines imported from GLTF files.

You can enable this feature globally by setting:

```ts
GLTFLoader2.UseMeshLines = true;
```

::: danger WARNING
Lines imported this way may not export correctly when using the glTF exporter, as the mesh-based lines are not standard GLTF lines. This may change in later versions of three.js or threepipe.

Only enable the feature when using `threepipe` as a viewer.
:::

Once the feature is enabled, glTF files with lines will be imported using `Line2` and `LineMaterial2` instead of the default line classes.

This can be controlled per-glTF file during load with the `useMeshLines` option:

```ts
const obj = await viewer.load('model.gltf', {
useMeshLines: false,
});
```

When enabled, all lines in the imported GLTF will use `Line2`/`LineMaterial2`, allowing you to set properties like `linewidth` (yes, it's all lowercase)

```ts
material.linewidth = 10;
```

> **Note:** The resolution of the line is set automatically based on the render size, so `linewidth` is always in pixels. If you want the line width to attenuate with distance (i.e., be in world units), you can set the `worldUnits` flag on the material to `true`.

## API Documentation

- `MeshLine` - https://threepipe.org/docs/classes/MeshLine.html
- `MeshLineSegments` - https://threepipe.org/docs/classes/MeshLineSegments.html
- `LineMaterial2`/`MeshLineMaterial` - https://threepipe.org/docs/classes/LineMaterial2.html
- `GLTFLoader2` - https://threepipe.org/docs/classes/GLTFLoader2.html
- three.js `LineMaterial` - https://threejs.org/docs/?q=line#examples/en/lines/LineMaterial
- three.js `Line2` - https://threejs.org/docs/?q=line#examples/en/lines/Line2

正在加载...
取消
保存