r3f-materials

Three.js materials in R3F, built-in materials (Standard, Physical, Basic, etc.), ShaderMaterial with custom GLSL, uniforms binding and animation, and material properties. Use when choosing materials, creating custom shaders, or binding dynamic uniforms.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "r3f-materials" with this command: npx skills add bbeierle12/skill-mcp-claude/bbeierle12-skill-mcp-claude-r3f-materials

R3F Materials

Materials define surface appearance—color, texture, reflectivity, transparency, and custom shader effects.

Quick Start

// Built-in material
<mesh>
  <boxGeometry />
  <meshStandardMaterial color="hotpink" metalness={0.8} roughness={0.2} />
</mesh>

// Custom shader
<mesh>
  <planeGeometry />
  <shaderMaterial
    uniforms={{ uTime: { value: 0 } }}
    vertexShader={vertexShader}
    fragmentShader={fragmentShader}
  />
</mesh>

Built-in Materials

Material Comparison

MaterialLightingUse CasePerformance
MeshBasicMaterialNoneUI, unlit, debugFastest
MeshStandardMaterialPBRGeneral 3DGood
MeshPhysicalMaterialPBR+Glass, car paintSlower
MeshLambertMaterialDiffuseMatte surfacesFast
MeshPhongMaterialSpecularShiny plasticFast
MeshToonMaterialCel-shadedStylizedGood
MeshNormalMaterialNoneDebug normalsFastest
MeshDepthMaterialNoneDepth passesFastest

MeshBasicMaterial (Unlit)

<meshBasicMaterial
  color="#ff0000"           // Base color
  map={texture}             // Color texture
  transparent={true}        // Enable transparency
  opacity={0.5}             // Transparency level
  alphaMap={alphaTexture}   // Transparency texture
  side={THREE.DoubleSide}   // Render both sides
  wireframe={true}          // Wireframe mode
  fog={false}               // Ignore scene fog
/>

MeshStandardMaterial (PBR)

<meshStandardMaterial
  // Base
  color="#ffffff"
  map={colorTexture}
  
  // PBR properties
  metalness={0.5}           // 0 = dielectric, 1 = metal
  metalnessMap={metalMap}
  roughness={0.5}           // 0 = mirror, 1 = diffuse
  roughnessMap={roughMap}
  
  // Normal mapping
  normalMap={normalTexture}
  normalScale={[1, 1]}
  
  // Ambient occlusion
  aoMap={aoTexture}
  aoMapIntensity={1}
  
  // Displacement
  displacementMap={dispMap}
  displacementScale={0.1}
  
  // Emission
  emissive="#000000"
  emissiveMap={emissiveTexture}
  emissiveIntensity={1}
  
  // Environment
  envMap={cubeTexture}
  envMapIntensity={1}
/>

MeshPhysicalMaterial (Advanced PBR)

<meshPhysicalMaterial
  // Inherits all MeshStandardMaterial props, plus:
  
  // Clearcoat (car paint, lacquer)
  clearcoat={1}
  clearcoatRoughness={0.1}
  clearcoatNormalMap={ccNormal}
  
  // Transmission (glass, water)
  transmission={0.9}        // 0 = opaque, 1 = fully transmissive
  thickness={0.5}           // Volume thickness
  ior={1.5}                 // Index of refraction
  
  // Sheen (fabric, velvet)
  sheen={1}
  sheenRoughness={0.5}
  sheenColor="#ff00ff"
  
  // Iridescence (soap bubbles, oil slicks)
  iridescence={1}
  iridescenceIOR={1.3}
  iridescenceThicknessRange={[100, 400]}
/>

MeshToonMaterial (Cel-shaded)

<meshToonMaterial
  color="#6fa8dc"
  gradientMap={gradientTexture}  // 3-5 color ramp texture
/>

// Create gradient texture
const gradientTexture = useMemo(() => {
  const canvas = document.createElement('canvas');
  canvas.width = 4;
  canvas.height = 1;
  const ctx = canvas.getContext('2d')!;
  
  // 4-step toon shading
  ctx.fillStyle = '#444'; ctx.fillRect(0, 0, 1, 1);
  ctx.fillStyle = '#888'; ctx.fillRect(1, 0, 1, 1);
  ctx.fillStyle = '#bbb'; ctx.fillRect(2, 0, 1, 1);
  ctx.fillStyle = '#fff'; ctx.fillRect(3, 0, 1, 1);
  
  const texture = new THREE.CanvasTexture(canvas);
  texture.minFilter = THREE.NearestFilter;
  texture.magFilter = THREE.NearestFilter;
  
  return texture;
}, []);

