Skip to content

Commit

Permalink
Merge pull request #3 from ImHyeLim1209/feat/create-key
Browse files Browse the repository at this point in the history
feat: 키캡 만들기
  • Loading branch information
behoney authored Feb 12, 2023
2 parents 517a6c7 + 4c1bc57 commit 4bfc5f0
Show file tree
Hide file tree
Showing 7 changed files with 334 additions and 32 deletions.
160 changes: 160 additions & 0 deletions src/components/Keyboard/Key/KeyCap.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
import { Vector3 } from '@react-three/fiber'
import { IkeyConfig } from '../../../types/KeyboardType'
import {
DIFF_WIDTH,
DIFF_DEPTH_TOP,
DIFF_DEPTH_BOTTOM,
TOP_WIDTH_INSET,
TOP_DEPTH_INSET,
HEIGHT,
} from './consts'

const createVertices = (width: number, depth: number) => {
const positionBottomRect = [
[0, 0, 0],
[width, 0, 0],
[0, 0, depth],
[width, 0, depth],
]

const positionTopOctagon = [
[width / 2, HEIGHT, depth / 2], // center
[DIFF_WIDTH + TOP_WIDTH_INSET, HEIGHT, DIFF_DEPTH_TOP],
[width - DIFF_WIDTH - TOP_WIDTH_INSET, HEIGHT, DIFF_DEPTH_TOP],
[DIFF_WIDTH, HEIGHT, DIFF_DEPTH_TOP + TOP_DEPTH_INSET],
[width - DIFF_WIDTH, HEIGHT, DIFF_DEPTH_TOP + TOP_DEPTH_INSET],
[DIFF_WIDTH, HEIGHT, depth - DIFF_DEPTH_BOTTOM - TOP_DEPTH_INSET],
[width - DIFF_WIDTH, HEIGHT, depth - DIFF_DEPTH_BOTTOM - TOP_DEPTH_INSET],
[DIFF_WIDTH + TOP_WIDTH_INSET, HEIGHT, depth - DIFF_DEPTH_BOTTOM],
[width - DIFF_WIDTH - TOP_WIDTH_INSET, HEIGHT, depth - DIFF_DEPTH_BOTTOM],
]

return new Float32Array([
// 윗면1
...positionTopOctagon[0],
...positionTopOctagon[2],
...positionTopOctagon[1],

// 윗면2
...positionTopOctagon[0],
...positionTopOctagon[1],
...positionTopOctagon[3],

// 윗면3
...positionTopOctagon[0],
...positionTopOctagon[4],
...positionTopOctagon[2],

// 윗면4
...positionTopOctagon[0],
...positionTopOctagon[3],
...positionTopOctagon[5],

// 윗면5
...positionTopOctagon[0],
...positionTopOctagon[6],
...positionTopOctagon[4],

// 윗면6
...positionTopOctagon[0],
...positionTopOctagon[5],
...positionTopOctagon[7],

// 윗면7
...positionTopOctagon[0],
...positionTopOctagon[8],
...positionTopOctagon[6],

// 윗면8
...positionTopOctagon[0],
...positionTopOctagon[7],
...positionTopOctagon[8],

// 옆면 코너 1
...positionTopOctagon[3],
...positionTopOctagon[1],
...positionBottomRect[0],

// 옆면 코너 2
...positionBottomRect[1],
...positionTopOctagon[2],
...positionTopOctagon[4],

// 옆면 코너 3
...positionTopOctagon[5],
...positionBottomRect[2],
...positionTopOctagon[7],

// 옆면 코너 4
...positionTopOctagon[6],
...positionTopOctagon[8],
...positionBottomRect[3],

// 옆면 1 - 1
...positionBottomRect[0],
...positionTopOctagon[1],
...positionTopOctagon[2],

// 옆면 1 - 2
...positionBottomRect[0],
...positionTopOctagon[2],
...positionBottomRect[1],

// 옆면 2 - 1
...positionBottomRect[0],
...positionTopOctagon[5],
...positionTopOctagon[3],

// 옆면 2 - 2
...positionBottomRect[0],
...positionBottomRect[2],
...positionTopOctagon[5],

// 옆면 3 - 1
...positionBottomRect[1],
...positionTopOctagon[4],
...positionTopOctagon[6],

// 옆면 3 - 2
...positionBottomRect[1],
...positionTopOctagon[6],
...positionBottomRect[3],

// 옆면 4 - 1
...positionBottomRect[2],
...positionTopOctagon[8],
...positionTopOctagon[7],

// 옆면 4 - 2
...positionBottomRect[2],
...positionBottomRect[3],
...positionTopOctagon[8],
])
}

