Skip to content

Commit

Permalink
feat: nurbs surface a93ea84
Browse files Browse the repository at this point in the history
  • Loading branch information
plantain-00 committed Nov 16, 2023
1 parent 620f06a commit c137b16
Show file tree
Hide file tree
Showing 8 changed files with 191 additions and 23 deletions.
6 changes: 6 additions & 0 deletions dev/lib.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,11 @@ declare module 'verb-nurbs-web' {
declare class BezierCurve extends verb.geom.NurbsCurve {
constructor(points: core.Data.Point[]);
}
declare class NurbsSurface {
static byKnotsControlPointsWeights(degreeU: number, degreeV: number, knotsU: number[], knotsV: number[], controlPoints: core.Data.Point[][], weights?: number[][]): NurbsSurface
point(u: number, v: number): core.Data.Point
normal(u: number, v: number): core.Data.Point
tessellate() : core.Data.MeshData
}
}
}
27 changes: 25 additions & 2 deletions dev/webgl-3d.story.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from "react"
import { getAxesGraphics, bindMultipleRefs, createWebgl3DRenderer, getDashedLine, Graphic3d, metaKeyIfMacElseCtrlKey, updateCamera, useDragMove, useWheelScroll, useWheelZoom, useWindowSize, angleToRadian, useGlobalKeyDown } from "../src"
import { getAxesGraphics, bindMultipleRefs, createWebgl3DRenderer, getDashedLine, Graphic3d, metaKeyIfMacElseCtrlKey, updateCamera, useDragMove, useWheelScroll, useWheelZoom, useWindowSize, angleToRadian, useGlobalKeyDown, getNurbsSurfaceVertices } from "../src"

export default () => {
const ref = React.useRef<HTMLCanvasElement | null>(null)
Expand Down Expand Up @@ -63,14 +63,37 @@ export default () => {
},
{
geometry: {
type: 'cune',
type: 'cone',
topRadius: 0,
bottomRadius: 100,
height: 200,
},
color: [1, 0, 1, 1],
position: [0, -250, 0],
},
{
geometry: {
type: 'triangles',
points: [-50, -50, 50, 50, 50, 50, -50, 50, 50],
},
color: [0.5, 0, 0.5, 1],
position: [250, 250, 250],
},
{
geometry: {
type: 'vertices',
vertices: getNurbsSurfaceVertices([
[[0, 0, -20], [20, 0, 0], [40, 0, 0], [60, 0, 0], [80, 0, 0], [100, 0, 0]],
[[0, -20, 0], [20, -20, 10], [40, -20, 20], [60, -20, 0], [80, -20, 0], [100, -20, 0]],
[[0, -40, 0], [20, -40, 10], [40, -40, 20], [60, -40, 0], [80, -40, -4], [100, -40, -24]],
[[0, -50, 0], [20, -60, 0], [40, -60, -46], [60, -60, 0], [80, -60, 0], [100, -50, 0]],
[[0, -80, 0], [20, -80, 0], [40, -80, 0], [60, -80, 8], [80, -80, -40], [100, -80, 0]],
[[0, -100, 24], [20, -100, 0], [40, -100, 40], [60, -100, 0], [100, -100, -20], [100, -100, -30]],
], 3, [0, 0, 0, 0, 0.333, 0.666, 1, 1, 1, 1], 3, [0, 0, 0, 0, 0.333, 0.666, 1, 1, 1, 1]),
},
color: [0, 0.5, 0, 1],
position: [-250, 250, 250],
},
])

