I have a mesh with an onBeforeCompile
shader, and would like to prevent the image from stretching, like so
Issue is, I already have a predefined shader, and was wondering how I could integrate it into this code?
material.onBeforeCompile = shader => {
const custom_map_fragment = THREE.ShaderChunk.map_fragment.replace(
`diffuseColor *= sampledDiffuseColor;`,
`diffuseColor = vec4( mix( diffuse, sampledDiffuseColor.rgb, sampledDiffuseColor.a ), opacity );`
);
shader.fragmentShader = shader.fragmentShader.replace( '#include <map_fragment>', custom_map_fragment );
shader.uniforms.atlasDimensions = { value: new THREE.Vector2( ).copy( new THREE.Vector2(4, 4) ) };
shader.vertexShader = `
uniform vec2 atlasDimensions;
attribute float textureChunkIndex;
${shader.vertexShader}
`.replace(
`#include <uv_vertex>`,
`#include <uv_vertex>
float chunkId = floor(textureChunkIndex + 0.1);
vec2 idUV = vec2(mod(chunkId, atlasDimensions.x), floor(chunkId / atlasDimensions.x));
vec2 normalizedDimensions = 1. / atlasDimensions;
vUv = (uv + idUV) * normalizedDimensions;
`
);
}
Can you share picture of what you have, ie. in the scene not the code itself, vs what you’d like it to look like?
1 Like
Hello. I had this question posted - Add texture to sphere without distortion
Essentially, I want my texture-atlas
to look like this on a sphere: https://www.youtube.com/watch?app=desktop&v=qRYu0GDU-qM&ab_channel=JenAbbottCreates (first few seconds of video)
Did you try using just basic material with .map = your texture?
The default sphere mapping might be fine…
1 Like
Hi, yes but the texture naturally becomes distorted on a sphere. Trying to find a way to apply the texture without the distortion effect (examples in my previous reply)
Can u try texture.offset.set(0, .5 )
And texture.wrapS=texture.wrapT=THREE.RepeatWrapping
?
2 Likes
My textures have this by default on load
texture.colorSpace = "srgb";
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set( repeat, repeat );
texture.encoding = THREE.sRGBEncoding;
resources.textures[name] = texture;
Code
var atlasTexture = resources.textures['faces-atlas'].clone( );
atlasTexture.needsUpdate = true;
var toonTexture = resources.textures['tone-3'].clone( );
toonTexture.minFilter = toonTexture.magFilter = THREE.NearestFilter;
let characterGeo = new THREE.SphereGeometry( 0.5, 32, 16 );
let characterMat = new THREE.MeshToonMaterial( {
map: atlasTexture,
gradientMap: toonTexture
} );
characterMat.onBeforeCompile = shader => {
const custom_map_fragment = THREE.ShaderChunk.map_fragment.replace(
`diffuseColor *= sampledDiffuseColor;`,
`diffuseColor = vec4( mix( diffuse, sampledDiffuseColor.rgb, sampledDiffuseColor.a ), opacity );`
);
shader.fragmentShader = shader.fragmentShader.replace( '#include <map_fragment>', custom_map_fragment );
shader.uniforms.atlasDimensions = { value: new THREE.Vector2( ).copy( new THREE.Vector2(4, 4) ) };
shader.vertexShader = `
uniform vec2 atlasDimensions;
attribute float textureChunkIndex;
${shader.vertexShader}
`.replace(
`#include <uv_vertex>`,
`#include <uv_vertex>
float chunkId = floor(textureChunkIndex + 0.1);
vec2 idUV = vec2(mod(chunkId, atlasDimensions.x), floor(chunkId / atlasDimensions.x));
vec2 normalizedDimensions = 1. / atlasDimensions;
vUv = (uv + idUV) * normalizedDimensions;
`
);
}
this.characterInstanceMesh = new THREE.InstancedMesh( characterGeo, characterMat, amount );
this.characterInstanceMesh.material.needsUpdate = true;
Texture atlas
Result (becomes stretched)
The classic, here is the link to a similar chat recently.
I made a little fictional custom solar system with spheres as planets rotating around a sun. I wanted to give the planets unique textures, but rather than make a gltf I thought it would be best to make some fractal type shaders to wrap around the planets.
I’m having a really hard time finding an example of say a simple fractal texture that can wrap around a sphere. I found some simple examples in the book of shaders but I can’t get it to wrap around the sphere.
Is there a dead simple example o…
1 Like
Hi Attila, sorry I’m having trouble integrating into the shader code without breaking it, as I don’t know much about it. I’m already using the coordinates of the atlasDimensions
, I don’t know how to apply this as well
An attempt from scratch, how to use a texture atlas, with some modifications for fragment shader
Demo: https://codepen.io/prisoner849/full/WNBrpJO
Maybe will be helpful )
8 Likes
Hi Prisoner849,
how would this work when the spheres are instanced?
Also side question, how do I go about learning this custom shader code?
An instanced buffer attribute of vec2
to store tile’s coords, for example.
Trying to change numbers in shader code, looking what it changes in visuals.
Reading the forum, docs and other resources.
In general, the same way you learn other things )
2 Likes
I think this works for a code drawn texture, not for a .png
image, since I think the opacity is not specified
When I replace
diffuseColor *= mix(sampledDiffuseColor, vec4(1), step(0.5, max(absUV.x, absUV.y)));
with
diffuseColor = vec4( mix( diffuse, sampledDiffuseColor.rgb, sampledDiffuseColor.a ), opacity );
I get this
Try to add that cut-off part from my approach to yours.
Something like this:
float cutoff = 1. - step(0.5, max(absUV.x, absUV.y));
diffuseColor = vec4( mix( diffuse, sampledDiffuseColor.rgb, sampledDiffuseColor.a * cutoff), opacity );
1 Like
Works great! Up to the point I try to add a float
attribute for the textureChunkIndex
and I just constantly get ERROR: 0:78: 'attribute' : Illegal use of reserved word
onBeforeCompile: shader => {
shader.uniforms.atlasSize = { value: new THREE.Vector2( ).copy( new THREE.Vector2(4, 4) ) };
shader.uniforms.tile = { value: new THREE.Vector2( 2, 0 ) }
shader.fragmentShader = `
uniform vec2 atlasSize;
uniform vec2 tile;
attribute float textureChunkIndex; // <-- ERROR: 0:78: 'attribute' : Illegal use of reserved word
${shader.fragmentShader}
`.replace(
`#include <map_fragment>`,
`
vec2 mUV = vMapUv;
vec2 centerUV = ((mUV - 0.5) * vec2(2., 1.) + vec2(0.5, 0.)) * PI / 2.;
mUV = centerUV + 0.5;
vec2 atlasTile = 1. / atlasSize;
mUV = clamp((mUV + tile) * atlasTile, vec2(0.), vec2(1.));
vec4 sampledDiffuseColor = texture2D( map, mUV );
vec2 absUV = abs(centerUV);
float cutoff = 1. - step(0.5, max(absUV.x, absUV.y));
diffuseColor = vec4( mix( diffuse, sampledDiffuseColor.rgb, sampledDiffuseColor.a * cutoff), opacity );
`
);
}
I’m trying to change the faces via geometry.setAttribute( 'textureChunkIndex', new THREE.InstancedBufferAttribute( new Uint8Array( textureChunkIndex ), 1 ) );
like in my previous code
Could you provide a minimal live-code working example? jsfiddle, codepen etc.
PS attribute
belongs to vertex shader only.
2 Likes
I figured as much, albeit I got confused after everything was written in the fragmentShader
Modification from your code
Hoping for a simple function that changes the face and color of selected instance dynamically
Beautiful, works like a charm! Appreciate your time and patience, thank you!
1 Like
jrlazz
May 21, 2024, 4:48am
20
Hi @Vardan_Betikyan ,
I had prepared this example page to send You:
https://jrlazz.eu5.org/anim/image_on_sphere.html
but I think @prisoner849 solution is the best way.!
PS: Based on the stackoverflow.com page that You have referred…
2 Likes