Skip to content

Instantly share code, notes, and snippets.

@whoisryosuke
Created May 27, 2022 02:04
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save whoisryosuke/e9c5aa46ce60125d9ea0bb4cdb90fa6a to your computer and use it in GitHub Desktop.
Save whoisryosuke/e9c5aa46ce60125d9ea0bb4cdb90fa6a to your computer and use it in GitHub Desktop.
Shader / GLSL / OpenGL - Inner border fragment shader (better version with lighter grid inside). Resembles a "prototype" box for "grid"-like level debugging in game development.
import * as THREE from 'three'
import { useFrame, extend, MeshProps } from '@react-three/fiber'
import { useRef, useState } from 'react'
import useStore from '@/helpers/store'
import { shaderMaterial } from '@react-three/drei'
import { Color, Mesh } from "three"
import vertex from './glsl/shader.vert'
import fragment from './glsl/shader.frag'
const ColorShiftMaterial = shaderMaterial(
{
time: 0,
color: new THREE.Color(8/255, 108/255, 149/255),
borderColor: new THREE.Color(0.9,0.9,0.9),
borderWidth: 0.1,
gridSize: 0.1,
gridWidth: 0.05,
},
vertex,
fragment
)
// This is the 🔑 that HMR will renew if this file is edited
// It works for THREE.ShaderMaterial as well as for drei/shaderMaterial
// @ts-ignore
ColorShiftMaterial.key = THREE.MathUtils.generateUUID()
extend({ ColorShiftMaterial })
type Props = Partial<MeshProps> & {
color: Color;
borderColor: Color;
}
const Shader = ({
color,
borderColor,
...props
}: Props) => {
const meshRef = useRef(null)
console.log('color', color)
useFrame((state, delta) => {
if (meshRef.current) {
meshRef.current.rotation.x = meshRef.current.rotation.y += 0.01
}
if (meshRef.current.material) {
meshRef.current.material.uniforms.time.value +=
Math.sin(delta / 2) * Math.cos(delta / 2)
}
if(meshRef.current.material && color) {
meshRef.current.material.uniforms.color.value = color;
}
if(meshRef.current.material && borderColor) {
meshRef.current.material.uniforms.borderColor.value = borderColor;
}
})
return (
<mesh
ref={meshRef}
{...props}
>
<boxBufferGeometry args={[1, 1, 1]} />
{/* @ts-ignore */}
<colorShiftMaterial key={ColorShiftMaterial.key} time={3} />
</mesh>
)
}
export default Shader
import * as THREE from 'three'
import dynamic from 'next/dynamic'
// import Shader from '@/components/canvas/Shader/Shader'
// Dynamic import is used to prevent a payload when the website start that will include threejs r3f etc..
// WARNING ! errors might get obfuscated by using dynamic import.
// If something goes wrong go back to a static import to show the error.
// https://github.com/pmndrs/react-three-next/issues/49
const Shader = dynamic(() => import('@/components/canvas/Shader/Shader'), {
ssr: false,
})
// dom components goes here
const DOM = () => {
return (
<></>
)
}
// canvas components goes here
const R3F = ({r3f = true}) => {
return (
<>
<Shader
color={new THREE.Color(8/255, 108/255, 149/255)}
borderColor={new THREE.Color(0.9,0.9,0.9)}
position={[-1,0,0]}
/>
<Shader
color={new THREE.Color(149/255, 108/255, 8/255)}
borderColor={new THREE.Color(0.9,0.9,0.9)}
position={[1,0,0]}
/>
</>
)
}
const Page = () => {
return (
<>
<DOM />
<R3F r3f />
</>
)
}
export default Page
export async function getStaticProps() {
return {
props: {
title: 'Index',
},
}
}
uniform vec3 color;
uniform vec3 borderColor;
uniform float borderWidth;
uniform float gridSize;
uniform float gridWidth;
varying vec2 vUv;
float grid(vec2 st, float res)
{
vec2 grid = fract(st*res);
return (step(res,grid.x) * step(res,grid.y));
}
void main() {
vec3 red = vec3(1,0,0);
vec4 finalColor;
// We basically go through the X and Y values to see if they're less than the threshold
// UV goes from 0 to 1, so as X travels from 0 to 1
// we "limit" the color to when X is less than the borderWidth
// e.g. 0-0.1 = colored, 0.1-1.0 - not colored
// But we also get the opposite corners by taking the borderWidth and subtracting from 1.0 (the max)
if (vUv.x <= borderWidth || vUv.y <= borderWidth || vUv.x >= 1.0 - borderWidth || vUv.y >= 1.0 - borderWidth)
{
finalColor = vec4(borderColor, 1.);
} else {
// And we "fill in" the "background" with another color
finalColor = vec4(color, 1.);
}
// UV goes from 0-1, so we need to break it up into a grid
// We do that by "dividing" 1 by the number of grid segments we need (e.g. 2 for 2x2 grid)
if(fract(vUv.x / gridSize) < gridWidth || fract(vUv.y / gridSize) < gridWidth)
finalColor = finalColor / vec4(0.9,0.9,0.9, 1);
// This makes a small square 1/4 the size (but fills color inversely? if that makes sense)
// if (vUv.x* 2.0 <= borderWidth || vUv.y* 2.0 <= borderWidth || vUv.x* 2.0 >= 1.0 - borderWidth || vUv.y* 2.0 >= 1.0 - borderWidth)
// {
// // finalColor = vec4(borderColor * vec3(0.3,0.3,0.3), 1.);
// finalColor = vec4(red, 1.);
// }
gl_FragColor.rgba = finalColor;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment