Easy methods to Create a PS1-Impressed Jitter Shader with React-Three-Fiber


This challenge demonstrates a customized jitter shader impressed by the visible fashion of PS1-era video games. The shader replicates the nostalgic ‘jitter’ impact, including a retro aesthetic to 3D fashions—good for builders trying so as to add a retro really feel to low-poly initiatives.

I’ve at all times discovered PS1 video games fascinating. Impressed by their nostalgic 3D environments, I made a decision to create a portfolio that captures this retro aesthetic. Nonetheless, whereas growing the parts, I observed a shortage of assets for net builders aiming to recreate this fashion. It’s time to carry a contact of nostalgia to the trendy net.

A little bit of background: The PS1 jitter impact outcomes from the console’s restricted precision in vertex calculations, resulting in the attribute “wobbling” of polygons. This was a byproduct of its fixed-point arithmetic and lack of sub-pixel accuracy, which, though seen as a limitation on the time, has now turn out to be a cherished visible quirk. That is particularly attention-grabbing for Indie video games and digital artwork that purpose to evoke nostalgia or discover lo-fi visuals.

Right here’s a video from the demo:

The Setup

Firstly, we create our stage.

import { Canvas } from "@react-three/fiber";


	
	

Next, we need to create a custom shader material based on the MeshStandardMaterial. The key here is ensuring it works with model animations and properly handles shadows.

The most important step is to adjust the default shader code using onBeforeCompile before compiling the shader.

In this modification process on the Vertex Shader, the X and Y coordinates of each vertex are scaled by uJitterLevel and rounded (using floor) on a specific grid. This creates the PS1-style jitter effect. Scaling the X and Y coordinates by uJitterLevel and applying floor() simulates the jitter effect by snapping vertex positions to a grid.

With the code we added in the Fragment Shader, we make the colors appear a bit more pale. Rendered colors can sometimes be too bright, so this can be useful when adjusting the shadow settings. Reducing color brightness with diffuseColor.rgb *= 0.8; is essential for achieving a more authentic retro look, as it helps mimic the limited color palette and lighting of older consoles. Additionally, the color settings can be expanded further if needed.

const createCustomMaterial = (color, jitterLevel, texture) => {
  return new THREE.MeshStandardMaterial({
    color,
    map: texture || null,
    onBeforeCompile: (shader) => {
      shader.uniforms.uJitterLevel = { value: jitterLevel };

      shader.vertexShader = `
        uniform float uJitterLevel;
        ${shader.vertexShader}
      `.replace(
        `#include `,
        `
          vec4 mvPosition = modelViewMatrix * vec4( transformed, 1.0 );
          gl_Position = projectionMatrix * mvPosition;

          gl_Position.xy /= gl_Position.w;
          gl_Position.xy = floor(gl_Position.xy * uJitterLevel) / uJitterLevel * gl_Position.w;
        `
      );

      shader.fragmentShader = shader.fragmentShader.replace(
        `vec4 diffuseColor = vec4( diffuse, opacity );`,
        `
         vec4 diffuseColor = vec4( diffuse, opacity );
         diffuseColor.rgb *= 0.8; // Little darker colors
        `
      );
    },
  });
};

Importing the model with textures

We need to select a model and export its textures. We will process these textures through the shader. The easiest option for exporting textures from the model is the glTF Report tool.

The Crash Bandicoot model I chose for this demo consists of several parts. This is particularly relevant because the models I used in my portfolio also consisted of separate parts for various reasons, requiring different solutions.

After making the model compatible with React Three Fiber using the gltfjsx tool, we can see that the model uses skinnedMesh because it contains animations.




After exporting the three texture photographs from the mannequin utilizing glTF.report, I eliminated the mannequin’s textures. Though textures don’t considerably have an effect on this mannequin, some textures could also be giant in dimension. This optimization helps to keep away from processing the textures twice. You’ll be able to delete the textures utilizing the glTF Report software.

For skinnedMesh supplies, we’ll now apply the customized shader operate we mentioned earlier. This enables us to include the textures we exported from the mannequin.

In case you are engaged on a easy mannequin with a single texture, it doesn’t have to be created individually. After that, we place our supplies within the skinnedMesh.

const [crashTextureOne, crashTextureTwo, crashTextureThree] = useTexture([
    "/textures/texture.png",
    "/textures/texture-1.png",
    "/textures/texture-2.png",
  ]);

  const crashMaterials = useMemo(() => {
    const baseColor = "#ffffff";
    const supplies = [
      createCustomMaterial(
        baseColor,
        jitterLevel,
        enableTexture ? crashTextureOne : null
      ),
      createCustomMaterial(
        baseColor,
        jitterLevel,
        enableTexture ? crashTextureTwo : null
      ),
      createCustomMaterial(
        baseColor,
        jitterLevel,
        enableTexture ? crashTextureThree : null
      ),
      createCustomMaterial(baseColor, jitterLevel)
    ];
    return supplies;
  }, [
    jitterLevel,
    enableTexture,
  ]);

By following these steps, we’ve efficiently built-in a customized jitter shader into our 3D mannequin, reaching the nostalgic aesthetic of PS1-era video games!

Thanks for studying!

Credit



Source link

Leave a Comment

Your email address will not be published. Required fields are marked *

error

Enjoy this blog? Please spread the word :)

YouTube
YouTube
Pinterest
fb-share-icon
LinkedIn
Share
Instagram
Index
Scroll to Top