Common Properties (All Materials)

<meshStandardMaterial
  // Rendering
  transparent={false}
  opacity={1}
  alphaTest={0}           // Discard pixels below threshold
  alphaToCoverage={false} // MSAA alpha
  
  // Faces
  side={THREE.FrontSide}  // FrontSide | BackSide | DoubleSide
  
  // Depth
  depthTest={true}
  depthWrite={true}
  
  // Stencil
  stencilWrite={false}
  stencilFunc={THREE.AlwaysStencilFunc}
  
  // Blending
  blending={THREE.NormalBlending}
  
  // Other
  visible={true}
  fog={true}
  toneMapped={true}
/>

Textures

Loading Textures

import { useTexture } from '@react-three/drei';

function TexturedMesh() {
  const [colorMap, normalMap, roughnessMap] = useTexture([
    '/textures/color.jpg',
    '/textures/normal.jpg',
    '/textures/roughness.jpg'
  ]);
  
  return (
    <mesh>
      <boxGeometry />
      <meshStandardMaterial 
        map={colorMap}
        normalMap={normalMap}
        roughnessMap={roughnessMap}
      />
    </mesh>
  );
}

Texture Settings

import { useTexture } from '@react-three/drei';
import * as THREE from 'three';

const texture = useTexture('/texture.jpg', (tex) => {
  tex.wrapS = tex.wrapT = THREE.RepeatWrapping;
  tex.repeat.set(4, 4);
  tex.anisotropy = 16;  // Sharper at angles
});

ShaderMaterial

Full control via GLSL vertex and fragment shaders:

import { useRef } from 'react';
import { useFrame } from '@react-three/fiber';
import * as THREE from 'three';

const vertexShader = `
  varying vec2 vUv;
  varying vec3 vNormal;
  
  void main() {
    vUv = uv;
    vNormal = normalize(normalMatrix * normal);
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
  }
`;

const fragmentShader = `
  uniform float uTime;
  uniform vec3 uColor;
  varying vec2 vUv;
  varying vec3 vNormal;
  
  void main() {
    float pulse = sin(uTime * 2.0) * 0.5 + 0.5;
    vec3 color = mix(uColor, vec3(1.0), pulse * 0.3);
    
    // Simple rim lighting
    float rim = 1.0 - dot(vNormal, vec3(0.0, 0.0, 1.0));
    color += rim * 0.5;
    
    gl_FragColor = vec4(color, 1.0);
  }
`;

function CustomShaderMesh() {
  const materialRef = useRef<THREE.ShaderMaterial>(null!);
  
  useFrame(({ clock }) => {
    materialRef.current.uniforms.uTime.value = clock.elapsedTime;
  });
  
  return (
    <mesh>
      <sphereGeometry args={[1, 32, 32]} />
      <shaderMaterial
        ref={materialRef}
        vertexShader={vertexShader}
        fragmentShader={fragmentShader}
        uniforms={{
          uTime: { value: 0 },
          uColor: { value: new THREE.Color('#ff6b6b') }
        }}
      />
    </mesh>
  );
}

Uniforms

Uniform Types

uniforms={{
  // Scalars
  uFloat: { value: 1.0 },
  uInt: { value: 1 },
  uBool: { value: true },
  
  // Vectors
  uVec2: { value: new THREE.Vector2(1, 2) },
  uVec3: { value: new THREE.Vector3(1, 2, 3) },
  uVec4: { value: new THREE.Vector4(1, 2, 3, 4) },
  uColor: { value: new THREE.Color('#ff0000') },
  
  // Matrices
  uMat3: { value: new THREE.Matrix3() },
  uMat4: { value: new THREE.Matrix4() },
  
  // Textures
  uTexture: { value: texture },
  uCubeTexture: { value: cubeTexture },
  
  // Arrays
  uFloatArray: { value: [1.0, 2.0, 3.0] },
  uVec3Array: { value: [new THREE.Vector3(), new THREE.Vector3()] }
}}

Animating Uniforms