interface IKeyCapProps {
config: IkeyConfig
position: Vector3
}

export default ({ config, position }: IKeyCapProps) => {
const { rowSpan, colSpan, color } = config
const vertices = createVertices(colSpan, rowSpan)

return (
<mesh position={position}>
<bufferGeometry
attach="geometry"
onUpdate={(self) => self.computeVertexNormals()}
>
<bufferAttribute
attach="attributes-position"
array={vertices}
count={vertices.length / 3}
itemSize={3}
/>
</bufferGeometry>
<meshStandardMaterial attach="material" color={color} />
</mesh>
)
}
56 changes: 56 additions & 0 deletions src/components/Keyboard/Key/KeyLegend.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { IKeyLegend } from '../../../types/KeyboardType'
import { DIFF_WIDTH, DIFF_DEPTH_TOP, HEIGHT } from './consts'
import { Vector3 } from 'three'

interface IKeyLegendProps {
keyPosition: {
row: number
column: number
}
config?: IKeyLegend
}

const createCanvas = ({ text, color }: IKeyLegend) => {
const canvas = document.createElement('canvas')
const context = canvas.getContext('2d')

if (context) {
context.font = 'Bold 60px system-ui'
context.fillStyle = color.toString()
context.fillText(text, 0, 40)
context.imageSmoothingQuality = 'high'
}

return canvas
}

export default (config: IKeyLegendProps) => {
const { keyPosition, config: legendConfig } = config

if (!legendConfig) return <></>

const textureCanvas = createCanvas(legendConfig)
const { column, row } = keyPosition
const legendPosition = new Vector3(
column + 0.5 + DIFF_WIDTH * 2,
HEIGHT,
row + 0.5 + DIFF_DEPTH_TOP * 2,
)

return (
<mesh position={legendPosition} rotation={[-Math.PI * 0.5, 0, 0]}>
<planeGeometry attach="geometry" args={[1, 1]} />
<meshStandardMaterial
transparent={true}
polygonOffset={true}
polygonOffsetFactor={-1}
>
<canvasTexture
attach="map"
image={textureCanvas}
onUpdate={(s) => (s.needsUpdate = true)}
/>
</meshStandardMaterial>
</mesh>
)
}
6 changes: 6 additions & 0 deletions src/components/Keyboard/Key/consts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export const DIFF_WIDTH = 0.3 / 2
export const DIFF_DEPTH_TOP = 0.2 / 2
export const DIFF_DEPTH_BOTTOM = 0.4 / 2
export const TOP_WIDTH_INSET = 0.07
export const TOP_DEPTH_INSET = 0.05
export const HEIGHT = 0.5
56 changes: 56 additions & 0 deletions src/components/Keyboard/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { Vector3 } from '@react-three/fiber'
import React from 'react'
import KeyCap from './Key/KeyCap'
import KeyLegend from './Key/KeyLegend'

const keyConfigs = [
{
row: 0,
column: 0,
rowSpan: 1,
colSpan: 1,
color: '#6096B4',
legend: { text: 'A', color: '#93BFCF' },
},
{
row: 0,
column: 1,
rowSpan: 1,
colSpan: 1,
color: '#F0EEED',
legend: { text: 'S', color: '#332C39' },
},
{ row: 1, column: 0, rowSpan: 1, colSpan: 2, color: '#FFFFFF' },
{ row: 0, column: 2, rowSpan: 1, colSpan: 2, color: '#000000' },
{
row: 1,
column: 2,
rowSpan: 1,
colSpan: 2,
color: '#EFA3C8',
legend: { text: 'ENTER', color: '#0F6292' },
},
]

