I want to make explode effect like this (http://threejs.org/examples/#webgl_modifier_tessellation), but for cube with panorama textures (cube with 6 images).
I transform vertex shader to this:
uniform float amplitude;
attribute float displacement;
varying vec3 vNormal;
varying vec2 vUv;
void main() {
vNormal = normal;
vUv = ( 0.5 + amplitude ) * uv + vec2( amplitude );
vec3 newPosition = position + amplitude * normal * vec3( displacement );
gl_Position = projectionMatrix * modelViewMatrix * vec4( newPosition, 1.0 );
}
and fragment to this by adding samplerCube and textureCube:
varying vec3 vNormal;
varying vec2 vUv;
uniform samplerCube texture1;
void main() {
vec3 light = vec3( 0.5, 0.2, 1.0 );
light = normalize( light );
float dProd = dot( vNormal, light ) * 0.5 + 0.5;
gl_FragColor = vec4( vec3( dProd ), 1.0 );
gl_FragColor = textureCube(texture1, vNormal);
}
But result doesn't looks good, it's shows color, but not real detailed texture (look texture http://pg2.paraplan.io/_pano/cube/1024/nx.jpg).
Can you help me with shader setting, or may be know how to do explode tessellation without shaders?
DEMO: http://pg2.paraplan.io/_pano/cube/scene.html
Related
I am trying to recreate the Volumetric Lighting example from JMSWRNR ( https://codesandbox.io/s/github/jmswrnr/website-examples/tree/master/3d-header/volumetric-lighting?from-embed=&file=/src/index.js ) but I am facing some issues with Occlusion Composer.
I don't really know GLSL so debugging is very hard especially for a beginner like me.
Here is the GitHub Repo: https://github.com/RolandTeslaru/roland-teslaru-portfolio/tree/not-working
Main Code is in the components/HomeCanvas/Scene.ts
My guess its that the VolumetricLightCylinder.js shader is causing the issue because when I change
worldPosition.xyz;
to
worldPosition
the error disappears.
import * as THREE from 'three'
export default () => ({
lights: true,
transparent: true,
depthWrite: false,
uniforms: THREE.UniformsUtils.merge([
THREE.UniformsLib['lights'],
{
attenuation: { value: 25.0 },
anglePower: { value: 10.0 },
spotPosition: { value: new THREE.Vector3(0, 0, 0) },
},
]),
vertexShader: /* glsl */ `
#include <common>
struct PointLight {
vec3 position;
vec3 color;
float distance;
float decay;
int shadow;
float shadowBias;
float shadowRadius;
vec2 shadowMapSize;
float shadowCameraNear;
float shadowCameraFar;
};
uniform PointLight pointLights[NUM_POINT_LIGHTS];
uniform float viewMix;
varying vec4 vColor;
varying vec3 vNormal;
varying vec3 vWorldPosition;
float _punctualLightIntensityToIrradianceFactor( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {
if( decayExponent > 0.0 ) {
return pow( saturate( -lightDistance / cutoffDistance + 1.0 ), decayExponent );
}
return 1.0;
}
void main() {
vNormal = normalize(normalMatrix * normal);
vec4 worldPosition = modelMatrix * vec4(position, 1.0);
vec4 modelViewPosition = modelViewMatrix * vec4(position, 1.0);
gl_Position = projectionMatrix * modelViewPosition;
vec4 addedLights = vec4(0.1, 0.1, 0.1, 1.0);
for(int l = 0; l < NUM_POINT_LIGHTS; l++) {
float dist = distance(pointLights[l].position, worldPosition.xyz);
addedLights.rgb += pointLights[l].color *
_punctualLightIntensityToIrradianceFactor(
dist,
pointLights[l].distance,
pointLights[l].decay
);
}
vWorldPosition = worldPosition.xyz;
vColor = addedLights;
}
`,
fragmentShader: /* glsl */`
varying vec3 vNormal;
varying vec3 vWorldPosition;
uniform vec3 spotPosition;
uniform float attenuation;
uniform float anglePower;
varying vec4 vColor;
void main() {
float intensity;
intensity = distance(vWorldPosition, spotPosition)/attenuation;
intensity = 1.0 - clamp(intensity, 0.0, 1.0);
vec3 normal = vec3(vNormal.x, vNormal.y, abs(vNormal.z));
float angleIntensity = pow(dot(normal, vec3(0.0, 0.0, 1.0)), anglePower);
intensity = intensity * angleIntensity;
gl_FragColor = vec4(vColor.rgb, intensity);
}
`,
})
How do I set the color to the mesh only when the height is zero?
As for now, i just mixed the colors:
The problem is that this kind on mixing is not precise. I just want the color blue only when the height is zero (so only inside that red path I made with paint).
I created a custom material for the mesh, like so:
material = new THREE.ShaderMaterial({
uniforms: THREE.UniformsUtils.merge([
THREE.UniformsLib['lights'],
{
lightIntensity: {type: 'f', value: 1.0},
diffuse: {type: 'c', value: new THREE.Color(0x0000ff)},
color0: {
value: new THREE.Color("blue")
},
color1: {
value: new THREE.Color("green")
},
color2: {
value: new THREE.Color("brown")
},
color3: {
value: new THREE.Color("black")
},
bboxMin: {
value: geom.boundingBox.min
},
bboxMax: {
value: geom.boundingBox.max
}
}
]),
vertexShader: `
uniform vec3 bboxMin;
uniform vec3 bboxMax;
varying vec2 vUv;
varying vec3 vPos;
varying vec3 vNormal;
void main() {
vPos = (modelMatrix * vec4(position, 1.0 )).xyz;
vNormal = normalMatrix * normal;
vUv.y = (position.y - bboxMin.y) / (bboxMax.y - bboxMin.y);
gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
}
`,
fragmentShader: `
uniform vec3 color1;
uniform vec3 color2;
uniform vec3 color3;
uniform vec3 color0;
varying vec2 vUv;
uniform vec3 diffuse;
varying vec3 vPos;
varying vec3 vNormal;
struct PointLight {
vec3 position;
vec3 color;
};
uniform PointLight pointLights[ NUM_POINT_LIGHTS ];
void main() {
vec4 addedLights = vec4(0.1, 0.1, 0.1, 1.0);
for(int l = 0; l < NUM_POINT_LIGHTS; l++) {
vec3 adjustedLight = pointLights[l].position + cameraPosition;
vec3 lightDirection = normalize(vPos - adjustedLight);
addedLights.rgb += clamp(dot(-lightDirection, vNormal), 0.0, 1.0) * pointLights[l].color;
}
gl_FragColor = mix(vec4(mix(mix(mix(color0, color1, vUv.y), color1, vUv.y), mix(color1, color2, vUv.y), vUv.y), 1.0),addedLights, addedLights);
}
`,
lights: true
});
Try using the step() function. Here's a definition to help you understand it. Here's how it works:
float step(float edge, float x)
It takes in a constant to declare the edge, and x, which is your variable.
If x is below the edge, you get 0, and if x is above the edge, you get 1.
Here's a simplified use of it. When height is below 0.2, you'll get blue, and when height is above 0.2, you'll get green.
vec3 green = vec3(0.0, 1.0, 0.0);
vec3 blue = vec3(0.0, 0.0, 1.0);
float edge = 0.2;
float colorMix = step(edge, height);
vec3 finalColor = mix(blue, green, colorMix);
I picked 0.2 to give the blue band some thickness, otherwise it wouldn't be visible.
I am rendering my scene in a 512x512 canvas, my goal is to have the pixel intensity change according to how far away the pixel is from the mouse cursor. But it doesn't seem to change at all. I try multipling by a large number, then it's all white.
var ico = new THREE.Mesh(new THREE.IcosahedronGeometry(0.3,0), light_mat);
ico.position.x = 0;
ico.position.y = 0;
ico.position.z = -3;
scene.add(ico);
var render = function() {
vec.set(
( mouse_x / 512 ) * 2 - 1,
- ( mouse_y / 512 ) * 2 + 1,
0.5 );
vec.unproject( camera );
vec.sub( camera.position ).normalize();
var distance = (ico.position.z-camera.position.z ) / vec.z;
pos.copy( camera.position ).add( vec.multiplyScalar( distance ) );
console.log(pos.x+":"+pos.y+":"+pos.z);
ico.material.uniforms.mouse.value = pos;
requestAnimationFrame(render);
renderer.render(scene, camera);
};
...
<script type="x-shader/x-vertex" id="light_f">
varying vec3 pos;
varying vec2 uv_pos;
varying vec3 norm;
uniform vec3 mouse;
void main() {
vec4 tex = vec4(1.0,1.0,1.0,1.0);
float ang = dot(mouse,norm);
float dis = 0.1*distance(mouse,pos);
gl_FragColor = tex*dis;
}
</script>
<script type="x-shader/x-vertex" id="light_v">
uniform vec3 mouse;
varying vec2 uv_pos;
varying vec3 norm;
varying vec3 pos;
void main() {
uv_pos = uv;
norm = normal;
pos = position;
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}
</script>
Any help appreciated.
I've created a simple three.js app which renders map tiles in 3D. Each tile is a separated mesh (a plane with 10 height and 10 width segments) which uses a THREE.ShaderMaterial. In order to access elevation data I used this Mapbox tileset. Two png tiles (elevation and color) are passed to the simple shader that decodes height value:
<script id="vertexShader" type="x-shader/x-vertex">
uniform sampler2D bump;
uniform sampler2D map;
varying float vAmount;
varying vec2 vUv;
void main()
{
vUv = uv;
vec4 bumpData = texture2D( bump, uv );
vAmount = bumpData.x;
float height = (-0.4 + (bumpData.x * 256.0 * 256.0 + bumpData.y * 256.0 + bumpData.z)/1024.0);
vec3 newPosition = position;
newPosition.z = height;
gl_Position = projectionMatrix * modelViewMatrix * vec4( newPosition, 1.0 );
}
</script>
<script id="fragmentShader" type="x-shader/x-vertex">
uniform sampler2D bump;
uniform sampler2D map;
varying vec2 vUv;
varying float vAmount;
void main()
{
if(vAmount == 0.0) {
discard;
}
vec4 tile = texture2D(map, vUv);
gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0) + tile;
}
</script>
However, it seems like nearby tiles have a bit different height values on edges. I've tried to use THREE.NearestFilter for textures but it didn't have any effect. Is there a way to get rid of these white stripes?
I'm using THREE.js r73, and I'm trying to make a particle system using THREE.BufferGeometery to hold the vertices and THREE.ShaderMaterial to add functionality to them. For some reason, I'm getting the error above. Here is my code (using Typescript). The error is occurring at the line gl_FragColor = gl_FragColor * texture2D( texture, gl_PointCoord ); (The last one in the fragment shader).
this.particleSystem = new THREE.PointCloud(
this.particles,
new THREE.ShaderMaterial({
uniforms: {
texture: wTex
},
vertexShader: `
attribute vec3 color;
attribute float size;
varying vec3 vColor;
varying vec2 vUv;
void main() {
vUv = uv;
vColor = color; // set color associated to vertex; use later in fragment shader
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
gl_PointSize = size * ( 300.0 / length( mvPosition.xyz ) );
gl_Position = projectionMatrix * mvPosition;
}
`,
fragmentShader: `
uniform sampler2D texture;
varying vec3 vColor; // colors associated to vertices; assigned by vertex shader
varying vec2 vUv;
void main() {
// calculates a color for the particle
gl_FragColor = vec4( vColor, 1.0 );
// sets particle texture to desired color
gl_FragColor = gl_FragColor * texture2D( texture, gl_PointCoord );
}
`
})
);
The code was adapted from some examples I found online, but I understand it.
You're not constructing the uniform correctly. It should be...
uniforms: {
texture: { type: 't', value: wTex }
}