function AnimatedShader() {
  const materialRef = useRef<THREE.ShaderMaterial>(null!);
  
  useFrame(({ clock, mouse }) => {
    const uniforms = materialRef.current.uniforms;
    
    uniforms.uTime.value = clock.elapsedTime;
    uniforms.uMouse.value.set(mouse.x, mouse.y);
    uniforms.uResolution.value.set(window.innerWidth, window.innerHeight);
  });
  
  return (
    <shaderMaterial
      ref={materialRef}
      uniforms={{
        uTime: { value: 0 },
        uMouse: { value: new THREE.Vector2() },
        uResolution: { value: new THREE.Vector2() }
      }}
      // ...
    />
  );
}

Shared Uniforms

// Create shared uniform object
const globalUniforms = useMemo(() => ({
  uTime: { value: 0 },
  uGlobalColor: { value: new THREE.Color('#00ff00') }
}), []);

// Update in useFrame
useFrame(({ clock }) => {
  globalUniforms.uTime.value = clock.elapsedTime;
});

// Use in multiple materials
<mesh>
  <boxGeometry />
  <shaderMaterial uniforms={{ ...globalUniforms, uLocalProp: { value: 1 } }} />
</mesh>

<mesh position={[2, 0, 0]}>
  <sphereGeometry />
  <shaderMaterial uniforms={{ ...globalUniforms, uLocalProp: { value: 2 } }} />
</mesh>

RawShaderMaterial

No built-in uniforms/attributes—full control:

<rawShaderMaterial
  vertexShader={`
    precision highp float;
    
    // Must declare all inputs manually
    attribute vec3 position;
    attribute vec2 uv;
    
    uniform mat4 projectionMatrix;
    uniform mat4 modelViewMatrix;
    
    varying vec2 vUv;
    
    void main() {
      vUv = uv;
      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
  `}
  fragmentShader={`
    precision highp float;
    
    varying vec2 vUv;
    
    void main() {
      gl_FragColor = vec4(vUv, 0.0, 1.0);
    }
  `}
/>

Material Extensions

Extend Existing Materials

import { extend } from '@react-three/fiber';
import { shaderMaterial } from '@react-three/drei';

// Create extended material
const GradientMaterial = shaderMaterial(
  // Uniforms
  { uColorA: new THREE.Color('#ff0000'), uColorB: new THREE.Color('#0000ff') },
  // Vertex
  `
    varying vec2 vUv;
    void main() {
      vUv = uv;
      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
  `,
  // Fragment
  `
    uniform vec3 uColorA;
    uniform vec3 uColorB;
    varying vec2 vUv;
    void main() {
      gl_FragColor = vec4(mix(uColorA, uColorB, vUv.y), 1.0);
    }
  `
);

// Register with R3F
extend({ GradientMaterial });

// Use in JSX
function Gradient() {
  return (
    <mesh>
      <planeGeometry args={[2, 2]} />
      <gradientMaterial uColorA="#ff0000" uColorB="#0000ff" />
    </mesh>
  );
}

Performance Tips

TechniqueWhen to Use
Share materialsMultiple meshes, same appearance
Use cheaper materialsDistant objects (Basic vs Standard)
Limit texture sizeMobile, large scene
Disable unneeded featuresfog={false}, toneMapped={false}

Material Reuse

// Define once
const sharedMaterial = useMemo(() => (
  <meshStandardMaterial color="red" roughness={0.5} />
), []);

// Reuse (same GPU program)
{items.map((item, i) => (
  <mesh key={i} position={item.pos}>
    <boxGeometry />
    {sharedMaterial}
  </mesh>
))}

File Structure

r3f-materials/
├── SKILL.md
├── references/
│   ├── pbr-properties.md     # PBR material deep-dive
│   ├── uniform-types.md      # Complete uniform reference
│   └── shader-templates.md   # Common shader patterns
└── scripts/
    ├── materials/
    │   ├── gradient.ts       # Gradient shader material
    │   ├── fresnel.ts        # Fresnel/rim effect
    │   └── dissolve.ts       # Dissolve effect
    └── utils/
        └── uniform-helpers.ts # Uniform animation utilities

Reference

  • references/pbr-properties.md — Deep-dive into PBR material properties
  • references/uniform-types.md — All uniform types and GLSL mappings
  • references/shader-templates.md — Common shader effect patterns

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

gsap-react

No summary provided by upstream source.

Repository SourceNeeds Review
General

gsap-scrolltrigger

No summary provided by upstream source.

Repository SourceNeeds Review
General

gsap-fundamentals

No summary provided by upstream source.

Repository SourceNeeds Review
General

gsap-sequencing

No summary provided by upstream source.

Repository SourceNeeds Review