I've rendered my scene to reflection, and refraction textures.
I then overlay those textures onto a water quad.
The reflection moves whenever I move the mouse up/down. At a certain mouse height, everything aligns up fine
Question How can I stop the reflection texture moving up/down and pulling away from my terrain...
VIDEO of behaviour!!
https://www.youtube.com/watch?v=hMZ-J6UUiJM&feature=youtu.be&hd=1
Or just a screenshot:
http://ift.tt/2ocLDLX
Here is the code that sets up and renders the water quad, overlaying the two textures
var waterHeight = 0;
function WaterSystem(){
// Need shaders as well
var waterVertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(waterVertexShader, [
'attribute vec2 waterPosition;',
// Out the texture coordinates from vertex shader
'varying vec2 textureCoords;',
'float tilingValue = 1.0;',
'varying vec4 clipSpace;', // Take in clip space in frag
'uniform mat4 projectionMatrix;',
'uniform mat4 viewMatrix;',
'uniform mat4 model;',
'void main(void){',
'vec4 worldPostion = model * vec4(waterPosition.x, 0.0, waterPosition.y, 1.0);', //needed for light and instancing
'vec4 positionRelativeToCamera = viewMatrix * worldPostion;',
// Output the clipSpace coordinates of current vertex
'clipSpace = projectionMatrix * positionRelativeToCamera;',
'gl_Position = clipSpace;',
'textureCoords = vec2(waterPosition.x/2.0 + 0.5, waterPosition.y/2.0 + 0.5) * tilingValue;',
'}'
].join('\n'));
gl.compileShader(waterVertexShader);
console.log("Water vertex shader compliation status: " + gl.getShaderInfoLog(waterVertexShader));
var waterFragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(waterFragmentShader, [
'precision highp float;',
'varying vec2 textureCoords;',
'varying vec4 clipSpace;',
// Want to sample the reflectionTexture and refractionTexture
'uniform sampler2D reflectionTexture;',
'uniform sampler2D refractionTexture;',
'uniform sampler2D dudvMap;',
// Water moving effect, offset for sampling dudv map
// Change the offset over time
'uniform float moveFactor;',
'float waveStrength = 0.2;',
'void main(void){',
// Need to convert clipSpace to NDC, using perspective division
// Divide by 2.0. then add 0.5 to get into texture coord systemLanguage
'vec2 ndc = (clipSpace.xy / clipSpace.w) / 2.0 + 0.5;',
'vec2 refractTextureCoords = vec2(ndc.x, ndc.y);',
'vec2 reflectTextureCoords = vec2(ndc.x, -ndc.y);', // negative because reflection
// Sample dudv map
'vec2 distortion1 = (texture2D(dudvMap, vec2(textureCoords.x + moveFactor, textureCoords.y)).rg * 2.0 - 1.0) * waveStrength;',
// Sample it again, and move it in completely different direction, realistic
'vec2 distortion2 = (texture2D(dudvMap, vec2(-textureCoords.x + moveFactor, textureCoords.y + moveFactor)).rg * 2.0 - 1.0) * waveStrength;',
// Add together
'vec2 totalDistortion = vec2(0.0, 0.0);',//distortion1 + distortion2;',
'refractTextureCoords += totalDistortion;',
'refractTextureCoords = clamp(refractTextureCoords, 0.001, 0.999);',
'reflectTextureCoords += totalDistortion;',
'reflectTextureCoords.x = clamp(reflectTextureCoords.x, 0.001, 0.999);', // ??
'reflectTextureCoords.y = clamp(reflectTextureCoords.y, -0.999, -0.001);', // flipped because reflection
'vec4 reflectColour = texture2D(reflectionTexture, vec2(reflectTextureCoords.s, reflectTextureCoords.t));',
'vec4 refractColour = texture2D(refractionTexture, vec2(refractTextureCoords.s, refractTextureCoords.t));',
// Mix factor 0.5, mix them equally
'gl_FragColor = mix(reflectColour, refractColour, 0.5);',
// Add blue tint to water colour, add 0.2 of it
'gl_FragColor = mix(gl_FragColor, vec4(0.0, 0.3, 0.7, 1.0), 0.2);',
'}'
].join('\n'));
gl.compileShader(waterFragmentShader);
console.log("Water fragment shader compliation status: " + gl.getShaderInfoLog(waterFragmentShader));
var waterProgram = gl.createProgram();
gl.attachShader(waterProgram, waterVertexShader);
gl.attachShader(waterProgram, waterFragmentShader);
gl.linkProgram(waterProgram);
console.log("waterProgram status: " + gl.getProgramInfoLog(waterProgram));
gl.useProgram(waterProgram);
var waterReflectionTextureLocation = gl.getUniformLocation(waterProgram, "reflectionTexture");
var waterRefractionTextureLocation = gl.getUniformLocation(waterProgram, "refractionTexture");
gl.enableVertexAttribArray(waterReflectionTextureLocation);
gl.enableVertexAttribArray(waterRefractionTextureLocation);
var waterPositionAttribLocation = gl.getAttribLocation(waterProgram, 'waterPosition');
gl.enableVertexAttribArray(waterPositionAttribLocation);
var waterViewMatrixLocation = gl.getUniformLocation(waterProgram, 'viewMatrix');
gl.uniformMatrix4fv(waterViewMatrixLocation, false, new Float32Array(viewMatrix));
var waterProjectionLocation = gl.getUniformLocation(waterProgram, 'projectionMatrix');
gl.uniformMatrix4fv(waterProjectionLocation, false, new Float32Array(projectionMatrix));
var waterModelLocation = gl.getUniformLocation(waterProgram, 'model');
gl.uniformMatrix4fv(waterModelLocation, false, new Float32Array(fullTransforms));
var waterDUDVmapLocation = gl.getUniformLocation(waterProgram, 'dudvMap');
var waterMoveFactorLocation = gl.getUniformLocation(waterProgram, 'moveFactor');
gl.useProgram(program);
this.renderToRefractionBuffer = function(){
gl.bindFramebuffer(gl.FRAMEBUFFER, refractionFrameBuffer);
// Want to render everything under the water, normal is pointing down
clipPlane = [0, -1, 0, -waterHeight]; // last param is water height
gl.clearColor(0.8, 0.8, 0.8, 0.7);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.viewport(0, 0, 512, 512);
terrain.render();
rockGenerator.renderInstancedRocks();
particleSystem.render();
lander.render();
//skybox.render(viewMatrix, projectionMatrix);
// Unbinds
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.viewport(0, 0, window.innerWidth, window.innerHeight);
}
/*
To create illusion of reflection texture
Need to move camera under the water, before rendering the reflection texture
The camera should move down by:
its original distance above the water * 2
The pitch of the camera also needs to be inverted
*/
this.renderToReflectionBuffer = function(){
/*
Want to render scene to a texture (frame buffer), so bind it
Clear it
Render to the texture (frame buffer)
Then unbind it
Then later on, we can render a square with that texture
Make sure this gets rendered to something that the original scene doesn't render
*/
gl.bindFramebuffer(gl.FRAMEBUFFER, reflectionFrameBuffer);
// Calculate distance we want to move camera down by
var distance = 2 * (cameraPosition[1] + waterHeight); // + ing, because water is negative, so --5 and breaks
cameraPosition[1] -= distance;
pitch -= pitch;
// Want to render everything above the waters surface, so normal as 0,1,0
// Horizontal plane, pointing upwards
clipPlane = [0, 1, 0, -waterHeight]; // last param is water height
gl.clearColor(0.8, 0.8, 0.8, 0.7);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.viewport(0, 0, 512, 512);
terrain.render();
rockGenerator.renderInstancedRocks();
particleSystem.render();
lander.render();
//skybox.render(viewMatrix, projectionMatrix);
// Reset camera
cameraPosition[1] += distance;
pitch += pitch;
// Unbinds
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.viewport(0, 0, window.innerWidth, window.innerHeight);
}
var waterVertexPositionBuffer;
var waterVertices = [];
var moveFactor = 0;
setup();
function setup(){
gl.useProgram(waterProgram);
waterVertexPositionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, waterVertexPositionBuffer);
// Setting x and z positions, y is set to 0 in vertex shader
waterVertices = [
-1, -1,
-1, 1,
1, -1,
1, -1,
-1, 1,
1, 1
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(waterVertices), gl.STATIC_DRAW);
gl.vertexAttribPointer(waterPositionAttribLocation, 2, gl.FLOAT, false, 0, 0);
gl.useProgram(program);
}
function updateWaterAttributesAndUniforms(){
moveFactor += Date.now() * 0.000000000000003; // dont ask....
moveFactor %= 1; // loops when reaches 0
gl.uniform1f(waterMoveFactorLocation, moveFactor);
// Don't know if needed
fullTransforms = m4.multiply(position, rotateZ);
fullTransforms = m4.multiply(fullTransforms, rotateY);
fullTransforms = m4.multiply(fullTransforms, rotateX);
fullTransforms = m4.multiply(fullTransforms, scale);
gl.uniformMatrix4fv(waterModelLocation, false, new Float32Array(fullTransforms));
gl.uniformMatrix4fv(waterViewMatrixLocation, false, new Float32Array(viewMatrix));
gl.uniformMatrix4fv(waterProjectionLocation, false, new Float32Array(projectionMatrix));
}
/*
Its rotating around the camera, but should instead rotate around the world origin?
*/
this.render = function(){
gl.useProgram(waterProgram);
scale = m4.scaling(35, 35, 35);
rotateX = m4.xRotation(0);
rotateY = m4.yRotation(0);
rotateZ = m4.zRotation(0);
position = m4.translation(230, waterHeight, 230);
// Reflection texture sampled from unit 0
gl.activeTexture(gl.TEXTURE0);
gl.uniform1i(gl.getUniformLocation(waterProgram, "reflectionTexture"), 0);
gl.bindTexture(gl.TEXTURE_2D, reflectionTexture);
// Refraction texture sampled from unit 1
gl.activeTexture(gl.TEXTURE1);
gl.uniform1i(gl.getUniformLocation(waterProgram, "refractionTexture"), 1);
gl.bindTexture(gl.TEXTURE_2D, refractionTexture);
// dudvMap texture sampled from unit 2
gl.activeTexture(gl.TEXTURE2);
gl.uniform1i(gl.getUniformLocation(waterProgram, "waterDUDVmapLocation"), 2);
gl.bindTexture(gl.TEXTURE_2D, WATER_DUDV_MAP_TEXTURE.getTextureAttribute.texture); // CHANGE THIS TO DUDV TEXTURE
updateWaterAttributesAndUniforms();
gl.bindBuffer(gl.ARRAY_BUFFER, waterVertexPositionBuffer);
gl.vertexAttribPointer(waterPositionAttribLocation, 2, gl.FLOAT, false, 0, 0);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 6);
gl.useProgram(program);
}
}
Aucun commentaire:
Enregistrer un commentaire