interface IKeyboardProps {
position: Vector3
}

export default ({ position }: IKeyboardProps) => {
return (
<group position={position}>
{keyConfigs.map((keyConfig) => (
<React.Fragment key={`${keyConfig.row}-${keyConfig.column}`}>
<KeyCap
config={keyConfig}
position={[keyConfig.column, 0, keyConfig.row]}
/>
<KeyLegend
config={keyConfig.legend}
keyPosition={{ row: keyConfig.row, column: keyConfig.column }}
/>
</React.Fragment>
))}
</group>
)
}
29 changes: 29 additions & 0 deletions src/components/Lights/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { useRef } from 'react'
import { useHelper } from '@react-three/drei'
import { DirectionalLight, DirectionalLightHelper } from 'three'

export default () => {
const frontLight = useRef<DirectionalLight>(null!)
const backShadow = useRef<DirectionalLight>(null!)

useHelper(frontLight, DirectionalLightHelper, 2, '#FFB2F5')
useHelper(backShadow, DirectionalLightHelper, 2, '#990085')

return (
<>
<ambientLight color="#FFFFFF" intensity={0.5} />
<directionalLight
ref={frontLight}
color="#FFFFFF"
intensity={0.5}
position={[5, 10, 10]}
/>
<directionalLight
ref={backShadow}
color="#CCCCCC"
intensity={0.2}
position={[-4, 3, -10]}
/>
</>
)
}
44 changes: 12 additions & 32 deletions src/components/ThreeFiber/ThreeFiber.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,48 +3,28 @@

import styled from '@emotion/styled'
import { OrbitControls } from '@react-three/drei'
import { Canvas, useFrame } from '@react-three/fiber'
import { useRef, useState } from 'react'
import { Canvas } from '@react-three/fiber'
import * as THREE from 'three'
import Keyboard from '../Keyboard'
import Lights from '../Lights'

export const ThreeFiber = () => {
return (
<CanvasContainer id="canvas-container">
<Canvas>
<ambientLight intensity={0.5} />
<spotLight position={[10, 10, 10]} angle={0.15} penumbra={1} />
<pointLight position={[-10, -10, -10]} />
<Box position={[-1.2, 0, 0]} />
<Box position={[1.2, 0, 0]} />
<Canvas
camera={{ position: [-2, 2, 5] }}
gl={{ antialias: true, toneMapping: THREE.NoToneMapping }}
// linear
>
<Keyboard position={[-1, 0, -1]} />
<Lights />
<axesHelper scale={10} />
<OrbitControls />
</Canvas>
</CanvasContainer>
)
}

function Box(props: any) {
// This reference gives us direct access to the THREE.Mesh object
const ref = useRef<any>()
// Hold state for hovered and clicked events
const [hovered, hover] = useState(false)
const [clicked, click] = useState(false)
// Subscribe this component to the render-loop, rotate the mesh every frame
useFrame((state, delta) => (ref.current.rotation.x += delta))
// Return the view, these are regular Threejs elements expressed in JSX
return (
<mesh
{...props}
ref={ref}
scale={clicked ? 1.5 : 1}
onClick={(event) => click(!clicked)}
onPointerOver={(event) => hover(true)}
onPointerOut={(event) => hover(false)}
>
<boxGeometry args={[1, 1, 1]} />
<meshStandardMaterial color={hovered ? 'hotpink' : 'orange'} />
</mesh>
)
}

const CanvasContainer = styled.div`
width: 100vw;
height: 100vh;
Expand Down
15 changes: 15 additions & 0 deletions src/types/KeyboardType.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Color } from '@react-three/fiber'

export interface IKeyLegend {
text: string
color: Color
}

export interface IkeyConfig {
row: number
column: number
rowSpan: number
colSpan: number
color: Color
legend?: IKeyLegend
}

0 comments on commit 4bfc5f0

Please sign in to comment.