Three.js Rendering & Texture System
Is Three.js the Right Choice?
Yes, Three.js is an excellent choice for your requirements. Here's why:
Three.js Strengths
- Web-Based: Runs in browsers, no plugins needed
- Texture Support: Excellent support for textures, materials, and decals
- Text Rendering: Can render text on 3D surfaces via:
- Canvas textures (render text to canvas, apply as texture)
- SVG textures
- Decal systems (project textures onto surfaces)
- HTML overlays (for UI elements)
- Material System: Supports PBR (Physically Based Rendering) materials
- Performance: Hardware-accelerated via WebGL
- Ecosystem: Large community, extensive documentation
- Mobile Support: Works on mobile devices
Architecture Overview
3D Modeling Pipeline:
- Model Creation: Models created in external tools (Blender, Maya, 3ds Max, etc.)
- Export: Models exported to GLTF/GLB format (industry standard)
- Storage: GLTF/GLB files stored in S3/CDN
- Rendering: Three.js loads and renders models in browser
- Customization: Textures, decals, and text applied dynamically
Texture & Customization System
ModelTexture Entity
Supports multiple customization types:
1. Paint Jobs
var paintJob = new ModelTexture
{
BoatId = boatId,
TextureType = TextureType.PaintJob,
PaintJobName = "Custom Blue Flake",
PaintType = "Metallic",
BaseColor = "#0066CC",
Metallic = 0.8f,
Roughness = 0.2f,
IsCustomPaintJob = true
};
2. Brand Logos/Decals
var brandDecal = new ModelTexture
{
BoatId = boatId,
TextureType = TextureType.BrandLogo,
DecalType = DecalType.BrandLogo,
BrandId = rangerBrandId,
BrandName = "Ranger",
TextureUrl = "https://cdn.example.com/decals/ranger-logo.png",
PlacementLocation = "Transom",
PositionX = 0.5f, // Center
PositionY = 0.8f, // Near bottom
HasBrandLicense = true,
BrandLicenseInfo = "Licensed dealer - License #12345"
};
3. User-Created Boat Names
var boatName = new ModelTexture
{
BoatId = boatId,
TextureType = TextureType.UserText,
DecalType = DecalType.UserText,
UserText = "The Reel Deal",
FontFamily = "Arial",
FontSize = 48,
FontColor = "#FFFFFF",
FontStyle = "bold",
TextAlignment = TextAlignment.Center,
PlacementLocation = "Transom",
PositionX = 0.5f, // Center
PositionY = 0.7f,
Rotation = 0f,
ScaleX = 1.0f,
ScaleY = 1.0f
};
4. Custom Images/Decals
var customDecal = new ModelTexture
{
BoatId = boatId,
TextureType = TextureType.Decal,
DecalType = DecalType.CustomImage,
TextureUrl = "https://s3.amazonaws.com/user-uploads/decal-123.png",
PlacementLocation = "Port Side",
PositionX = 0.3f,
PositionY = 0.5f,
ScaleX = 0.5f,
ScaleY = 0.5f
};
Three.js Implementation Examples
Rendering Text on 3D Surface (Boat Name)
// Option 1: Canvas Texture (Recommended)
function createTextTexture(text, font, fontSize, color) {
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
// Set canvas size based on text
context.font = `${fontSize}px ${font}`;
const metrics = context.measureText(text);
canvas.width = metrics.width + 20;
canvas.height = fontSize + 20;
// Draw text
context.fillStyle = color;
context.font = `${fontSize}px ${font}`;
context.fillText(text, 10, fontSize + 10);
// Create texture
const texture = new THREE.CanvasTexture(canvas);
texture.needsUpdate = true;
return texture;
}
// Option 2: SVG Texture (Better quality, scalable)
function createSVGTexture(text, font, fontSize, color) {
const svg = `
<svg xmlns="http://www.w3.org/2000/svg" width="400" height="100">
<text x="50%" y="50%" font-family="${font}" font-size="${fontSize}"
fill="${color}" text-anchor="middle" dominant-baseline="middle">
${text}
</text>
</svg>
`;
const blob = new Blob([svg], { type: 'image/svg+xml' });
const url = URL.createObjectURL(blob);
const texture = new THREE.TextureLoader().load(url);
return texture;
}
// Option 3: Decal System (Project onto surface)
import { DecalGeometry } from 'three/examples/jsm/geometries/DecalGeometry.js';
function applyDecal(mesh, texture, position, rotation, scale) {
const decalGeometry = new DecalGeometry(
mesh,
position,
rotation,
scale
);
const decalMaterial = new THREE.MeshPhongMaterial({
map: texture,
transparent: true,
depthTest: true,
depthWrite: false,
polygonOffset: true,
polygonOffsetFactor: -4
});
const decal = new THREE.Mesh(decalGeometry, decalMaterial);
scene.add(decal);
}
Applying Paint Job
// Load base model
const loader = new THREE.GLTFLoader();
loader.load('boat-model.glb', (gltf) => {
const boat = gltf.scene;
// Apply custom paint job
boat.traverse((child) => {
if (child.isMesh) {
// Update material properties
child.material.color.setHex(0x0066CC); // Blue
child.material.metalness = 0.8;
child.material.roughness = 0.2;
// Or load custom texture
const textureLoader = new THREE.TextureLoader();
textureLoader.load('custom-paint-job.jpg', (texture) => {
child.material.map = texture;
child.material.needsUpdate = true;
});
}
});
scene.add(boat);
});
Applying Brand Decals
function applyBrandDecal(boatMesh, decalData) {
const { textureUrl, position, rotation, scale } = decalData;
// Load decal texture
const textureLoader = new THREE.TextureLoader();
textureLoader.load(textureUrl, (texture) => {
// Create decal
const decalGeometry = new DecalGeometry(
boatMesh,
new THREE.Vector3(position.x, position.y, position.z),
new THREE.Euler(rotation.x, rotation.y, rotation.z),
new THREE.Vector3(scale.x, scale.y, scale.z)
);
const decalMaterial = new THREE.MeshPhongMaterial({
map: texture,
transparent: true,
opacity: 1.0
});
const decal = new THREE.Mesh(decalGeometry, decalMaterial);
scene.add(decal);
});
}
Brand Licensing
License Tracking
The ModelTexture entity includes:
HasBrandLicense: Boolean flag indicating user has licenseBrandLicenseInfo: License details (number, expiration, etc.)BrandId: Link to brand entity
License Validation
// Check if user can display brand logo
public bool CanDisplayBrandLogo(Guid userId, Guid brandId)
{
var texture = context.ModelTextures
.FirstOrDefault(mt => mt.UserId == userId &&
mt.BrandId == brandId &&
mt.DecalType == DecalType.BrandLogo);
return texture?.HasBrandLicense == true;
}
// Validate license before displaying
public bool ValidateBrandLicense(Guid userId, Guid brandId, string licenseNumber)
{
// Check against license database or API
// This would integrate with brand licensing system
return true; // Placeholder
}
UV Mapping
UV maps define which part of the texture applies to which part of the model:
- Hull: Main boat body
- Deck: Top surface
- Transom: Back of boat (where boat name goes)
- Port Side: Left side
- Starboard Side: Right side
- Bow: Front of boat
The UvMapName field stores which UV map to use, and UvMappingJson can store custom UV coordinates if needed.
Material Properties
Three.js supports PBR (Physically Based Rendering) materials:
- BaseColor: Base color of the material
- Metallic: How metallic the surface is (0.0 = non-metallic, 1.0 = metallic)
- Roughness: Surface roughness (0.0 = mirror-like, 1.0 = matte)
- Opacity: Transparency (0.0 = transparent, 1.0 = opaque)
- Normal Map: Surface detail (bumps, scratches)
- Roughness Map: Variable roughness across surface
- Metallic Map: Variable metallic properties
Performance Considerations
- Texture Compression: Use compressed texture formats (KTX2, Basis)
- LOD (Level of Detail): Multiple detail levels for different distances
- Texture Atlasing: Combine multiple textures into one atlas
- Caching: Cache textures and models in browser
- Lazy Loading: Load textures on-demand
Alternative Rendering Engines
While Three.js is excellent, alternatives include:
- Babylon.js: More features, slightly steeper learning curve
- A-Frame: Higher-level, easier for simple scenes
- PlayCanvas: Game engine, more features but heavier
- Unity WebGL: Full game engine, exports to WebGL
Recommendation: Stick with Three.js for your use case - it's the most popular, well-documented, and has excellent texture/decal support.
Future Enhancements
- Texture Editor: In-browser texture painting tool
- Decal Library: Pre-made decals users can apply
- Paint Job Templates: Pre-configured paint job presets
- Brand License Marketplace: Users can purchase brand licenses
- 3D Text Editor: Visual editor for placing boat names
- Material Presets: Factory paint jobs, custom finishes