I've created a custom shader to be able to use a BlendMap with 4 different textures but I'm unable to get the shadows/lightning effects to work with it.
What am I missing here? Or is there some other way I can achieve same functionality?
Mesh creation method below which shows all textures blended properly.
// Creates the ground
function CreateGround() {
var uniforms = THREE.UniformsUtils.merge([
THREE.UniformsLib["lights"],
THREE.UniformsLib["shadowmap"],
{
TextureBackground: { type: "t", value: null },
TextureR: { type: "t", value: null },
TextureG: { type: "t", value: null },
TextureB: { type: "t", value: null },
TextureBlendMap: { type: "t", value: null }
}]);
var shaderMaterial;
try {
shaderMaterial = new THREE.ShaderMaterial({
lights: true,
uniforms: uniforms,
vertexShader: BlendMapVertexShader,
fragmentShader: BlendMapFragmentShader
});
} catch (e) {
alert("Error 'CreateGround' : GPU Shader couldn't compile");
}
shaderMaterial.uniforms.TextureBlendMap.value = _TextureBlendMap;
shaderMaterial.uniforms.TextureBackground.value = _TextureSand;
shaderMaterial.uniforms.TextureR.value = _TextureClay;
shaderMaterial.uniforms.TextureG.value = _TextureClay;
shaderMaterial.uniforms.TextureB.value = _TextureRock;
var geometry = new THREE.BoxGeometry(GROUND_SIZE, GROUND_HEIGHT, GROUND_SIZE);
var mesh = new THREE.Mesh(geometry, shaderMaterial);
mesh.castShadow = false;
mesh.receiveShadow = true;
return mesh;
}
And this is my current shader:
BlendMapVertexShader = [
THREE.ShaderChunk["shadowmap_pars_vertex"],
"varying vec2 vUv;",
"varying vec3 vPosition;",
"void main( void ) {",
"vUv = uv;",
"vPosition = position;",
"gl_Position = projectionMatrix * modelViewMatrix * vec4(vPosition, 1);",
THREE.ShaderChunk["begin_vertex"],
THREE.ShaderChunk["worldpos_vertex"],
THREE.ShaderChunk["shadowmap_vertex"],
"}",
].join("\n");
BlendMapFragmentShader = [
THREE.ShaderChunk["common"],
THREE.ShaderChunk["packing"],
THREE.ShaderChunk["shadowmap_pars_fragment"],
"varying vec2 vUv;",
"varying vec3 vPosition;",
"uniform sampler2D TextureBlendMap;",
"uniform sampler2D TextureBackground;",
"uniform sampler2D TextureR;",
"uniform sampler2D TextureG;",
"uniform sampler2D TextureB;",
"void main() {",
"vec4 cBlend = texture2D(TextureBlendMap, vUv);",
"float bText = 1.0 - (cBlend.r + cBlend.g + cBlend.b);",
"vec2 tiledCoords = vUv * 40.0;",
"vec4 cBack = texture2D(TextureBackground, tiledCoords) * bText;",
"vec4 cR = texture2D(TextureR, tiledCoords) * cBlend.r;",
"vec4 cG = texture2D(TextureG, tiledCoords) * cBlend.g;",
"vec4 cB = texture2D(TextureB, tiledCoords) * cBlend.b;",
"vec4 cTot = cBack + cR + cG + cB;",
"gl_FragColor = cTot;",
THREE.ShaderChunk["shadowmap_fragment"],
"}",
].join("\n");
I have no errors nor warnings in the browser.
three.js r85Dev
Alright. I ended up copying the PHONG shader and then override the diffuse color input. Solution below.
This is the method to create the mesh with blendmapshader
// Creates the ground
function CreateGround(material) {
var uniforms = THREE.UniformsUtils.merge([
THREE.UniformsLib["common"],
THREE.UniformsLib["aomap"],
THREE.UniformsLib["lightmap"],
THREE.UniformsLib["emissivemap"],
THREE.UniformsLib["bumpmap"],
THREE.UniformsLib["normalmap"],
THREE.UniformsLib["displacementmap"],
THREE.UniformsLib["gradientmap"],
THREE.UniformsLib["fog"],
THREE.UniformsLib["lights"],
{
emissive: { type: "c", value: new THREE.Color(0x000000) },
specular: { type: "c", value: new THREE.Color(0x111111) },
shininess: { type: "f", value: 30 },
TextureBackground: { type: "t", value: null },
TextureR: { type: "t", value: null },
TextureG: { type: "t", value: null },
TextureB: { type: "t", value: null },
TextureBlendMap: { type: "t", value: null },
}]);
var shaderMaterial;
try {
shaderMaterial = new THREE.ShaderMaterial({
lights: true,
uniforms: uniforms,
vertexShader: BlendMapVertexShader,
fragmentShader: BlendMapFragmentShader
});
} catch (e) {
alert("Error 'CreateGround' : GPU Shader couldn't compile");
}
shaderMaterial.uniforms.TextureBlendMap.value = _TextureBlendMap;
shaderMaterial.uniforms.TextureBackground.value = _TextureSand;
shaderMaterial.uniforms.TextureR.value = _TextureClay;
shaderMaterial.uniforms.TextureG.value = _TextureGrass;
shaderMaterial.uniforms.TextureB.value = _TextureSandRock;
var geometry = new THREE.BoxGeometry(GROUND_SIZE, GROUND_HEIGHT, GROUND_SIZE);
var mesh = new THREE.Mesh(geometry, shaderMaterial);
mesh.castShadow = false;
mesh.receiveShadow = true;
return mesh;
}
And this is the modified PHONG shader:
BlendMapVertexShader = [
"#define PHONG",
"varying vec3 vViewPosition;",
"varying vec2 vUv;",
"#ifndef FLAT_SHADED",
"varying vec3 vNormal;",
"#endif",
THREE.ShaderChunk["common"],
THREE.ShaderChunk["uv_pars_vertex"],
THREE.ShaderChunk["uv2_pars_vertex"],
THREE.ShaderChunk["displacementmap_pars_vertex"],
THREE.ShaderChunk["envmap_pars_vertex"],
THREE.ShaderChunk["color_pars_vertex"],
THREE.ShaderChunk["morphtarget_pars_vertex"],
THREE.ShaderChunk["skinning_pars_vertex"],
THREE.ShaderChunk["shadowmap_pars_vertex"],
THREE.ShaderChunk["logdepthbuf_pars_vertex"],
THREE.ShaderChunk["clipping_planes_pars_vertex"],
"void main() {",
THREE.ShaderChunk["uv_vertex"],
THREE.ShaderChunk["uv2_vertex"],
THREE.ShaderChunk["color_vertex"],
THREE.ShaderChunk["beginnormal_vertex"],
THREE.ShaderChunk["morphnormal_vertex"],
THREE.ShaderChunk["skinbase_vertex"],
THREE.ShaderChunk["skinnormal_vertex"],
THREE.ShaderChunk["defaultnormal_vertex"],
"#ifndef FLAT_SHADED // Normal computed with derivatives when FLAT_SHADED",
"vNormal = normalize( transformedNormal );",
"#endif",
THREE.ShaderChunk["begin_vertex"],
THREE.ShaderChunk["displacementmap_vertex"],
THREE.ShaderChunk["morphtarget_vertex"],
THREE.ShaderChunk["skinning_vertex"],
THREE.ShaderChunk["project_vertex"],
THREE.ShaderChunk["logdepthbuf_vertex"],
THREE.ShaderChunk["clipping_planes_vertex"],
"vUv = uv;",
"vViewPosition = - mvPosition.xyz;",
THREE.ShaderChunk["worldpos_vertex"],
THREE.ShaderChunk["envmap_vertex"],
THREE.ShaderChunk["shadowmap_vertex"],
"}",
].join("\n");
BlendMapFragmentShader = [
"#define PHONG",
"varying vec2 vUv;",
"uniform vec3 diffuse;",
"uniform vec3 emissive;",
"uniform vec3 specular;",
"uniform float shininess;",
"uniform float opacity;",
"uniform sampler2D TextureBlendMap;",
"uniform sampler2D TextureBackground;",
"uniform sampler2D TextureR;",
"uniform sampler2D TextureG;",
"uniform sampler2D TextureB;",
THREE.ShaderChunk["common"],
THREE.ShaderChunk["packing"],
THREE.ShaderChunk["color_pars_fragment"],
THREE.ShaderChunk["uv_pars_fragment"],
THREE.ShaderChunk["uv2_pars_fragment"],
THREE.ShaderChunk["map_pars_fragment"],
THREE.ShaderChunk["alphamap_pars_fragment"],
THREE.ShaderChunk["aomap_pars_fragment"],
THREE.ShaderChunk["lightmap_pars_fragment"],
THREE.ShaderChunk["emissivemap_pars_fragment"],
THREE.ShaderChunk["envmap_pars_fragment"],
THREE.ShaderChunk["fog_pars_fragment"],
THREE.ShaderChunk["bsdfs"],
THREE.ShaderChunk["lights_pars"],
THREE.ShaderChunk["lights_phong_pars_fragment"],
THREE.ShaderChunk["shadowmap_pars_fragment"],
THREE.ShaderChunk["bumpmap_pars_fragment"],
THREE.ShaderChunk["normalmap_pars_fragment"],
THREE.ShaderChunk["specularmap_pars_fragment"],
THREE.ShaderChunk["logdepthbuf_pars_fragment"],
THREE.ShaderChunk["clipping_planes_pars_fragment"],
"void main() {",
THREE.ShaderChunk["clipping_planes_fragment"],
"// THIS IS CUSTOM CODE TO OVERRIDE THE DIFFUSE COLOR WITH BLENDMAP TEXTURES",
"vec4 cBlend = texture2D(TextureBlendMap, vUv);",
"float bText = 1.0 - (cBlend.r + cBlend.g + cBlend.b);",
"vec2 tiledCoords = vUv * 40.0;",
"vec4 cBack = texture2D(TextureBackground, tiledCoords) * bText;",
"vec4 cR = texture2D(TextureR, tiledCoords) * cBlend.r;",
"vec4 cG = texture2D(TextureG, tiledCoords) * cBlend.g;",
"vec4 cB = texture2D(TextureB, tiledCoords) * cBlend.b;",
"vec4 cTot = cBack + cR + cG + cB;",
"vec4 diffuseColor = vec4( diffuse, opacity );",
"diffuseColor.r = cTot.r;",
"diffuseColor.g = cTot.g;",
"diffuseColor.b = cTot.b;",
"ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );",
"vec3 totalEmissiveRadiance = emissive;",
THREE.ShaderChunk["logdepthbuf_fragment"],
THREE.ShaderChunk["map_fragment"],
THREE.ShaderChunk["color_fragment"],
THREE.ShaderChunk["alphamap_fragment"],
THREE.ShaderChunk["alphatest_fragment"],
THREE.ShaderChunk["specularmap_fragment"],
THREE.ShaderChunk["normal_flip"],
THREE.ShaderChunk["normal_fragment"],
THREE.ShaderChunk["emissivemap_fragment"],
"// accumulation",
THREE.ShaderChunk["lights_phong_fragment"],
THREE.ShaderChunk["lights_template"],
"// modulation",
THREE.ShaderChunk["aomap_fragment"],
"vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;",
THREE.ShaderChunk["envmap_fragment"],
"gl_FragColor = vec4( outgoingLight, diffuseColor.a );",
THREE.ShaderChunk["premultiplied_alpha_fragment"],
THREE.ShaderChunk["tonemapping_fragment"],
THREE.ShaderChunk["encodings_fragment"],
THREE.ShaderChunk["fog_fragment"],
"}",
].join("\n");
just add shaderMaterial.lights = true;, i had encountered the same problem as you. here is a complete typescript class wrote by myself: threejs git issue
this is the full code:
import * as THREE from 'three';
export class TerrainMaterial extends THREE.ShaderMaterial {
public constructor() {
super({
uniforms: THREE.UniformsUtils.merge([
THREE.UniformsLib.fog,
THREE.UniformsLib.lights,
{
diffuse: { value: new THREE.Color(0xeeeeee) },
opacity: { value: 1.0 },
emissive: { value: new THREE.Color(0x000000) },
specular: { value: new THREE.Color(0x111111) },
shininess: { value: 0 },
offsetRepeat: { value: new THREE.Vector4(0, 0, 1, 1) },
map1: { value: null },
map2: { value: null },
map3: { value: null },
map1Normal: { value: null },
map2Normal: { value: null },
map3Normal: { value: null },
map1HeightRange: { value: 0 },
map2HeightRange: { value: 0 },
map3HeightRange: { value: 0 }
}
]),
vertexShader: [
"varying vec3 vNormal;",
"varying vec3 vViewPosition;",
"varying vec3 fPosition;",
"varying vec2 vUv;",
"uniform vec4 offsetRepeat;",
THREE.ShaderChunk.shadowmap_pars_vertex,
//THREE.ShaderChunk.logdepthbuf_pars_vertex,
THREE.ShaderChunk.fog_pars_vertex,
"void main(){",
THREE.ShaderChunk.beginnormal_vertex,
THREE.ShaderChunk.defaultnormal_vertex,
"vUv = uv * offsetRepeat.zw + offsetRepeat.xy;",
"vNormal = normalize( transformedNormal );",
THREE.ShaderChunk.begin_vertex,
THREE.ShaderChunk.project_vertex,
//THREE.ShaderChunk.logdepthbuf_vertex,
"fPosition = position;",
"vViewPosition = - mvPosition.xyz;",
THREE.ShaderChunk.worldpos_vertex,
THREE.ShaderChunk.shadowmap_vertex,
THREE.ShaderChunk.fog_vertex,
"}"
].join("\n"),
fragmentShader: [
"uniform vec3 diffuse;",
"uniform vec3 emissive;",
"uniform vec3 specular;",
"uniform float shininess;",
"uniform float opacity;",
"uniform sampler2D map1;",
"uniform sampler2D map2;",
"uniform sampler2D map3;",
"uniform sampler2D map1Normal;",
"uniform sampler2D map2Normal;",
"uniform sampler2D map3Normal;",
"uniform float map1HeightRange;",
"uniform float map2HeightRange;",
"uniform float map3HeightRange;",
"varying vec2 vUv;",
"varying vec3 fPosition;",
THREE.ShaderChunk.common,
THREE.ShaderChunk.packing,
THREE.ShaderChunk.dithering_pars_fragment,
THREE.ShaderChunk.emissivemap_pars_fragment,
THREE.ShaderChunk.fog_pars_fragment,
THREE.ShaderChunk.bsdfs,
THREE.ShaderChunk.lights_pars,
THREE.ShaderChunk.lights_phong_pars_fragment,
THREE.ShaderChunk.shadowmap_pars_fragment,
THREE.ShaderChunk.specularmap_pars_fragment,
//THREE.ShaderChunk.logdepthbuf_pars_fragment,
"vec3 perturbNormal2Arb( vec3 normalColor, vec3 eye_pos, vec3 surf_norm ) {",
"vec3 q0 = vec3( dFdx( eye_pos.x ), dFdx( eye_pos.y ), dFdx( eye_pos.z ) );",
"vec3 q1 = vec3( dFdy( eye_pos.x ), dFdy( eye_pos.y ), dFdy( eye_pos.z ) );",
"vec2 st0 = dFdx( vUv.st );",
"vec2 st1 = dFdy( vUv.st );",
"vec3 S = normalize( q0 * st1.t - q1 * st0.t );",
"vec3 T = normalize( -q0 * st1.s + q1 * st0.s );",
"vec3 N = normalize( surf_norm );",
"vec3 mapN = normalColor * 2.0 - 1.0;",
//"mapN.xy = normalScale * mapN.xy;",
"mat3 tsn = mat3( S, T, N );",
"return normalize( tsn * mapN );",
"}",
"void main(){",
"vec4 diffuseColor = vec4( diffuse, opacity );",
"ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );",
"vec3 totalEmissiveRadiance = emissive;",
//THREE.ShaderChunk.logdepthbuf_fragment,
"vec3 texel;",
"vec3 texelNormal;",
"float amount;",
//need to optimize here, let's say remove if else if else?
"if(fPosition.y < map1HeightRange){",
"texel = texture2D(map1, vUv).rgb;",
"texelNormal = texture2D(map1Normal, vUv).rgb;",
"}",
"else if(fPosition.y < map2HeightRange){",
"amount = (fPosition.y - map1HeightRange) / map1HeightRange;",
"texel = mix(texture2D(map1, vUv), texture2D(map2, vUv), amount).rgb;",
"texelNormal = mix(texture2D(map1Normal, vUv), texture2D(map2Normal, vUv), amount).rgb;",
"}",
"else if(fPosition.y < map3HeightRange){",
"float hStep = map3HeightRange - map2HeightRange;",
"amount = (fPosition.y - hStep) / hStep;",
"texel = mix(texture2D(map2, vUv), texture2D(map3, vUv), amount).rgb;",
"texelNormal = mix(texture2D(map2Normal, vUv), texture2D(map3Normal, vUv), amount).rgb;",
"} else {",
"texel = texture2D(map3, vUv).rgb;",
"texelNormal = texture2D(map3Normal, vUv).rgb;",
"}",
"vec4 texelColor = vec4( texel, 1.0 );",
"texelColor = mapTexelToLinear( texelColor );",
"diffuseColor *= texelColor;",
THREE.ShaderChunk.specularmap_fragment,
"vec3 normal = normalize( vNormal );",
"normal = perturbNormal2Arb( texelNormal.rgb, -vViewPosition, normal );",
THREE.ShaderChunk.emissivemap_fragment,
THREE.ShaderChunk.lights_phong_fragment,
THREE.ShaderChunk.lights_template,
"vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;",
"gl_FragColor = vec4( outgoingLight, diffuseColor.a );",
THREE.ShaderChunk.tonemapping_fragment,
THREE.ShaderChunk.encodings_fragment,
THREE.ShaderChunk.fog_fragment,
THREE.ShaderChunk.premultiplied_alpha_fragment,
THREE.ShaderChunk.dithering_fragment,
"}"
].join("\n")
});
this.defaultAttributeValues = null;
this.fog = true;
this.lights = true;
this.extensions.derivatives = true;
this.extensions.shaderTextureLOD = true;
}
public setOffsetRepeat(ofX: number, ofY: number, rpX: number, rpY: number):void {
this.uniforms["offsetRepeat"].value.set(ofX, ofY, rpX, rpY);
this.setRepeat(this.uniforms["map1"].value, this.uniforms["map1Normal"].value);
this.setRepeat(this.uniforms["map2"].value, this.uniforms["map2Normal"].value);
this.setRepeat(this.uniforms["map3"].value, this.uniforms["map3Normal"].value);
this.needsUpdate = true;
}
private setRepeat(map: THREE.Texture, normal: THREE.Texture): void {
let v4: THREE.Vector4 = this.uniforms["offsetRepeat"].value;
if (v4.y != 1 || v4.z != 1) {
if (map) map.wrapS = map.wrapT = THREE.RepeatWrapping;
if (normal) normal.wrapS = normal.wrapT = THREE.RepeatWrapping;
}
}
public setMap1(map: THREE.Texture, normal: THREE.Texture, heightRange: number) {
this.setRepeat(map, normal);
this.uniforms["map1"].value = map;
this.uniforms["map1Normal"].value = normal;
this.uniforms["map1HeightRange"].value = heightRange;
this.needsUpdate = true;
}
public setMap2(map: THREE.Texture, normal: THREE.Texture, heightRange: number) {
this.setRepeat(map, normal);
this.uniforms["map2"].value = map;
this.uniforms["map2Normal"].value = normal;
this.uniforms["map2HeightRange"].value = heightRange;
this.needsUpdate = true;
}
public setMap3(map: THREE.Texture, normal: THREE.Texture, heightRange: number) {
this.setRepeat(map, normal);
this.uniforms["map3"].value = map;
this.uniforms["map3Normal"].value = normal;
this.uniforms["map3HeightRange"].value = heightRange;
this.needsUpdate = true;
}
}
and the usage:
let loader = new THREE.TextureLoader();
let terrainMat = new TerrainMaterial();
terrainMat.dithering = Config.DITHERING;
terrainMat.setOffsetRepeat(0, 0, 80, 80);
let map1 = loader.load("images/maps/ground/shatter.jpg");
let map1Normal = loader.load("images/maps/ground/shatter_normal.png");
map1.anisotropy = map1Normal.anisotropy = anisotropy;
let map2 = loader.load("images/maps/ground/earth.jpg");
let map2Normal = loader.load("images/maps/ground/earth_normal.png");
map2.anisotropy = map2Normal.anisotropy = anisotropy;
let map3 = loader.load("images/maps/ground/moss.jpg");
let map3Normal = loader.load("images/maps/ground/moss_normal.png");
map3.anisotropy = map3Normal.anisotropy = anisotropy;
let hStep = GroundGeometry.MAX_HEIGHT / 4;
terrainMat.setMap1(map1, map1Normal, hStep);
terrainMat.setMap2(map2, map2Normal, hStep * 2);
terrainMat.setMap3(map3, map3Normal, hStep * 4);
//note: replace new THREE.PlaneGeometry with your terrain geometry so the mateiral can detect height change. otherise the plane will be filled full with the same 1 map.
let p = new THREE.Mesh(new THREE.PlaneGeometry(900, 900, 257, 257), terrainMat);
p.geometry.rotateX(-NumberConsts.PI_2);
scene.add(p);
and the result:
click to see image (i don't have the privilege to embed images yet)
This is kind of a long shot, but if all objects in your scene use this material, then there shouldn't be any shadows because nothing casts shadows.
mesh.castShadow = false;
mesh.receiveShadow = true;
But i'm guessing that in the rest of your code you have some Meshes set to cast shadows.
I don't know if i fully understand the ShaderChunk methods, but it looks like it's just a series of defined strings that you drop into the middle of your own text, this part looked a little suspicious:
"gl_FragColor = cTot;",
THREE.ShaderChunk["shadowmap_fragment"],
But I don't see how whatever the shadowmap_fragment does has a chance to mix with our existing value for gl_FragColor. In the shadowmap_fragment src it runs:
void main() {
gl_FragColor = vec4( 0.0, 0.0, 0.0, opacity * ( 1.0 - getShadowMask() ) );
}
where getShadowMask() does a lot of magic with lights to return a float. So I don't see how your assigned gl_FragColor gets mixed with what the shadowmap_fragment returns. What about changing the order:
THREE.ShaderChunk["shadowmap_fragment"],
"gl_FragColor = cTot*gl_FragColor.a;"
not sure if that'll help, but you might check out the src of shadowmap_pars_frag to see what's happening behind the scenes. Maybe we're missing something.
One last thing: try doing just the shadows with none of the texture mixing, to isolate the issue. It might be that you're hitting a GLSL limit to the number of texture samplings - because the shadow chunk also uses texture sampling.
The basic components took from the ShaderLib['lambert'],
But there I did not find the lighting calculation for Lambert in the fragment shader
In addition, in the current shader get an error:
three.js:22433 WebGL: INVALID_VALUE: uniform3fv: no array
this.uniforms= {
"directionalLightDirection" : { type: "fv", value: [] },
"directionalLightColor" : { type: "fv", value: [] },
"opacity":{type:'f', value:1},
"map" : { type: "t", value: params.map }
};
this.vertexShader=[
varying vec2 vUv;',
"varying vec3 vLightFront;",
THREE.ShaderChunk[ 'logdepthbuf_pars_vertex'],
"#if MAX_DIR_LIGHTS > 0",
" uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];",
" uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];",
"#endif",
'void main()',
'{',
'vUv = uv;',
'vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );',
'gl_Position = projectionMatrix * mvPosition;',
THREE.ShaderChunk[ 'logdepthbuf_vertex'],
"#ifdef USE_SKINNING",
" vec3 objectNormal = skinnedNormal.xyz;",
"#elif defined( USE_MORPHNORMALS )",
" vec3 objectNormal = morphedNormal;",
"#else",
" vec3 objectNormal = normal;",
"#endif",
"#ifdef FLIP_SIDED",
" objectNormal = -objectNormal;",
"#endif",
"vec3 transformedNormal = normalMatrix * objectNormal;",
"#if MAX_DIR_LIGHTS > 0",
"transformedNormal = normalize( transformedNormal );",
"for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {",
" vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );",
" vec3 dirVector = normalize( lDirection.xyz );",
" float dotProduct = dot( transformedNormal, dirVector );",
" vec3 directionalLightWeighting = vec3( max( dotProduct, 0.0 ) );",
" #ifdef DOUBLE_SIDED",
" vec3 directionalLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );",
" #ifdef WRAP_AROUND",
" vec3 directionalLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );",
" #endif",
" #endif",
" #ifdef WRAP_AROUND",
" vec3 directionalLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );",
" directionalLightWeighting = mix( directionalLightWeighting, directionalLightWeightingHalf, wrapRGB );",
" #ifdef DOUBLE_SIDED",
" directionalLightWeightingBack = mix( directionalLightWeightingBack, directionalLightWeightingHalfBack, wrapRGB );",
" #endif",
" #endif",
" vLightFront += directionalLightColor[ i ] * directionalLightWeighting;",
" #ifdef DOUBLE_SIDED",
" vLightBack += directionalLightColor[ i ] * directionalLightWeightingBack;",
" #endif",
"}",
" #endif", *
'}'].join('\n');
this.fragmentShader=[
THREE.ShaderChunk[ 'logdepthbuf_pars_fragment'],
'varying vec2 vUv;',
'uniform float opacity;',
'uniform sampler2D map;',
'void main()',
'{',
'gl_FragColor = vec4( 0.0,0.0,0.0, opacity );',
'gl_FragColor+=texture2D(map,vUv);',
THREE.ShaderChunk[ 'logdepthbuf_fragment'],
'}'
].join('\n');
What I missed in the vertex shader? What besides need to specify?
add lights: true to params Material like this:
new THREE.ShaderMaterial({
fragmentShader: fragmentShader,
vertexShader: vertexShader,
uniforms: uniforms,
side: THREE.DoubleSide,
lights: true // <--
})
I am currently working on creating a shader in THREE.JS which will act like the normal shader, but using a color as the input to define how it is shaded.
Below is the Code that is causing the problem, and after that is a longer explanation of why I am doing it, and what I think is causing the problem:
fragmentShader: [
"uniform float opacity;",
"varying vec3 vNormal;",
"uniform vec3 color;",
"void main() {",
//THIS IS WHAT I THINK IS SCREWING UP EVERYTHING
//Can I not call normalize with that complex
//of equations within a normalize function?
"gl_FragColor = vec4( normalize(color.r + (vNormal.x*color.r)*.5, color.g + (vNormal.y*color.g)*.5, color.b + (vNormal.z*color.b)*.5), opacity );",
"}"
].join("\n")
A longer description:
I am basically using the same code as the normal shader in the THREE.shaderLib, which is as follows:
'normal': {
uniforms: {
"opacity" : { type: "f", value: 1.0 }
},
vertexShader: [
"varying vec3 vNormal;",
"void main() {",
"vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",
"vNormal = normalize( normalMatrix * normal );",
"gl_Position = projectionMatrix * mvPosition;",
"}"
].join("\n"),
fragmentShader: [
"uniform float opacity;",
"varying vec3 vNormal;",
"void main() {",
"gl_FragColor = vec4( 0.5 * normalize( vNormal ) + 0.5, opacity );",
"}"
].join("\n")
},
What I am using is basically this, but with a color aspect added, and it is called within a function that defines a new shader, like so:
function assignNewShader(color){
var colorAssign = new THREE.Color(color)
THREE.ShaderLib[color] = {
uniforms: {
"opacity" : { type: "f", value: 1.0 },
"color" : { type: "c", value: colorAssign },
},
vertexShader: [
"varying vec3 vNormal;",
"void main() {",
"vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",
"vNormal = normalMatrix * normal;",
"gl_Position = projectionMatrix * mvPosition;",
"}"
].join("\n"),
fragmentShader: [
"uniform float opacity;",
"varying vec3 vNormal;",
"uniform vec3 color;",
"void main() {",
"gl_FragColor = vec4(color.r + (vNormal.x*color.r)*.5, color.g + (vNormal.y*color.g)*.5, color.b + (vNormal.z*color.b)*.5, opacity );",
"}"
].join("\n")
}
}
You can see that the biggest difference lies within the 'fragmentShader' section, where the vNormal is used to make the gl_FragColor similar (but not exactly the same) as the color that is given in the function.
My problem is this: As a object is 'scaled' this color difference gets more and more drastic, to the point where all of the colors are only as bright as possible. Because of that, I tried to do the following to the 'fragementShader' section of the code:
fragmentShader: [
"uniform float opacity;",
"varying vec3 vNormal;",
"uniform vec3 color;",
"void main() {",
"gl_FragColor = vec4( normalize(color.r + (vNormal.x*color.r)*.5, color.g + (vNormal.y*color.g)*.5, color.b + (vNormal.z*color.b)*.5), opacity );",
"}"
].join("\n")
When I do this, I am greeted with a PLETHORA of errors including:
ERROR: 0:37: 'normalize' : no matching overloaded function found
ERROR: 0:37: 'constructor' : not enough data provided for construction
WebGL: INVALID_VALUE: attachShader: no object or object deleted
Could not initialise shader
VALIDATE_STATUS: false, gl error [1281]
WebGL: INVALID_OPERATION: getUniformLocation: program not linked
I am definitly in over my head getting into the webGL part of THREE, but it seems to me that this mode of altering the fragment shader should work. Does anybody have any ideas as to why it might not?
Normalize takes a vec3 not a vec4.