React.useEffect(() => {
Expand Down
32 changes: 28 additions & 4 deletions dev/webgpu-3d.story.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import * as React from "react"
import { bindMultipleRefs, Graphic3d, metaKeyIfMacElseCtrlKey, updateCamera, useDragMove, useWheelScroll, useWheelZoom, useWindowSize, angleToRadian, createWebgpu3DRenderer, getAxesGraphics, getDashedLine, useGlobalKeyDown } from "../src"
import { bindMultipleRefs, Graphic3d, metaKeyIfMacElseCtrlKey, updateCamera, useDragMove, useWheelScroll, useWheelZoom, useWindowSize, angleToRadian, createWebgpu3DRenderer, getAxesGraphics, getDashedLine, useGlobalKeyDown, getNurbsSurfaceVertices } from "../src"

export default () => {
const ref = React.useRef<HTMLCanvasElement | null>(null)
const renderer = React.useRef<Awaited<ReturnType<typeof createWebgpu3DRenderer>>>()
const { x, y, setX, setY, ref: wheelScrollRef } = useWheelScroll<HTMLDivElement>()
const { scale, setScale, ref: wheelZoomRef } = useWheelZoom<HTMLDivElement>()
const [rotate, setRotate] = React.useState({ x: 0, y: 0 })
const { offset, onStart: onStartMoveCanvas, mask: moveCanvasMask, resetDragMove} = useDragMove(() => {
const { offset, onStart: onStartMoveCanvas, mask: moveCanvasMask, resetDragMove } = useDragMove(() => {
setRotate((v) => ({ x: v.x + offset.x, y: v.y + offset.y }))
})
useGlobalKeyDown(e => {
Expand Down Expand Up @@ -63,14 +63,38 @@ export default () => {
},
{
geometry: {
type: 'cune',
type: 'cone',
topRadius: 0,
bottomRadius: 100,
height: 200,
},
color: [1, 0, 1, 1],
position: [0, -250, 0],
},
{
geometry: {
type: 'triangles',
points: [-50, -50, 50, 50, 50, 50, -50, 50, 50],
},
color: [0.5, 0, 0.5, 1],
position: [250, 250, 250],
},
{
geometry: {
type: 'vertices',
vertices: getNurbsSurfaceVertices([
[[0, 0, -20], [20, 0, 0], [40, 0, 0], [60, 0, 0], [80, 0, 0], [100, 0, 0]],
[[0, -20, 0], [20, -20, 10], [40, -20, 20], [60, -20, 0], [80, -20, 0], [100, -20, 0]],
[[0, -40, 0], [20, -40, 10], [40, -40, 20], [60, -40, 0], [80, -40, -4], [100, -40, -24]],
[[0, -50, 0], [20, -60, 0], [40, -60, -46], [60, -60, 0], [80, -60, 0], [100, -50, 0]],
[[0, -80, 0], [20, -80, 0], [40, -80, 0], [60, -80, 8], [80, -80, -40], [100, -80, 0]],
[[0, -100, 24], [20, -100, 0], [40, -100, 40], [60, -100, 0], [100, -100, -20], [100, -100, -30]],
], 3, [0, 0, 0, 0, 0.333, 0.666, 1, 1, 1, 1], 3, [0, 0, 0, 0, 0.333, 0.666, 1, 1, 1, 1]),
},
color: [0, 0.5, 0, 1],
position: [250, 250, -250],
rotateY: Math.PI,
},
])

React.useEffect(() => {
Expand Down Expand Up @@ -119,7 +143,7 @@ export default () => {
width={width}
height={height}
onMouseDown={e => onStartMoveCanvas({ x: e.clientX, y: e.clientY })}
onMouseMove={async e => setHovering(await renderer.current?.pick?.(e.clientX, e.clientY, (g) => g.geometry.type !== 'lines'))}
onMouseMove={async e => setHovering(await renderer.current?.pick?.(e.clientX, e.clientY, (g) => g.geometry.type !== 'lines' && g.geometry.type !== 'triangles'))}
/>
{moveCanvasMask}
</div>
Expand Down
2 changes: 1 addition & 1 deletion main.bundle.js

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions spec/nurbs.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import test from 'ava'
import { toQuadraticCurves, toBezierCurves, equals, interpolate3, interpolate4, interpolateNurbs, interpolateNurbs2 } from '../src'
import { toQuadraticCurves, toBezierCurves, equals, interpolate3, interpolate4, interpolateNurbs, interpolateNurbs2, Vec2 } from '../src'

test('interpolateNurbs2', (t) => {
const tvalues = [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]
const points = [
const points: Vec2[] = [
[-1.0, 0.0],
[-0.5, 0.5],
[0.5, -0.5],
Expand All @@ -21,7 +21,7 @@ test('interpolateNurbs2', (t) => {
[0.5, -0.5]
], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])))
const w = Math.pow(0.5, 0.5)
const points2 = [
const points2: Vec2[] = [
[0.0, -0.5],
[-0.5, -0.5],
[-0.5, 0.0],
Expand Down
29 changes: 23 additions & 6 deletions src/components/webgl-3d-renderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,24 @@ export interface Light {
export interface Material {
color: Vec4
position?: Vec3
rotateY?: number
}

export interface LinesGeometry {
type: 'lines' | 'line strip'
points: number[]
}

export interface TrianglesGeometry {
type: 'triangles' | 'triangle strip'
points: number[]
}

export interface VerticesGeometry {
type: 'vertices'
vertices: Record<string, twgl.primitives.TypedArray>
}

export interface PolygonGeometry {
type: 'polygon'
points: number[]
Expand All @@ -54,15 +65,15 @@ export interface CylinderGeometry {
height: number
}

export interface CuneGeometry {
type: 'cune'
export interface ConeGeometry {
type: 'cone'
bottomRadius: number
topRadius: number
height: number
}

export interface Graphic3d extends Material {
geometry: SphereGeometry | CubeGeometry | CylinderGeometry | CuneGeometry | LinesGeometry | PolygonGeometry
geometry: SphereGeometry | CubeGeometry | CylinderGeometry | ConeGeometry | LinesGeometry | TrianglesGeometry | PolygonGeometry | VerticesGeometry
}

export function createWebgl3DRenderer(canvas: HTMLCanvasElement) {
Expand Down Expand Up @@ -226,11 +237,14 @@ export function createWebgl3DRenderer(canvas: HTMLCanvasElement) {
return
}
let world = m4.identity()
if (g.rotateY) {
world = m4.rotateY(world, g.rotateY)
}
if (g.position) {
world = m4.translate(world, g.position)
}
let programInfo: twgl.ProgramInfo
if (g.geometry.type === 'lines' || g.geometry.type === 'line strip' || g.geometry.type === 'polygon') {
if (g.geometry.type === 'lines' || g.geometry.type === 'line strip' || g.geometry.type === 'triangles' || g.geometry.type === 'triangle strip' || g.geometry.type === 'polygon') {
programInfo = basicProgramInfo.instance
} else {
programInfo = primaryProgramInfo.instance
Expand All @@ -247,7 +261,7 @@ export function createWebgl3DRenderer(canvas: HTMLCanvasElement) {
if (g.geometry.type === 'cylinder') {
return twgl.primitives.createCylinderBufferInfo(gl, g.geometry.radius, g.geometry.height, 36, 4)
}
if (g.geometry.type === 'cune') {
if (g.geometry.type === 'cone') {
return twgl.primitives.createTruncatedConeBufferInfo(gl, g.geometry.bottomRadius, g.geometry.topRadius, g.geometry.height, 36, 4)
}
if (g.geometry.type === 'polygon') {
Expand All @@ -258,14 +272,17 @@ export function createWebgl3DRenderer(canvas: HTMLCanvasElement) {
}
})
}
if (g.geometry.type === 'vertices') {
return twgl.createBufferInfoFromArrays(gl, g.geometry.vertices)
}
return twgl.createBufferInfoFromArrays(gl, {
position: {
numComponents: 3,
data: g.geometry.points,
}
})
}),
type: g.geometry.type === 'lines' ? gl.LINES : g.geometry.type === 'line strip' ? gl.LINE_STRIP : gl.TRIANGLES,
type: g.geometry.type === 'lines' ? gl.LINES : g.geometry.type === 'line strip' ? gl.LINE_STRIP : g.geometry.type === 'triangle strip' ? gl.TRIANGLE_STRIP : gl.TRIANGLES,
uniforms: {
...uniforms,
u_diffuseMult: g.color,
Expand Down
16 changes: 11 additions & 5 deletions src/components/webgpu-3d-renderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -241,13 +241,16 @@ export async function createWebgpu3DRenderer(canvas: HTMLCanvasElement) {
return
}
let world = m4.identity()
if (g.rotateY) {
world = m4.rotateY(world, g.rotateY)
}
if (g.position) {
world = m4.translate(world, g.position)
}
const pipeline = basicPipelineCache.get(g.geometry.type, () => {
let shaderModule: GPUShaderModule
const bufferLayouts: GPUVertexBufferLayout[] = [{ arrayStride: 3 * 4, attributes: [{ shaderLocation: 0, offset: 0, format: 'float32x3' }] }]
if (g.geometry.type === 'lines' || g.geometry.type === 'line strip' || g.geometry.type === 'polygon') {
if (g.geometry.type === 'lines' || g.geometry.type === 'line strip' || g.geometry.type === 'triangles' || g.geometry.type === 'triangle strip' || g.geometry.type === 'polygon') {
shaderModule = basicShaderModule.instance
} else {
shaderModule = primaryShaderModule.instance
Expand All @@ -269,7 +272,7 @@ export async function createWebgpu3DRenderer(canvas: HTMLCanvasElement) {
},
primitive: {
cullMode: 'back',
topology: g.geometry.type === 'lines' ? 'line-list' : g.geometry.type === 'line strip' ? 'line-strip' : 'triangle-list',
topology: g.geometry.type === 'lines' ? 'line-list' : g.geometry.type === 'line strip' ? 'line-strip' : g.geometry.type === 'triangle strip' ? 'triangle-strip' : 'triangle-list',
},
depthStencil: {
depthWriteEnabled: true,
Expand Down Expand Up @@ -301,7 +304,7 @@ export async function createWebgpu3DRenderer(canvas: HTMLCanvasElement) {
])
},
}]
if (g.geometry.type !== 'lines' && g.geometry.type !== 'line strip' && g.geometry.type !== 'polygon') {
if (g.geometry.type !== 'lines' && g.geometry.type !== 'line strip' && g.geometry.type !== 'triangles' && g.geometry.type !== 'triangle strip' && g.geometry.type !== 'polygon') {
bindGroupEntries.push(
{ binding: 1, resource: sampler },
{ binding: 2, resource: texture.createView() },
Expand All @@ -321,7 +324,7 @@ export async function createWebgpu3DRenderer(canvas: HTMLCanvasElement) {
if (g.geometry.type === 'cylinder') {
return createBuffers(device, twgl.primitives.createCylinderVertices(g.geometry.radius, g.geometry.height, 36, 4))
}
if (g.geometry.type === 'cune') {
if (g.geometry.type === 'cone') {
return createBuffers(device, twgl.primitives.createTruncatedConeVertices(g.geometry.bottomRadius, g.geometry.topRadius, g.geometry.height, 36, 4))
}
if (g.geometry.type === 'polygon') {
Expand All @@ -330,6 +333,9 @@ export async function createWebgpu3DRenderer(canvas: HTMLCanvasElement) {
count: g.geometry.points.length / 3,
}
}
if (g.geometry.type === 'vertices') {
return createBuffers(device, g.geometry.vertices)
}
return {
positionBuffer: createVertexBuffer(device, new Float32Array(g.geometry.points)),
count: g.geometry.points.length / 3,
Expand Down Expand Up @@ -407,7 +413,7 @@ export async function createWebgpu3DRenderer(canvas: HTMLCanvasElement) {
},
primitive: {
cullMode: 'back',
topology: g.geometry.type === 'lines' ? 'line-list' : g.geometry.type === 'line strip' ? 'line-strip' : 'triangle-list',
topology: g.geometry.type === 'lines' ? 'line-list' : g.geometry.type === 'line strip' ? 'line-strip' : g.geometry.type === 'triangle strip' ? 'triangle-strip' : 'triangle-list',
},
depthStencil: {
depthWriteEnabled: true,
Expand Down
Loading

0 comments on commit c137b16

Please sign in to comment.