Skip to content

Commit

Permalink
feat: working example
Browse files Browse the repository at this point in the history
  • Loading branch information
piellardj authored and Sceat committed Oct 2, 2024
1 parent 4e8695a commit e521c46
Show file tree
Hide file tree
Showing 13 changed files with 90 additions and 62 deletions.
4 changes: 2 additions & 2 deletions src/lib/effects/billboard/gpu/gpu-textures-state.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { createFullscreenQuad } from "../../../helpers/fullscreen-quad";
import { createFullscreenQuad } from '../../../helpers/fullscreen-quad';
import * as THREE from '../../../libs/three-usage';

type UniformType = 'sampler2D' | 'float' | 'vec2' | 'vec3' | 'vec4';
Expand Down Expand Up @@ -39,7 +39,7 @@ class GpuTexturesState {

this.textureNames = params.textureNames;

this.fullscreenQuad = createFullscreenQuad("aPosition");
this.fullscreenQuad = createFullscreenQuad('aPosition');

const vertexShader = `
in vec2 aPosition;
Expand Down
67 changes: 44 additions & 23 deletions src/lib/helpers/customizable-texture.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as THREE from "../libs/three-usage";
import * as THREE from '../libs/three-usage';

import { createFullscreenQuad } from "./fullscreen-quad";
import { createFullscreenQuad } from './fullscreen-quad';

type Parameters = {
readonly width: number;
Expand All @@ -22,12 +22,13 @@ class CustomizableTexture {

private readonly renderTarget: THREE.WebGLRenderTarget;
private readonly fakeCamera = new THREE.PerspectiveCamera();
private readonly fullscreenQuad = createFullscreenQuad("aPosition");
private readonly fullscreenQuad = createFullscreenQuad('aPosition');
private readonly applyLayer: {
readonly shader: THREE.RawShaderMaterial;
readonly uniforms: {
readonly layer: THREE.IUniform<THREE.Texture | null>;
readonly color: THREE.IUniform<THREE.Color>;
readonly flipY: THREE.IUniform<number>;
};
};

Expand All @@ -36,11 +37,15 @@ class CustomizableTexture {

const layers = new Map<string, TextureLayer>();
for (const [name, texture] of params.additionalTextures.entries()) {
layers.set(name, { texture, color: new THREE.Color(0xFFFFFF) });
layers.set(name, { texture, color: new THREE.Color(0xffffff) });
}
this.layers = layers;

this.renderTarget = new THREE.WebGLRenderTarget(params.width, params.height, {
wrapS: this.baseTexture.wrapS,
wrapT: this.baseTexture.wrapT,
magFilter: this.baseTexture.magFilter,
// minFilter: this.baseTexture.minFilter,
depthBuffer: false,
});
const texture = this.renderTarget.textures[0];
Expand All @@ -51,23 +56,36 @@ class CustomizableTexture {

const uniforms = {
layer: { value: null },
color: { value: new THREE.Color(0xFFFFFF) },
color: { value: new THREE.Color(0xffffff) },
flipY: { value: 0 },
};

const shader = new THREE.RawShaderMaterial({
glslVersion: "300 es",
glslVersion: '300 es',
depthTest: false,
blending: THREE.CustomBlending,
blendSrc: THREE.SrcAlphaFactor,
blendDst: THREE.OneMinusSrcAlphaFactor,
blendSrcAlpha: THREE.ZeroFactor,
blendDstAlpha: THREE.OneFactor,
uniforms: {
uLayerTexture: uniforms.layer,
uLayerColor: uniforms.color,
uFlipY: uniforms.flipY,
},
vertexShader: `
uniform float uFlipY;
in vec2 aPosition;
out vec2 vUv;
void main() {
vUv = aPosition;
gl_Position = vec4(2.0 * aPosition - 1.0, 0, 1);
vUv = vec2(
aPosition.x,
mix(aPosition.y, 1.0 - aPosition.y, uFlipY)
);
}`,
fragmentShader: `
precision mediump float;
Expand All @@ -77,15 +95,17 @@ uniform vec3 uLayerColor;
in vec2 vUv;
(layout location = 0) out vec4 fragColor;
layout(location = 0) out vec4 fragColor;
void main() {
vec4 sample = texture(uLayerTexture, vUv);
// sample.rgb *= uLayerColor;
fragColor = sample + vec4(0, 1, 0, 1);
vec4 sampled = texture(uLayerTexture, vUv);
if (sampled.a < 0.5) discard;
sampled.rgb *= uLayerColor;
fragColor = sampled;
}
`,
});
this.fullscreenQuad.material = shader;

this.applyLayer = { shader, uniforms };
}
Expand All @@ -94,7 +114,7 @@ void main() {
const layer = this.layers.get(layerName);
if (!layer) {
const layerNames = Array.from(this.layers.keys());
throw new Error(`Unknown layer name "${layerName}". Layer names are: ${layerNames.join("; ")}.`);
throw new Error(`Unknown layer name "${layerName}". Layer names are: ${layerNames.join('; ')}.`);
}

if (layer.color.equals(color)) {
Expand All @@ -114,20 +134,24 @@ void main() {
};

renderer.setRenderTarget(this.renderTarget);
renderer.setClearColor(0xFF0000, 0);
renderer.setClearColor(0x000000, 0);
renderer.autoClear = false;
renderer.autoClearColor = false;
renderer.clear(true);

this.applyLayer.uniforms.layer.value = this.baseTexture;
this.applyLayer.uniforms.color.value = new THREE.Color(0xFFFFFF);
this.applyLayer.uniforms.color.value = new THREE.Color(0xffffff);
this.applyLayer.uniforms.flipY.value = Number(this.baseTexture.flipY);
this.applyLayer.shader.uniformsNeedUpdate = true;
renderer.render(this.fullscreenQuad, this.fakeCamera);

// for (const layer of this.layers.values()) {
// this.applyLayer.uniforms.layer.value = layer.texture;
// this.applyLayer.uniforms.color.value = layer.color;
// renderer.render(this.fullscreenQuad, this.fakeCamera);
// }
for (const layer of this.layers.values()) {
this.applyLayer.uniforms.layer.value = layer.texture;
this.applyLayer.uniforms.color.value = layer.color;
this.applyLayer.uniforms.flipY.value = Number(layer.texture.flipY);
this.applyLayer.shader.uniformsNeedUpdate = true;
renderer.render(this.fullscreenQuad, this.fakeCamera);
}

renderer.setRenderTarget(previousState.renderTarget);
renderer.setClearColor(previousState.clearColor);
Expand All @@ -137,7 +161,4 @@ void main() {
}
}

export {
CustomizableTexture
};

export { CustomizableTexture };
6 changes: 2 additions & 4 deletions src/lib/helpers/fullscreen-quad.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as THREE from "../libs/three-usage";
import * as THREE from '../libs/three-usage';

function createFullscreenQuad(attributeName: string): THREE.Mesh {
const fullscreenQuadGeometry = new THREE.BufferGeometry();
Expand All @@ -9,6 +9,4 @@ function createFullscreenQuad(attributeName: string): THREE.Mesh {
return fullscreenQuad;
}

export {
createFullscreenQuad,
};
export { createFullscreenQuad };
8 changes: 4 additions & 4 deletions src/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,19 @@ export {
type ILocalMapData,
type IVoxelMap,
type IVoxelMaterial,
type VoxelsChunkSize
type VoxelsChunkSize,
} from './terrain/voxelmap/i-voxelmap';
export {
VoxelmapViewerAutonomous,
type VoxelmapViewerAutonomousOptions
type VoxelmapViewerAutonomousOptions,
} from './terrain/voxelmap/viewer/autonomous/voxelmap-viewer-autonomous';
export {
EComputationMethod,
VoxelmapViewer,
type ComputationOptions,
type ComputationStatus,
type VoxelmapViewerOptions,
type VoxelsChunkData
type VoxelsChunkData,
} from './terrain/voxelmap/viewer/simple/voxelmap-viewer';
export { VoxelmapVisibilityComputer } from './terrain/voxelmap/voxelmap-visibility-computer';
export { type CheckerboardType } from './terrain/voxelmap/voxelsRenderable/voxelsRenderableFactory/voxels-renderable-factory-base';
Expand All @@ -36,4 +36,4 @@ export { Rain } from './effects/weather/rain';
export { Snow } from './effects/weather/snow';
export { GpuInstancedBillboard } from './effects/weather/weather-particles-base';

export { CustomizableTexture } from "./helpers/customizable-texture";
export { CustomizableTexture } from './helpers/customizable-texture';
5 changes: 5 additions & 0 deletions src/lib/libs/three-usage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export {
Box3,
BufferGeometry,
Color,
CustomBlending,
DataTexture,
Float32BufferAttribute,
Group,
Expand All @@ -18,6 +19,8 @@ export {
MeshPhongMaterial,
NoBlending,
NormalBlending,
OneFactor,
OneMinusSrcAlphaFactor,
PerspectiveCamera,
PlaneGeometry,
RawShaderMaterial,
Expand All @@ -26,6 +29,7 @@ export {
RGBAFormat,
ShaderMaterial,
Sphere,
SrcAlphaFactor,
Texture,
TextureLoader,
Uint32BufferAttribute,
Expand All @@ -34,6 +38,7 @@ export {
Vector3,
Vector4,
WebGLRenderTarget,
ZeroFactor,
type Frustum,
type IUniform,
type Material,
Expand Down
2 changes: 1 addition & 1 deletion src/lib/terrain/voxelmap/i-voxelmap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ interface ILocalMapData {
* Each element in the array represent a coordinate in the map and stores the data of the voxel at these coordinates.
* Each element should be encoded as follows:
* - bit 0: 0 if the voxel is empty, 1 otherwise
* - bit 1: 1 if the voxel should be displayed as cheesserboard, 0 otherwise
* - bit 1: 1 if the voxel should be displayed as checkerboard, 0 otherwise
* - bits 2-13: ID of the material
* Use the helper "voxelmapDataPacking" to do this encoding and be future-proof.
*
Expand Down
2 changes: 1 addition & 1 deletion src/test/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ function createVoxelMap(): VoxelMap {
const mapScaleY = 200;
const mapSeed = 'fixed_seed';
const includeTreesInLod = false;

return new VoxelMap(mapScaleXZ, mapScaleY, mapSeed, includeTreesInLod);
}

Expand Down
58 changes: 31 additions & 27 deletions src/test/test-texture-customization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ class TestTextureCustomization extends TestBase {
private readonly parameters = {
color1: 0xff0000,
color2: 0x00ff00,
color3: 0x0000ff,
};

private customizableTexture: CustomizableTexture | null = null;
Expand All @@ -26,14 +25,15 @@ class TestTextureCustomization extends TestBase {
gridHelper.position.setY(-0.01);
this.scene.add(gridHelper);

const ambientLight = new THREE.AmbientLight(0xCCCCCC);
const ambientLight = new THREE.AmbientLight(0xffffff);
this.scene.add(ambientLight);

const enforceColors = () => { this.enforceColors(); };
const enforceColors = () => {
this.enforceColors();
};
this.gui = new GUI();
this.gui.addColor(this.parameters, "color1").onChange(enforceColors);
this.gui.addColor(this.parameters, "color2").onChange(enforceColors);
this.gui.addColor(this.parameters, "color3").onChange(enforceColors);
this.gui.addColor(this.parameters, 'color1').onChange(enforceColors);
this.gui.addColor(this.parameters, 'color2').onChange(enforceColors);
enforceColors();

const gltfLoader = new THREE.GLTFLoader();
Expand All @@ -42,41 +42,45 @@ class TestTextureCustomization extends TestBase {
dracoLoader.setDecoderConfig({ type: 'js' });
gltfLoader.setDRACOLoader(dracoLoader);

gltfLoader.load("/resources/character/primemachin.glb", gltf => {
Promise.all([
gltfLoader.loadAsync('/resources/character/iop_male.glb'),
new THREE.TextureLoader().loadAsync('/resources/character/color_01.png'),
new THREE.TextureLoader().loadAsync('/resources/character/color_02.png'),
]).then(([gltf, color1Texture, color2Texture]) => {
this.scene.add(gltf.scene);

gltf.scene.traverse(child => {
if ((child as any).isMesh) {
const childMesh = child as THREE.Mesh;
const childMaterial = childMesh.material as THREE.MeshPhongMaterial;

setTimeout(() => {
const childTexture = childMaterial.map;
if (!childTexture) {
throw new Error("No base texture");
}
this.customizableTexture = new CustomizableTexture({
width: 100,
height: 100,
baseTexture: childTexture,
additionalTextures: new Map<string, THREE.Texture>(),
});
this.customizableTexture.update(this.renderer);
childMaterial.map = this.customizableTexture.texture;
}, 2000);
const childTexture = childMaterial.map;
if (!childTexture) {
throw new Error('No base texture');
}

this.customizableTexture = new CustomizableTexture({
width: 128,
height: 256,
baseTexture: childTexture,
additionalTextures: new Map<string, THREE.Texture>([
['color1', color1Texture],
['color2', color2Texture],
]),
});
this.enforceColors();
childMaterial.map = this.customizableTexture.texture;
}
})
});
});
}

protected override update(): void {
}
protected override update(): void {}

private enforceColors(): void {
if (this.customizableTexture) {
// this.customizableTexture.setLayerColor("color1", new THREE.Color(this.parameters.color1));
// this.customizableTexture.setLayerColor("color2", new THREE.Color(this.parameters.color2));
// this.customizableTexture.setLayerColor("color3", new THREE.Color(this.parameters.color3));
this.customizableTexture.setLayerColor('color1', new THREE.Color(this.parameters.color1));
this.customizableTexture.setLayerColor('color2', new THREE.Color(this.parameters.color2));
this.customizableTexture.update(this.renderer);
}
}
Expand Down
Binary file added test/resources/character/char01male.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added test/resources/character/color_01.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added test/resources/character/color_02.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added test/resources/character/iop_male.glb
Binary file not shown.
Binary file removed test/resources/character/primemachin.glb
Binary file not shown.

0 comments on commit e521c46

Please sign in to comment.