React Three Fiber ShaderMaterial animation problem - javascript

I've been trying to find where I made a mistake maybe 30 times, but I couldn't find it. There is no problem in the view, but the animation does not work in the Component.
The view works well, but the animation needs to work in the code I wrote in the fragment. The link I referenced is
https://www.youtube.com/watch?v=3krH52AhPqk.
import React, { Suspense, useMemo, useRef } from "react";
import * as THREE from "three";
import { Canvas, useFrame,extend } from "#react-three/fiber";
import { OrbitControls } from "#react-three/drei";
import fragmentShader from "./shader/fragment.js";
import vertexShader from "./shader/vertex.js";
import fragment1 from "./shader/shaderSun/fragment.js";
import vertex1 from "./shader/shaderSun/vertex.js";
// function Perlin(props) {
// return (
// <mesh {...props}>
// <sphereBufferGeometry />
// <meshPhysicalMaterial />
// <shaderMaterial
// attach="material"
// args={[
// {
// uniforms: [1.1, 30, 30],
// vertexShader: vertex1,
// fragmentShader: fragment1,
// },
// ]}
// side={THREE.DoubleSide}
// />
// </mesh>
// );
// }
class CustomMaterial extends THREE.ShaderMaterial {
constructor() {
super({
uniforms: { time:{value:0},resolution:{value:new THREE.Vector4()} },
vertexShader: vertexShader,
fragmentShader: fragmentShader,
side: THREE.DoubleSide
})
}
}
extend({ CustomMaterial })
function Sphere(props) {
// const data = useMemo(() => ({ fragment }));
const myMesh = React.useRef();
// useFrame(({ clock }) => {
// myMesh.current.rotation.z += 0.1;
// });
// const data = useMemo(
// () => ({
// uniforms: {},
// fragmentShader,
// vertexShader,
// uPerlin: { value: null },
// }),
// []
// );
return (
<mesh {...props} ref={myMesh}>
<sphereBufferGeometry args={[1, 30, 30]} />
{/*
<Perlin /> */}
<customMaterial attach="material" />
</mesh>
);
}
function index() {
return (
<Canvas >
{" "}
{/* <spotLight
intensity={0.5}
angle={0.2}
penumbra={1}
position={[5, -25, 10]}
/>{" "} */}
<Suspense fallback={null}>
<Sphere />
{/* <Perlin /> */}
</Suspense>
<OrbitControls />
</Canvas>
);
}
export default index;
fragmentShader
const fragment = `
//
// Description : Array and textureless GLSL 2D/3D/4D simplex
// noise functions.
// Author : Ian McEwan, Ashima Arts.
// Maintainer : ijm
// Lastmod : 20110822 (ijm)
// License : Copyright (C) 2011 Ashima Arts. All rights reserved.
// Distributed under the MIT License. See LICENSE file.
// https://github.com/ashima/webgl-noise
//
uniform float time;
uniform float progress;
uniform sampler2D texture1;
uniform vec4 resolution;
varying vec2 vUv;
varying vec3 vPosition;
float PI= 3.141592653589793238;
vec4 mod289(vec4 x) {
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
float mod289(float x) {
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec4 permute(vec4 x) {
return mod289(((x*34.0)+1.0)*x);
}
float permute(float x) {
return mod289(((x*34.0)+1.0)*x);
}
vec4 taylorInvSqrt(vec4 r)
{
return 1.79284291400159 - 0.85373472095314 * r;
}
float taylorInvSqrt(float r)
{
return 1.79284291400159 - 0.85373472095314 * r;
}
vec4 grad4(float j, vec4 ip)
{
const vec4 ones = vec4(1.0, 1.0, 1.0, -1.0);
vec4 p,s;
p.xyz = floor( fract (vec3(j) * ip.xyz) * 7.0) * ip.z - 1.0;
p.w = 1.5 - dot(abs(p.xyz), ones.xyz);
s = vec4(lessThan(p, vec4(0.0)));
p.xyz = p.xyz + (s.xyz*2.0 - 1.0) * s.www;
return p;
}
// (sqrt(5) - 1)/4 = F4, used once below
#define F4 0.309016994374947451
float snoise(vec4 v)
{
const vec4 C = vec4( 0.138196601125011, // (5 - sqrt(5))/20 G4
0.276393202250021, // 2 * G4
0.414589803375032, // 3 * G4
-0.447213595499958); // -1 + 4 * G4
// First corner
vec4 i = floor(v + dot(v, vec4(F4)) );
vec4 x0 = v - i + dot(i, C.xxxx);
// Other corners
// Rank sorting originally contributed by Bill Licea-Kane, AMD (formerly ATI)
vec4 i0;
vec3 isX = step( x0.yzw, x0.xxx );
vec3 isYZ = step( x0.zww, x0.yyz );
// i0.x = dot( isX, vec3( 1.0 ) );
i0.x = isX.x + isX.y + isX.z;
i0.yzw = 1.0 - isX;
// i0.y += dot( isYZ.xy, vec2( 1.0 ) );
i0.y += isYZ.x + isYZ.y;
i0.zw += 1.0 - isYZ.xy;
i0.z += isYZ.z;
i0.w += 1.0 - isYZ.z;
// i0 now contains the unique values 0,1,2,3 in each channel
vec4 i3 = clamp( i0, 0.0, 1.0 );
vec4 i2 = clamp( i0-1.0, 0.0, 1.0 );
vec4 i1 = clamp( i0-2.0, 0.0, 1.0 );
// x0 = x0 - 0.0 + 0.0 * C.xxxx
// x1 = x0 - i1 + 1.0 * C.xxxx
// x2 = x0 - i2 + 2.0 * C.xxxx
// x3 = x0 - i3 + 3.0 * C.xxxx
// x4 = x0 - 1.0 + 4.0 * C.xxxx
vec4 x1 = x0 - i1 + C.xxxx;
vec4 x2 = x0 - i2 + C.yyyy;
vec4 x3 = x0 - i3 + C.zzzz;
vec4 x4 = x0 + C.wwww;
// Permutations
i = mod289(i);
float j0 = permute( permute( permute( permute(i.w) + i.z) + i.y) + i.x);
vec4 j1 = permute( permute( permute( permute (
i.w + vec4(i1.w, i2.w, i3.w, 1.0 ))
+ i.z + vec4(i1.z, i2.z, i3.z, 1.0 ))
+ i.y + vec4(i1.y, i2.y, i3.y, 1.0 ))
+ i.x + vec4(i1.x, i2.x, i3.x, 1.0 ));
// Gradients: 7x7x6 points over a cube, mapped onto a 4-cross polytope
// 7*7*6 = 294, which is close to the ring size 17*17 = 289.
vec4 ip = vec4(1.0/294.0, 1.0/49.0, 1.0/7.0, 0.0) ;
vec4 p0 = grad4(j0, ip);
vec4 p1 = grad4(j1.x, ip);
vec4 p2 = grad4(j1.y, ip);
vec4 p3 = grad4(j1.z, ip);
vec4 p4 = grad4(j1.w, ip);
// Normalise gradients
vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3)));
p0 *= norm.x;
p1 *= norm.y;
p2 *= norm.z;
p3 *= norm.w;
p4 *= taylorInvSqrt(dot(p4,p4));
// Mix contributions from the five corners
vec3 m0 = max(0.6 - vec3(dot(x0,x0), dot(x1,x1), dot(x2,x2)), 0.0);
vec2 m1 = max(0.6 - vec2(dot(x3,x3), dot(x4,x4) ), 0.0);
m0 = m0 * m0;
m1 = m1 * m1;
return 49.0 * ( dot(m0*m0, vec3( dot( p0, x0 ), dot( p1, x1 ), dot( p2, x2 )))
+ dot(m1*m1, vec2( dot( p3, x3 ), dot( p4, x4 ) ) ) ) ;
}
void main(){
// vec4 p=vec4(vPosition*5.,time*0.2);
// float noisy=fbm(p);
// vec4 p1=vec4(vPosition*2.,time*0.02);
// float spots=max(snoise(p1),0.);
// gl_FragColor=vec4(noisy);
// gl_FragColor*=mix(1.,spots,0.7);
// // gl_FragColor = vec4(vUv,0.0,1.);
// // gl_FragColor=vec4(vPosition,1.);
float noisy=snoise(vec4(vPosition*5.,time));
gl_FragColor=vec4(vUv,0.0,1.);
gl_FragColor=vec4(noisy);
// gl_FragColor=vec4(vPosition,1.);
}
`;
export default fragment;
Vertex
const vertex = `
uniform float time;
varying vec2 vUv;
varying vec3 vPosition;
varying vec2 pixels;
float PI = 3.141592653589793238;
void main(){
vUv = uv;
vPosition = position;
gl_Position = projectionMatrix*modelViewMatrix*vec4(position,1.0);
}
`;
export default vertex;
Thank you in advance for your opinions.

Related

how do i make the html code appear on top of the animation and not behind it

I tried putting this in CSS p{ z-index: 99 !important; } it didn't work
I Just want to make everything in html appear on top of the animation
here is the code::
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
</head>
<body>
<div id="container">
<p>hellpo</p>
</div>
<script id="vertex-shader" type="no-js">
void main() {
gl_Position = vec4( position, 1.0 );
}
</script>
<script id="fragment-shader" type="no-js">
uniform float iGlobalTime;
uniform vec2 iResolution;
const int NUM_STEPS = 8;
const float PI = 3.1415;
const float EPSILON = 1e-3;
float EPSILON_NRM = 0.1 / iResolution.x;
// sea variables
const int ITER_GEOMETRY = 3;
const int ITER_FRAGMENT = 5;
const float SEA_HEIGHT = 0.6;
const float SEA_CHOPPY = 1.0;
const float SEA_SPEED = 1.0;
const float SEA_FREQ = 0.16;
const vec3 SEA_BASE = vec3(0.1,0.19,0.22);
const vec3 SEA_WATER_COLOR = vec3(0.8,0.9,0.6);
float SEA_TIME = iGlobalTime * SEA_SPEED;
mat2 octave_m = mat2(1.6,1.2,-1.2,1.6);
mat3 fromEuler(vec3 ang) {
vec2 a1 = vec2(sin(ang.x),cos(ang.x));
vec2 a2 = vec2(sin(ang.y),cos(ang.y));
vec2 a3 = vec2(sin(ang.z),cos(ang.z));
mat3 m;
m[0] = vec3(
a1.y*a3.y+a1.x*a2.x*a3.x,
a1.y*a2.x*a3.x+a3.y*a1.x,
-a2.y*a3.x
);
m[1] = vec3(-a2.y*a1.x,a1.y*a2.y,a2.x);
m[2] = vec3(
a3.y*a1.x*a2.x+a1.y*a3.x,
a1.x*a3.x-a1.y*a3.y*a2.x,
a2.y*a3.y
);
return m;
}
float hash( vec2 p ) {
float h = dot(p,vec2(127.1,311.7));
return fract(sin(h)*43758.5453123);
}
float noise( in vec2 p ) {
vec2 i = floor(p);
vec2 f = fract(p);
vec2 u = f * f * (3.0 - 2.0 * f);
return -1.0 + 2.0 * mix(
mix(
hash(i + vec2(0.0,0.0)
),
hash(i + vec2(1.0,0.0)), u.x),
mix(hash(i + vec2(0.0,1.0) ),
hash(i + vec2(1.0,1.0) ), u.x),
u.y
);
}
float diffuse(vec3 n,vec3 l,float p) {
return pow(dot(n,l) * 0.4 + 0.6,p);
}
float specular(vec3 n,vec3 l,vec3 e,float s) {
float nrm = (s + 8.0) / (3.1415 * 8.0);
return pow(max(dot(reflect(e,n),l),0.0),s) * nrm;
}
vec3 getSkyColor(vec3 e) {
e.y = max(e.y, 0.0);
vec3 ret;
ret.x = pow(1.0 - e.y, 2.0);
ret.y = 1.0 - e.y;
ret.z = 0.6+(1.0 - e.y) * 0.4;
return ret;
}
float sea_octave(vec2 uv, float choppy) {
uv += noise(uv);
vec2 wv = 1.0 - abs(sin(uv));
vec2 swv = abs(cos(uv));
wv = mix(wv, swv, wv);
return pow(1.0 - pow(wv.x * wv.y, 0.65), choppy);
}
float map(vec3 p) {
float freq = SEA_FREQ;
float amp = SEA_HEIGHT;
float choppy = SEA_CHOPPY;
vec2 uv = p.xz;
uv.x *= 0.75;
float d, h = 0.0;
for(int i = 0; i < ITER_GEOMETRY; i++) {
d = sea_octave((uv + SEA_TIME) * freq, choppy);
d += sea_octave((uv - SEA_TIME) * freq, choppy);
h += d * amp;
uv *= octave_m;
freq *= 1.9;
amp *= 0.22;
choppy = mix(choppy, 1.0, 0.2);
}
return p.y - h;
}
float map_detailed(vec3 p) {
float freq = SEA_FREQ;
float amp = SEA_HEIGHT;
float choppy = SEA_CHOPPY;
vec2 uv = p.xz;
uv.x *= 0.75;
float d, h = 0.0;
for(int i = 0; i < ITER_FRAGMENT; i++) {
d = sea_octave((uv+SEA_TIME) * freq, choppy);
d += sea_octave((uv-SEA_TIME) * freq, choppy);
h += d * amp;
uv *= octave_m;
freq *= 1.9;
amp *= 0.22;
choppy = mix(choppy,1.0,0.2);
}
return p.y - h;
}
vec3 getSeaColor(
vec3 p,
vec3 n,
vec3 l,
vec3 eye,
vec3 dist
) {
float fresnel = 1.0 - max(dot(n,-eye),0.0);
fresnel = pow(fresnel,3.0) * 0.65;
vec3 reflected = getSkyColor(reflect(eye,n));
vec3 refracted = SEA_BASE + diffuse(n,l,80.0) * SEA_WATER_COLOR * 0.12;
vec3 color = mix(refracted,reflected,fresnel);
float atten = max(1.0 - dot(dist,dist) * 0.001, 0.0);
color += SEA_WATER_COLOR * (p.y - SEA_HEIGHT) * 0.18 * atten;
color += vec3(specular(n,l,eye,60.0));
return color;
}
// tracing
vec3 getNormal(vec3 p, float eps) {
vec3 n;
n.y = map_detailed(p);
n.x = map_detailed(vec3(p.x+eps,p.y,p.z)) - n.y;
n.z = map_detailed(vec3(p.x,p.y,p.z+eps)) - n.y;
n.y = eps;
return normalize(n);
}
float heightMapTracing(vec3 ori, vec3 dir, out vec3 p) {
float tm = 0.0;
float tx = 1000.0;
float hx = map(ori + dir * tx);
if(hx > 0.0) {
return tx;
}
float hm = map(ori + dir * tm);
float tmid = 0.0;
for(int i = 0; i < NUM_STEPS; i++) {
tmid = mix(tm,tx, hm/(hm-hx));
p = ori + dir * tmid;
float hmid = map(p);
if(hmid < 0.0) {
tx = tmid;
hx = hmid;
} else {
tm = tmid;
hm = hmid;
}
}
return tmid;
}
void main() {
vec2 uv = gl_FragCoord.xy / iResolution.xy;
uv = uv * 2.0 - 1.0;
uv.x *= iResolution.x / iResolution.y;
float time = iGlobalTime * 0.3;
// ray
vec3 ang = vec3(
sin(time*3.0)*0.1,sin(time)*0.2+0.3,time
);
vec3 ori = vec3(0.0,3.5,time*5.0);
vec3 dir = normalize(
vec3(uv.xy,-2.0)
);
dir.z += length(uv) * 0.15;
dir = normalize(dir);
// tracing
vec3 p;
heightMapTracing(ori,dir,p);
vec3 dist = p - ori;
vec3 n = getNormal(
p,
dot(dist,dist) * EPSILON_NRM
);
vec3 light = normalize(vec3(0.0,1.0,0.8));
// color
vec3 color = mix(
getSkyColor(dir),
getSeaColor(p,n,light,dir,dist),
pow(smoothstep(0.0,-0.05,dir.y),0.3)
);
// post
gl_FragColor = vec4(pow(color,vec3(0.75)), 1.0);
}
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r77/three.min.js"></script>
<script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
<script src="script.js"></script>
</body>
</html>
css
body {
overflow: hidden;
margin: 0;
}
p{ z-index: 99 !important; }
JavaScript
var container,
renderer,
scene,
camera,
mesh,
start = Date.now(),
fov = 30;
var clock = new THREE.Clock();
var timeUniform = {
iGlobalTime: {
type: 'f',
value: 0.1
},
iResolution: {
type: 'v2',
value: new THREE.Vector2()
}
};
timeUniform.iResolution.value.x = window.innerWidth;
timeUniform.iResolution.value.y = window.innerHeight;
window.addEventListener('load', function() {
container = document.getElementById('container');
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(
fov,
window.innerWidth / window.innerHeight,
1,
10000
);
camera.position.x = 20;
camera.position.y = 10;
camera.position.z = 20;
camera.lookAt(scene.position);
scene.add(camera);
var axis = new THREE.AxisHelper(10);
scene.add (axis);
material = new THREE.ShaderMaterial({
uniforms: timeUniform,
vertexShader: document.getElementById('vertex-shader').textContent,
fragmentShader: document.getElementById('fragment-shader').textContent
});
var water = new THREE.Mesh(
new THREE.PlaneBufferGeometry(window.innerWidth, window.innerHeight, 40), material
);
scene.add(water);
var geometry = new THREE.SphereGeometry( 10, 32, 32 );
var material = new THREE.MeshBasicMaterial( {color: 0xffff00} );
var sphere = new THREE.Mesh( geometry, material );
scene.add( sphere );
renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
render();
});
window.addEventListener('resize',function() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
function render() {
timeUniform.iGlobalTime.value += clock.getDelta();
renderer.render(scene, camera);
requestAnimationFrame(render);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
you can wrap ur animation in a div(your ThreeJs canvas). give the div and add this styles to it
position: absolute;
top: 0;
left: 0;
z-index: -1;
and make #container position: relative

How to make a proper planar reflection using ogl with a perspective camera?

I'm trying to reflect a WebGL scene in a plane with ogl, as a mirror would do. I made a naive implementation of the three.js reflector but all I got is a distorted image that doesn't match what an actual reflection would look like.
I get the general idea of how the reflector works by rendering the scene from the virtual reflected point of view of the original camera, adjusting the projection matrix of the virtual camera to render only what projects onto the plane, and later mapping the resulting texture to the plane. But I don't have a complete understanding of all the involved computations (particularly for the two last steps I described).
All I did is copy line by line the three.js reflector and change function names or references, but I can't tell where I'm wrong or what I missed. I would really appreciate any help !
// objects/Reflector.js
import { Transform, Mesh, Plane, Program, RenderTarget, Camera, Vec3, Vec4, Quat, Mat4 } from 'ogl'
import { dot } from 'ogl/src/math/functions/Vec4Func'
import vertex from '../shaders/reflector.vert'
import fragment from '../shaders/reflector.frag'
import { setFromNormalAndCoplanarPoint, transformMat4 } from '../math/PlaneFunc'
import { getRotationMatrix } from '../math/Mat4Func'
import { reflect } from '../math/Vec3Func'
export class Reflector extends Mesh {
constructor(gl, {
scene,
camera,
renderSize = 512,
clipBias = 0
}) {
const renderTarget = new RenderTarget(gl, {
width: renderSize,
height: renderSize
})
super(gl, {
geometry: new Plane(gl),
program: new Program(gl, {
vertex,
fragment,
uniforms: {
textureMatrix: { value: new Mat4() },
diffuseMap: { value: renderTarget.texture }
}
})
})
this.viewCamera = camera
this.clipBias = clipBias
this.reflectionCamera = new Camera(gl)
this.reflectionPlane = new Vec4()
this.reflectionWorldMatrixInverse = new Mat4()
this.reflectionQuaternion = new Quat()
this.worldPosition = new Vec3()
this.normal = new Vec3()
this.view = new Vec3()
this.lookAtPosition = new Vec3()
this.rotationMatrix = new Mat4()
this.target = new Vec3()
this.textureMatrix = this.program.uniforms.textureMatrix.value
this.renderParameters = {
scene,
target: renderTarget,
camera: this.reflectionCamera
}
}
update() {
this.worldMatrix.getTranslation(this.worldPosition)
getRotationMatrix(this.rotationMatrix, this.worldMatrix)
this.normal
.set(0, 0, 1)
.applyMatrix4(this.rotationMatrix)
this.view.sub(this.worldPosition, this.viewCamera.worldPosition)
if (this.view.dot(this.normal) > 0) {
return
}
reflect(this.view, this.view, this.normal)
.negate()
.add(this.worldPosition)
getRotationMatrix(this.rotationMatrix, this.viewCamera.worldMatrix)
this.lookAtPosition.set(0, 0, -1)
this.lookAtPosition.applyMatrix4(this.rotationMatrix)
this.lookAtPosition.add(this.viewCamera.worldPosition)
this.target.sub(this.worldPosition, this.lookAtPosition)
reflect(this.target, this.target, this.normal)
.negate()
.add(this.worldPosition)
this.reflectionCamera.position.copy(this.view)
this.reflectionCamera.up
.set(0, 1, 0)
.applyMatrix4(this.rotationMatrix)
reflect(this.reflectionCamera.up, this.reflectionCamera.up, this.normal)
this.reflectionCamera.lookAt(this.target)
this.reflectionCamera.perspective({
near: this.viewCamera.near,
far: this.viewCamera.far,
fov: this.viewCamera.fov,
aspect: 1
})
this.reflectionCamera.worldMatrixNeedsUpdate = true
this.reflectionCamera.updateMatrixWorld()
this.reflectionWorldMatrixInverse.inverse(this.reflectionCamera.worldMatrix)
this.reflectionCamera.updateFrustum()
this.textureMatrix.set(
0.5, 0.0, 0.0, 0.5,
0.0, 0.5, 0.0, 0.5,
0.0, 0.0, 0.5, 0.5,
0.0, 0.0, 0.0, 1.0
)
this.textureMatrix
.multiply(this.reflectionCamera.projectionMatrix)
.multiply(this.reflectionWorldMatrixInverse)
.multiply(this.worldMatrix)
setFromNormalAndCoplanarPoint(this.reflectionPlane, this.normal, this.worldPosition)
transformMat4(this.reflectionPlane, this.reflectionPlane, this.reflectionWorldMatrixInverse)
const projectionMatrix = this.reflectionCamera.projectionMatrix
this.reflectionQuaternion.set(
(Math.sign(this.reflectionPlane.x) + projectionMatrix[8]) / projectionMatrix[0],
(Math.sign(this.reflectionPlane.y) + projectionMatrix[9]) / projectionMatrix[5],
-1,
(1 + projectionMatrix[10]) / projectionMatrix[14]
)
const f = 2 / dot(this.reflectionPlane, this.reflectionQuaternion)
this.reflectionPlane.x *= f
this.reflectionPlane.y *= f
this.reflectionPlane.z *= f
this.reflectionPlane.w *= f
projectionMatrix[2] = this.reflectionPlane.x
projectionMatrix[6] = this.reflectionPlane.y
projectionMatrix[10] = this.reflectionPlane.z + 1 - this.clipBias
projectionMatrix[14] = this.reflectionPlane.w
this.helper.position.copy(this.reflectionCamera.position)
this.helper.rotation.copy(this.reflectionCamera.rotation)
this.visible = false
this.gl.renderer.render(this.renderParameters)
this.visible = true
}
}
// shaders/reflector.vert
precision highp float;
attribute vec3 position;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
uniform mat4 textureMatrix;
varying vec4 vUv;
void main() {
vUv = textureMatrix * vec4(position, 1.);
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.);
}
// shaders/reflector.frag
precision highp float;
uniform sampler2D diffuseMap;
varying vec4 vUv;
void main() {
vec3 diffuse = texture2DProj(diffuseMap, vUv).rgb;
gl_FragColor = vec4(diffuse, 1.);
}
Here are some math functions available in three.js that I had to implement myself:
// math/Mat4Func.js
import { length } from 'ogl/src/math/functions/Vec3Func'
export function getRotationMatrix(out, m) {
const sX = 1 / length(m.slice(0, 3))
const sY = 1 / length(m.slice(4, 7))
const sZ = 1 / length(m.slice(8, 11))
out[0] = m[0] * sX
out[1] = m[1] * sX
out[2] = m[2] * sX
out[3] = 0
out[4] = m[4] * sY
out[5] = m[5] * sY
out[6] = m[6] * sY
out[7] = 0
out[8] = m[8] * sZ
out[9] = m[9] * sZ
out[10] = m[10] * sZ
out[11] = 0
out[12] = 0
out[13] = 0
out[14] = 0
out[15] = 1
return out
}
// math/PlaneFunc.js
import { normalFromMat4 } from 'ogl/src/math/functions/Mat3Func'
import {
dot,
normalize,
transformMat4 as transformMat4Vec3,
transformMat3 as transformMat3Vec3
} from 'ogl/src/math/functions/Vec3Func'
const normal = []
const normalMatrix = []
const coplanarPoint = []
export function transformMat4(out, p, m) {
normalFromMat4(normalMatrix, m)
getCoplanarPoint(coplanarPoint, p)
transformMat4Vec3(coplanarPoint, coplanarPoint, m)
transformMat3Vec3(normal, p, normalMatrix)
normalize(normal, normal)
setFromNormalAndCoplanarPoint(out, normal, coplanarPoint)
return out
}
export function getCoplanarPoint(out, p) {
out[0] = p[0] * -p[3]
out[1] = p[1] * -p[3]
out[2] = p[2] * -p[3]
return out
}
export function setFromNormalAndCoplanarPoint(out, n, c) {
out[0] = n[0]
out[1] = n[1]
out[2] = n[2]
out[3] = -dot(c, n)
return out
}
// math/Vec3Func.js
import { dot } from 'ogl/src/math/functions/Vec3Func'
export function reflect(out, a, b) {
const f = 2 * dot(a, b)
out[0] = a[0] - b[0] * f
out[1] = a[1] - b[1] * f
out[2] = a[2] - b[2] * f
return out
}

How to add a displacement map to a point material in ThreeJS?

I'm new to ThreeJS and trying to create something like asteroids with textures made of particles (something like from this website https://staratlas.com/). Unfortunately, when I tried to apply a displacement map to a points material nothing worked. How can I resolve this issue?
const dispTexture = new THREE.TextureLoader().load('NormalMap.jpg');
const sphere = new THREE.Points(
new THREE.SphereGeometry(3, 32, 32),
new THREE.PointsMaterial({
size: 0.07,
color: 0xFF325F,
displacementMap: dispTexture,
displacementScale : 0.2,
})
);
scene.add(sphere);
The option, mentioned in comments, with the using of noise. An asteroid of 30K points. Added a simple lighting: the more light on a point, the bigger and brighter it is.
Just in case, codepen: https://codepen.io/prisoner849/pen/mdBzjBy
Maybe it'll be helpful for somebody:
body{
overflow: hidden;
margin: 0;
}
<script>
simplexNoise = `
// Simplex 3D Noise
// by Ian McEwan, Ashima Arts
//
vec4 permute(vec4 x){return mod(((x*34.0)+1.0)*x, 289.0);}
vec4 taylorInvSqrt(vec4 r){return 1.79284291400159 - 0.85373472095314 * r;}
float snoise(vec3 v){
const vec2 C = vec2(1.0/6.0, 1.0/3.0) ;
const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);
// First corner
vec3 i = floor(v + dot(v, C.yyy) );
vec3 x0 = v - i + dot(i, C.xxx) ;
// Other corners
vec3 g = step(x0.yzx, x0.xyz);
vec3 l = 1.0 - g;
vec3 i1 = min( g.xyz, l.zxy );
vec3 i2 = max( g.xyz, l.zxy );
// x0 = x0 - 0. + 0.0 * C
vec3 x1 = x0 - i1 + 1.0 * C.xxx;
vec3 x2 = x0 - i2 + 2.0 * C.xxx;
vec3 x3 = x0 - 1. + 3.0 * C.xxx;
// Permutations
i = mod(i, 289.0 );
vec4 p = permute( permute( permute(
i.z + vec4(0.0, i1.z, i2.z, 1.0 ))
+ i.y + vec4(0.0, i1.y, i2.y, 1.0 ))
+ i.x + vec4(0.0, i1.x, i2.x, 1.0 ));
// Gradients
// ( N*N points uniformly over a square, mapped onto an octahedron.)
float n_ = 1.0/7.0; // N=7
vec3 ns = n_ * D.wyz - D.xzx;
vec4 j = p - 49.0 * floor(p * ns.z *ns.z); // mod(p,N*N)
vec4 x_ = floor(j * ns.z);
vec4 y_ = floor(j - 7.0 * x_ ); // mod(j,N)
vec4 x = x_ *ns.x + ns.yyyy;
vec4 y = y_ *ns.x + ns.yyyy;
vec4 h = 1.0 - abs(x) - abs(y);
vec4 b0 = vec4( x.xy, y.xy );
vec4 b1 = vec4( x.zw, y.zw );
vec4 s0 = floor(b0)*2.0 + 1.0;
vec4 s1 = floor(b1)*2.0 + 1.0;
vec4 sh = -step(h, vec4(0.0));
vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy ;
vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww ;
vec3 p0 = vec3(a0.xy,h.x);
vec3 p1 = vec3(a0.zw,h.y);
vec3 p2 = vec3(a1.xy,h.z);
vec3 p3 = vec3(a1.zw,h.w);
//Normalise gradients
vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3)));
p0 *= norm.x;
p1 *= norm.y;
p2 *= norm.z;
p3 *= norm.w;
// Mix final noise value
vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);
m = m * m;
return 42.0 * dot( m*m, vec4( dot(p0,x0), dot(p1,x1),
dot(p2,x2), dot(p3,x3) ) );
}
`;
</script>
<script type="module">
import * as THREE from "https://cdn.skypack.dev/three#0.136.0";
import {OrbitControls} from "https://cdn.skypack.dev/three#0.136.0/examples/jsm/controls/OrbitControls";
let scene = new THREE.Scene();
let camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 1, 1000);
camera.position.set(0, 0, 10);
let renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize(innerWidth, innerHeight);
//renderer.setClearColor(0xffffff)
document.body.appendChild(renderer.domElement);
window.addEventListener("resize", event => {
camera.aspect = innerWidth / innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(innerWidth, innerHeight);
})
let controls = new OrbitControls(camera, renderer.domElement);
let light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(1, 1, 0);
scene.add(light, new THREE.AmbientLight(0xffffff, 0.5));
//scene.add(new THREE.GridHelper());
let pts = new Array(30000).fill().map(p => {
return new THREE.Vector3().randomDirection().multiplyScalar(4);
});
let g = new THREE.BufferGeometry().setFromPoints(pts);
let u = {
time: {value: 0},
lightPos: {value: new THREE.Vector3()}
}
let m = new THREE.PointsMaterial({
size: 0.075,
color: 0x7fffff,
//map: new THREE.TextureLoader().load("https://threejs.org/examples/textures/sprites/circle.png"),
onBeforeCompile: shader => {
shader.uniforms.lightPos = u.lightPos;
shader.vertexShader = `
uniform float time; // just the force of habit to add it :)
uniform vec3 lightPos;
varying float vShade;
${simplexNoise}
float turbulence( vec3 p ) {
float w = 100.0;
float t = -.5;
for (float f = 1.0 ; f <= 10.0 ; f++ ){
float power = pow( 2.0, f );
t += snoise( vec3( power * p ) ) / power ;
}
return t;
}
vec3 setFromSphericalCoords( float radius, float phi, float theta ) {
float sinPhiRadius = sin( phi ) * radius;
vec3 v = vec3( sinPhiRadius * sin( theta ), cos( phi ) * radius, sinPhiRadius * cos( theta ) );
return v;
}
vec2 setFromCartesianCoords( vec3 v ) {
float radius = sqrt( v.x * v.x + v.y * v.y + v.z * v.z );
float theta = 0.;
float phi = 0.;
if ( radius != 0. ) {
theta = atan( v.x, v.z );
phi = acos( clamp( v.y / radius, - 1., 1. ) );
}
return vec2(phi, theta);
}
vec3 getPoint(vec3 p){
vec3 n = normalize(p);
float s = turbulence(n * 0.5);
return p + n * s;
}
${shader.vertexShader}
`.replace(
`#include <begin_vertex>`,
`#include <begin_vertex>
vec3 p0 = getPoint(position);
vec2 spherical = setFromCartesianCoords(position);
vec2 s = vec2(0.01, 0.);
vec3 p1 = setFromSphericalCoords(length(position), spherical.x + s.x, spherical.y + s.y);
vec3 p2 = setFromSphericalCoords(length(position), spherical.x + s.y, spherical.y + s.x);
p1 = getPoint(p1);
p2 = getPoint(p2);
vec3 nor = normalize(cross(p1 - p0, p2 - p0));
transformed = p0;
`
).replace(
`gl_PointSize = size;`,
`
vec3 lightDir = normalize(lightPos);
float shade = clamp(dot(nor, lightDir), 0., 1.);
vShade = shade;
gl_PointSize = size + (shade * size);`
);
console.log(shader.vertexShader);
shader.fragmentShader = `
varying float vShade;
${shader.fragmentShader}
`.replace(
`vec4 diffuseColor = vec4( diffuse, opacity );`,
`
if(length(gl_PointCoord - 0.5) > 0.5) discard; // make'em round
float shade = vShade * 0.5 + 0.5;
vec4 diffuseColor = vec4( diffuse * shade, opacity );`
);
console.log(shader.fragmentShader);
}
});
let p = new THREE.Points(g, m);
scene.add(p);
let clock = new THREE.Clock();
renderer.setAnimationLoop(() => {
let t = clock.getElapsedTime() * 0.5;
p.rotation.x = t * 0.271;
p.rotation.y = t * 0.314;
p.rotation.z = t * 0.158;
p.worldToLocal(u.lightPos.value.copy(light.position).add(p.position));
renderer.render(scene, camera);
})
</script>

Error in calling createcanvas method of p5.js using webgl

I'm studying p5.js.
While testing the example below locally,
I got the following error:
Here's the code I tested locally:
let flower = (p) => {
let size, shading;
p.setup = function() {
let renderer = p.createCanvas(1024, 768, p.WEBGL);
p.noStroke();
size = p.min(p.width, p.height) / 3;
shading = new p5.Shader(renderer, p.vert, p.frag);
p.shader(shading);
p.mouseX = p.width / 2;
p.mouseY = p.height / 2;
}
p.draw = function() {
p.background("#1a0633");
p.orbitControl();
p.rotateX(p.PI / 2);
let time = p.millis() / 1000;
shading.setUniform('iTime', time);
shading.setUniform('size', size);
shading.setUniform('mouse', [p.mouseX / p.width, p.mouseY / p.height]);
p.plane(1, 1, 100, 100);
}
};
let p5Flower = new p5(flower);
What is causing the error?
You haven't defined any shaders
This error
suggests that p.vert is not set to anything.
Also I'm pretty sure you want to move p.shader(shading) from setup to draw. The only reason it's working in the example is because there is only 1 shader. As soon as there are 2 it will fail. But, that's not why you're getting an error. You're getting an error because p.vert is undefined.
const vert = `precision mediump float;
#define PI 3.14159265359
// our vertex data
attribute vec3 aPosition;
attribute vec2 aTexCoord;
//transform
uniform mat4 uModelViewMatrix;
uniform mat4 uProjectionMatrix;
uniform mat3 uNormalMatrix;
// lets get texcoords just for fun!
varying vec2 vTexCoord;
varying float n;
uniform float iTime;
uniform vec2 mouse;
uniform float size;
// --- Simplex3D noise by Lallis/2015 https://www.shadertoy.com/view/XtBGDG
//http://webstaff.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf
//simplex pretty much 99% copied from there
//adjusted by getting "completely random" gradients instead of randoming from 12 preset ones
//and normalizing the gradient vector
float noise3D(vec3 p)
{
return fract(sin(dot(p ,vec3(12.9898,78.233,128.852))) * 43758.5453)*2.0-1.0;
}
float simplex3D(vec3 p)
{
float f3 = 1.0/3.0;
float s = (p.x+p.y+p.z)*f3;
int i = int(floor(p.x+s));
int j = int(floor(p.y+s));
int k = int(floor(p.z+s));
float g3 = 1.0/6.0;
float t = float((i+j+k))*g3;
float x0 = float(i)-t;
float y0 = float(j)-t;
float z0 = float(k)-t;
x0 = p.x-x0;
y0 = p.y-y0;
z0 = p.z-z0;
int i1,j1,k1;
int i2,j2,k2;
if(x0>=y0)
{
if(y0>=z0){ i1=1; j1=0; k1=0; i2=1; j2=1; k2=0; } // X Y Z order
else if(x0>=z0){ i1=1; j1=0; k1=0; i2=1; j2=0; k2=1; } // X Z Y order
else { i1=0; j1=0; k1=1; i2=1; j2=0; k2=1; } // Z X Z order
}
else
{
if(y0<z0) { i1=0; j1=0; k1=1; i2=0; j2=1; k2=1; } // Z Y X order
else if(x0<z0) { i1=0; j1=1; k1=0; i2=0; j2=1; k2=1; } // Y Z X order
else { i1=0; j1=1; k1=0; i2=1; j2=1; k2=0; } // Y X Z order
}
float x1 = x0 - float(i1) + g3;
float y1 = y0 - float(j1) + g3;
float z1 = z0 - float(k1) + g3;
float x2 = x0 - float(i2) + 2.0*g3;
float y2 = y0 - float(j2) + 2.0*g3;
float z2 = z0 - float(k2) + 2.0*g3;
float x3 = x0 - 1.0 + 3.0*g3;
float y3 = y0 - 1.0 + 3.0*g3;
float z3 = z0 - 1.0 + 3.0*g3;
vec3 ijk0 = vec3(i,j,k);
vec3 ijk1 = vec3(i+i1,j+j1,k+k1);
vec3 ijk2 = vec3(i+i2,j+j2,k+k2);
vec3 ijk3 = vec3(i+1,j+1,k+1);
vec3 gr0 = normalize(vec3(noise3D(ijk0),noise3D(ijk0*2.01),noise3D(ijk0*2.02)));
vec3 gr1 = normalize(vec3(noise3D(ijk1),noise3D(ijk1*2.01),noise3D(ijk1*2.02)));
vec3 gr2 = normalize(vec3(noise3D(ijk2),noise3D(ijk2*2.01),noise3D(ijk2*2.02)));
vec3 gr3 = normalize(vec3(noise3D(ijk3),noise3D(ijk3*2.01),noise3D(ijk3*2.02)));
float n0 = 0.0;
float n1 = 0.0;
float n2 = 0.0;
float n3 = 0.0;
float t0 = 0.5 - x0*x0 - y0*y0 - z0*z0;
if(t0>=0.0)
{
t0*=t0;
n0 = t0 * t0 * dot(gr0, vec3(x0, y0, z0));
}
float t1 = 0.5 - x1*x1 - y1*y1 - z1*z1;
if(t1>=0.0)
{
t1*=t1;
n1 = t1 * t1 * dot(gr1, vec3(x1, y1, z1));
}
float t2 = 0.5 - x2*x2 - y2*y2 - z2*z2;
if(t2>=0.0)
{
t2 *= t2;
n2 = t2 * t2 * dot(gr2, vec3(x2, y2, z2));
}
float t3 = 0.5 - x3*x3 - y3*y3 - z3*z3;
if(t3>=0.0)
{
t3 *= t3;
n3 = t3 * t3 * dot(gr3, vec3(x3, y3, z3));
}
return 96.0*(n0+n1+n2+n3);
}
void main() {
vTexCoord = aTexCoord;
vec4 pos = vec4(aPosition, 1.0);
n = simplex3D(vec3(iTime,pos.xy * 10.))*0.5+0.5;
vec3 temp = pos.xyz;
pos.x = cos(temp.x * PI * 10. * mouse.x) * (n+0.3) * size * (temp.y-mouse.y+0.5);
pos.z = sin(temp.x * PI * 10. * mouse.x) * (n+0.3) * size * (temp.y-mouse.y+0.5);
pos.y = pos.y * size * 3.;
gl_Position = uProjectionMatrix * uModelViewMatrix * pos;
}`
const frag = `precision mediump float;
varying vec2 vTexCoord;
varying float n;
uniform float iTime;
void main()
{
vec2 uv = vTexCoord;//*2.0-1.0;
vec3 col = vec3(n*1.0, n*n*n*0.76, .2);
gl_FragColor = vec4(col, 1.0);
}`
let flower = (p) => {
let size, shading;
p.setup = function() {
let renderer = p.createCanvas(1024, 768, p.WEBGL);
p.noStroke();
size = p.min(p.width, p.height) / 3;
shading = new p5.Shader(renderer, vert, frag);
p.mouseX = p.width / 2;
p.mouseY = p.height / 2;
}
p.draw = function() {
p.background("#1a0633");
p.orbitControl();
p.rotateX(p.PI / 2);
p.shader(shading);
let time = p.millis() / 1000;
shading.setUniform('iTime', time);
shading.setUniform('size', size);
shading.setUniform('mouse', [p.mouseX / p.width, p.mouseY / p.height]);
p.plane(1, 1, 100, 100);
}
};
let p5Flower = new p5(flower);
<script src="https://cdn.jsdelivr.net/npm/p5#0.10.2/lib/p5.js"></script>

Phong and Gouraud Shading WebGL

I read that that in Gouraud Shading, the color for the fragment is computed in the Vertex Shader. Whereas, in Phong Shading, the color for the fragment is computed in the Fragment Shader.
In this implementation , which of these are we using ?
I did not understand exactly the difference between them.
Could anyone help me ? Thanks
<button id = "ButtonX">Rotate X</button>
<button id = "ButtonY">Rotate Y</button>
<button id = "ButtonZ">Rotate Z</button>
<button id = "ButtonT">Toggle Rotation</button>
<button id="Direction">Change Direction</button>
<button id="OrthoPersp">Change Ortho/Persp</button>
<div>Traslation on X <input id="slideX" type="range"
min="-1" max="1" step="0.1" value="0" />
</div>
<div>Traslation on Y <input id="slideY" type="range"
min="-1" max="1" step="0.1" value="0" />
</div>
<div>Traslation on Z <input id="slideZ" type="range"
min="-1" max="1" step="0.1" value="0" />
</div>
<div>Scaling on X <input id="ScalingX" type="range"
min="0" max="1" step="0.1" value="0" />
</div>
<div>Scaling on Y <input id="ScalingY" type="range"
min="0" max="1" step="0.1" value="0" />
</div>
<div>Scaling on Z <input id="ScalingZ" type="range"
min="0" max="1" step="0.1" value="0" />
</div>
<div>
zNear Min<input id="zNearSlider" type="range" min="0.00" max="2.8" step="0.1" value="0.3">
Max
</div>
<div>
zFar Min<input id="zFarSlider" type="range" min="3" max="10" step="3.0" value="3">
Max
</div>
<script id="vertex-shader" type="x-shader/x-vertex">
attribute vec4 vPosition;
attribute vec4 vColor;
varying vec4 fColor;
//uniform vec3 theta;
// Point 2 -> Move the matrices
// Per spostare le matrici le abbiamo dovuto dichiarare nel file GLSL come uniform
// le matrici rx ry e rz sono rispettivamente le matrici di rotazione sugli assi
uniform mat4 rx;
uniform mat4 ry;
uniform mat4 rz;
// Points 3 -> Traslation Matrix
uniform mat4 traslation;
// Points 3 -> Scaling Matrix
uniform mat4 scaling;
//Point 4 -> MV and P matrices
uniform mat4 modelView;
uniform mat4 projection;
//Poinit 6 -> Light Source
attribute vec4 vNormal;
uniform vec4 ambientProduct, diffuseProduct, specularProduct;
uniform vec4 lightPosition;
uniform float shininess;
void main()
{
// Compute the sines and cosines of theta for each of
// the three axes in one computation.
//vec3 angles = radians( theta );
//vec3 c = cos( angles );
//vec3 s = sin( angles );
// Remember: the matrices are column-major
/*
mat4 rx = mat4( 1.0, 0.0, 0.0, 0.0,
0.0, c.x, s.x, 0.0,
0.0, -s.x, c.x, 0.0,
0.0, 0.0, 0.0, 1.0 );
mat4 ry = mat4( c.y, 0.0, -s.y, 0.0,
0.0, 1.0, 0.0, 0.0,
s.y, 0.0, c.y, 0.0,
0.0, 0.0, 0.0, 1.0 );
mat4 rz = mat4( c.z, s.z, 0.0, 0.0,
-s.z, c.z, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0 );
*/
//fColor = vColor;
// ORDINE : scaling -> rotazione -> traslation
//gl_Position = projection*modelView*scaling *rz * ry * rx * traslation *vPosition ;
//gl_Position.z = -gl_Position.z;
//Point 6
vec3 pos = -(modelView * vPosition).xyz;
vec3 light = lightPosition.xyz;
vec3 L = normalize( light - pos );
vec3 E = normalize( -pos );
vec3 H = normalize( L + E );
vec3 N = normalize( (modelView*vNormal).xyz);
vec4 ambient = ambientProduct;
float Kd = max( dot(L, N), 0.0 );
vec4 diffuse = Kd*diffuseProduct;
float Ks = pow( max(dot(N, H), 0.0), shininess );
vec4 specular = Ks * specularProduct;
if( dot(L, N) < 0.0 ) {
specular = vec4(0.0, 0.0, 0.0, 1.0);
}
fColor = ambient + diffuse + specular;
fColor.a = 1.0;
gl_Position = projection*modelView*scaling *rz * ry * rx * traslation *vPosition ;
gl_Position.z = -gl_Position.z;
// *******************
}
</script>
<script id="fragment-shader" type="x-shader/x-fragment">
precision mediump float;
varying vec4 fColor;
void
main()
{
gl_FragColor = fColor;
}
</script>
<script type="text/javascript" src="../Common/webgl-utils.js"></script>
<script type="text/javascript" src="../Common/initShaders.js"></script>
<script type="text/javascript" src="../Common/MV.js"></script>
<script type="text/javascript" src="Homework1.js"></script>
<body>
<canvas id="gl-canvas" width="1024" height="1024">
Oops ... your browser doesn't support the HTML5 canvas element
</canvas>
</body>
</html>
I did not understand exactly the difference between them. Could anyone help me ?
The technique used in the code snippet of the question is Gouraud Shading.
In common Phong shading means the technique, which does the light calculations per fragment, in compare at Gouraud Shading, the light calculations ar done per vertex.
This means that at Phong shading the light calcualtions ar done in the fragment shader (Not to be confused with Phong reflection model).
Phong shading:
At Gouraud Shading the light calculations are done in the vertex shader, for the corners of the primitives (corners of the triangles). The calculated light is (either in a perspective correct manner or linearly) interpolated for all the fragments covered by the primitive, according to the Barycentric coordinate. This increases the performance, but gives a big loss of quality, especially on large primitives and strong specular highlights.
Gouraud Shading:
Note, the light is not linear distributed on a surface. If the light is only calculated for some samples and interpolated in between them, this causes flat stains.
See the example, which compares the 2 techniques:
(function loadscene() {
var resize, gl, gouraudDraw, phongDraw, vp_size;
var bufSphere = {};
function render(delteMS){
var shading = document.getElementById( "shading" ).value;
var shininess = document.getElementById( "shininess" ).value;
var ambientCol = [0.2, 0.2, 0.2];
var diffuseCol = [0.6, 0.6, 0.6];
var specularCol = [0.8, 0.8, 0.8];
Camera.create();
Camera.vp = vp_size;
gl.enable( gl.DEPTH_TEST );
gl.clearColor( 0.0, 0.0, 0.0, 1.0 );
gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );
gl.enable(gl.CULL_FACE);
gl.cullFace(gl.BACK);
//gl.frontFace(gl.CW);
gl.frontFace(gl.CCW);
var progDraw = shading == 0 ? gouraudDraw : phongDraw;;
// set up draw shader
ShaderProgram.Use( progDraw.prog );
ShaderProgram.SetUniformM44( progDraw.prog, "u_projectionMat44", Camera.Perspective() );
ShaderProgram.SetUniformM44( progDraw.prog, "u_viewMat44", Camera.LookAt() );
ShaderProgram.SetUniformF3( progDraw.prog, "u_lightSource.lightDir", [-1.0, -0.5, -2.0] )
ShaderProgram.SetUniformF3( progDraw.prog, "u_lightSource.ambient", ambientCol )
ShaderProgram.SetUniformF3( progDraw.prog, "u_lightSource.diffuse", diffuseCol )
ShaderProgram.SetUniformF3( progDraw.prog, "u_lightSource.specular", specularCol )
ShaderProgram.SetUniformF1( progDraw.prog, "u_lightSource.shininess", shininess )
var modelMat = IdentityMat44()
modelMat = RotateAxis( modelMat, CalcAng( delteMS, 13.0 ), 0 );
modelMat = RotateAxis( modelMat, CalcAng( delteMS, 17.0 ), 1 );
ShaderProgram.SetUniformM44( progDraw.prog, "u_modelMat44", modelMat );
// draw scene
VertexBuffer.Draw( bufSphere );
requestAnimationFrame(render);
}
function resize() {
//vp_size = [gl.drawingBufferWidth, gl.drawingBufferHeight];
vp_size = [window.innerWidth, window.innerHeight]
canvas.width = vp_size[0];
canvas.height = vp_size[1];
gl.viewport( 0, 0, vp_size[0], vp_size[1] );
}
function initScene() {
canvas = document.getElementById( "canvas");
gl = canvas.getContext( "experimental-webgl" );
if ( !gl )
return null;
gouraudDraw = {}
gouraudDraw.prog = ShaderProgram.Create(
[ { source : "gouraud-shader-vs", stage : gl.VERTEX_SHADER },
{ source : "gouraud-shader-fs", stage : gl.FRAGMENT_SHADER }
],
[ "u_projectionMat44", "u_viewMat44", "u_modelMat44",
"u_lightSource.lightDir", "u_lightSource.ambient", "u_lightSource.diffuse", "u_lightSource.specular", "u_lightSource.shininess", ] );
if ( gouraudDraw.prog == 0 )
return;
gouraudDraw.inPos = gl.getAttribLocation( gouraudDraw.prog, "inPos" );
gouraudDraw.inNV = gl.getAttribLocation( gouraudDraw.prog, "inNV" );
gouraudDraw.inCol = gl.getAttribLocation( gouraudDraw.prog, "inCol" );
phongDraw = {}
phongDraw.prog = ShaderProgram.Create(
[ { source : "phong-shader-vs", stage : gl.VERTEX_SHADER },
{ source : "phong-shader-fs", stage : gl.FRAGMENT_SHADER }
],
[ "u_projectionMat44", "u_viewMat44", "u_modelMat44",
"u_lightSource.lightDir", "u_lightSource.ambient", "u_lightSource.diffuse", "u_lightSource.specular", "u_lightSource.shininess", ] );
if ( phongDraw.prog == 0 )
return;
phongDraw.inPos = gl.getAttribLocation( phongDraw.prog, "inPos" );
phongDraw.inNV = gl.getAttribLocation( phongDraw.prog, "inNV" );
phongDraw.inCol = gl.getAttribLocation( phongDraw.prog, "inCol" );
// create cube
var layer_size = 16, circum_size = 32;
var rad_circum = 1.0;
var rad_tube = 0.5;
var sphere_pts = [];
var sphere_nv = [];
var sphere_col = [];
sphere_pts.push( 0.0, 0.0, -2.0 );
sphere_nv.push( 0.0, 0.0, -1.0 );
sphere_col.push( 0.8, 0.6, 0.3 );
for ( var i_l = 1; i_l < layer_size; ++ i_l ) {
var angH = (1.0 - i_l / layer_size) * Math.PI;
var h = Math.cos( angH );
var r = Math.sin( angH );
for ( var i_c = 0; i_c < circum_size; ++ i_c ) {
var circumX = Math.cos(2 * Math.PI * i_c / circum_size);
var circumY = Math.sin(2 * Math.PI * i_c / circum_size);
sphere_pts.push( r * circumX * 2.0, r * circumY * 2.0, h * 2.0 );
sphere_nv.push( r * circumX, r * circumY, h );
sphere_col.push( 0.8, 0.6, 0.3 );
}
}
sphere_pts.push( 0.0, 0.0, 2.0 );
sphere_nv.push( 0.0, 0.0, 1.0 );
sphere_col.push( 0.75, 0.75, 0.75 );
var sphere_inx = [];
for ( var i_c = 0; i_c < circum_size; ++ i_c ) {
sphere_inx.push( i_c+1, 0, (i_c+1) % circum_size + 1 )
}
for ( var i_l = 0; i_l < layer_size-2; ++ i_l ) {
var l1 = i_l * circum_size + 1;
var l2 = (i_l+1) * circum_size + 1
for ( var i_c = 0; i_c < circum_size; ++ i_c ) {
var i_n = (i_c+1) % circum_size;
sphere_inx.push( l1+i_c, l1+i_n, l2+i_c, l1+i_n, l2+i_n, l2+i_c );
}
}
for ( var i_c = 0; i_c < circum_size; ++ i_c ) {
var i_start = 1 + (layer_size-2) * circum_size;
var i_n = (i_c+1) % circum_size;
sphere_inx.push( i_start + i_c, i_start + i_n, sphere_pts.length/3-1 );
}
bufSphere = VertexBuffer.Create(
[ { data : sphere_pts, attrSize : 3, attrLoc : gouraudDraw.inPos },
{ data : sphere_nv, attrSize : 3, attrLoc : gouraudDraw.inNV },
{ data : sphere_col, attrSize : 3, attrLoc : gouraudDraw.inCol } ],
sphere_inx );
window.onresize = resize;
resize();
requestAnimationFrame(render);
}
function Fract( val ) {
return val - Math.trunc( val );
}
function CalcAng( deltaTime, intervall ) {
return Fract( deltaTime / (1000*intervall) ) * 2.0 * Math.PI;
}
function CalcMove( deltaTime, intervall, range ) {
var pos = self.Fract( deltaTime / (1000*intervall) ) * 2.0
var pos = pos < 1.0 ? pos : (2.0-pos)
return range[0] + (range[1] - range[0]) * pos;
}
function EllipticalPosition( a, b, angRag ) {
var a_b = a * a - b * b
var ea = (a_b <= 0) ? 0 : Math.sqrt( a_b );
var eb = (a_b >= 0) ? 0 : Math.sqrt( -a_b );
return [ a * Math.sin( angRag ) - ea, b * Math.cos( angRag ) - eb, 0 ];
}
glArrayType = typeof Float32Array !="undefined" ? Float32Array : ( typeof WebGLFloatArray != "undefined" ? WebGLFloatArray : Array );
function IdentityMat44() {
var m = new glArrayType(16);
m[0] = 1; m[1] = 0; m[2] = 0; m[3] = 0;
m[4] = 0; m[5] = 1; m[6] = 0; m[7] = 0;
m[8] = 0; m[9] = 0; m[10] = 1; m[11] = 0;
m[12] = 0; m[13] = 0; m[14] = 0; m[15] = 1;
return m;
};
function RotateAxis(matA, angRad, axis) {
var aMap = [ [1, 2], [2, 0], [0, 1] ];
var a0 = aMap[axis][0], a1 = aMap[axis][1];
var sinAng = Math.sin(angRad), cosAng = Math.cos(angRad);
var matB = new glArrayType(16);
for ( var i = 0; i < 16; ++ i ) matB[i] = matA[i];
for ( var i = 0; i < 3; ++ i ) {
matB[a0*4+i] = matA[a0*4+i] * cosAng + matA[a1*4+i] * sinAng;
matB[a1*4+i] = matA[a0*4+i] * -sinAng + matA[a1*4+i] * cosAng;
}
return matB;
}
function Cross( a, b ) { return [ a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0], 0.0 ]; }
function Dot( a, b ) { return a[0]*b[0] + a[1]*b[1] + a[2]*b[2]; }
function Normalize( v ) {
var len = Math.sqrt( v[0] * v[0] + v[1] * v[1] + v[2] * v[2] );
return [ v[0] / len, v[1] / len, v[2] / len ];
}
var Camera = {};
Camera.create = function() {
this.pos = [0, 3, 0.0];
this.target = [0, 0, 0];
this.up = [0, 0, 1];
this.fov_y = 90;
this.vp = [800, 600];
this.near = 0.5;
this.far = 100.0;
}
Camera.Perspective = function() {
var fn = this.far + this.near;
var f_n = this.far - this.near;
var r = this.vp[0] / this.vp[1];
var t = 1 / Math.tan( Math.PI * this.fov_y / 360 );
var m = IdentityMat44();
m[0] = t/r; m[1] = 0; m[2] = 0; m[3] = 0;
m[4] = 0; m[5] = t; m[6] = 0; m[7] = 0;
m[8] = 0; m[9] = 0; m[10] = -fn / f_n; m[11] = -1;
m[12] = 0; m[13] = 0; m[14] = -2 * this.far * this.near / f_n; m[15] = 0;
return m;
}
Camera.LookAt = function() {
var mz = Normalize( [ this.pos[0]-this.target[0], this.pos[1]-this.target[1], this.pos[2]-this.target[2] ] );
var mx = Normalize( Cross( this.up, mz ) );
var my = Normalize( Cross( mz, mx ) );
var tx = Dot( mx, this.pos );
var ty = Dot( my, this.pos );
var tz = Dot( [-mz[0], -mz[1], -mz[2]], this.pos );
var m = IdentityMat44();
m[0] = mx[0]; m[1] = my[0]; m[2] = mz[0]; m[3] = 0;
m[4] = mx[1]; m[5] = my[1]; m[6] = mz[1]; m[7] = 0;
m[8] = mx[2]; m[9] = my[2]; m[10] = mz[2]; m[11] = 0;
m[12] = tx; m[13] = ty; m[14] = tz; m[15] = 1;
return m;
}
var ShaderProgram = {};
ShaderProgram.Create = function( shaderList ) {
var shaderObjs = [];
for ( var i_sh = 0; i_sh < shaderList.length; ++ i_sh ) {
var shderObj = this.CompileShader( shaderList[i_sh].source, shaderList[i_sh].stage );
if ( shderObj == 0 )
return 0;
shaderObjs.push( shderObj );
}
var progObj = this.LinkProgram( shaderObjs )
if ( progObj != 0 ) {
progObj.attribIndex = {};
var noOfAttributes = gl.getProgramParameter( progObj, gl.ACTIVE_ATTRIBUTES );
for ( var i_n = 0; i_n < noOfAttributes; ++ i_n ) {
var name = gl.getActiveAttrib( progObj, i_n ).name;
progObj.attribIndex[name] = gl.getAttribLocation( progObj, name );
}
progObj.unifomLocation = {};
var noOfUniforms = gl.getProgramParameter( progObj, gl.ACTIVE_UNIFORMS );
for ( var i_n = 0; i_n < noOfUniforms; ++ i_n ) {
var name = gl.getActiveUniform( progObj, i_n ).name;
progObj.unifomLocation[name] = gl.getUniformLocation( progObj, name );
}
}
return progObj;
}
ShaderProgram.AttributeIndex = function( progObj, name ) { return progObj.attribIndex[name]; }
ShaderProgram.UniformLocation = function( progObj, name ) { return progObj.unifomLocation[name]; }
ShaderProgram.Use = function( progObj ) { gl.useProgram( progObj ); }
ShaderProgram.SetUniformI1 = function( progObj, name, val ) { if(progObj.unifomLocation[name]) gl.uniform1i( progObj.unifomLocation[name], val ); }
ShaderProgram.SetUniformF1 = function( progObj, name, val ) { if(progObj.unifomLocation[name]) gl.uniform1f( progObj.unifomLocation[name], val ); }
ShaderProgram.SetUniformF2 = function( progObj, name, arr ) { if(progObj.unifomLocation[name]) gl.uniform2fv( progObj.unifomLocation[name], arr ); }
ShaderProgram.SetUniformF3 = function( progObj, name, arr ) { if(progObj.unifomLocation[name]) gl.uniform3fv( progObj.unifomLocation[name], arr ); }
ShaderProgram.SetUniformF4 = function( progObj, name, arr ) { if(progObj.unifomLocation[name]) gl.uniform4fv( progObj.unifomLocation[name], arr ); }
ShaderProgram.SetUniformM33 = function( progObj, name, mat ) { if(progObj.unifomLocation[name]) gl.uniformMatrix3fv( progObj.unifomLocation[name], false, mat ); }
ShaderProgram.SetUniformM44 = function( progObj, name, mat ) { if(progObj.unifomLocation[name]) gl.uniformMatrix4fv( progObj.unifomLocation[name], false, mat ); }
ShaderProgram.CompileShader = function( source, shaderStage ) {
var shaderScript = document.getElementById(source);
if (shaderScript)
source = shaderScript.text;
var shaderObj = gl.createShader( shaderStage );
gl.shaderSource( shaderObj, source );
gl.compileShader( shaderObj );
var status = gl.getShaderParameter( shaderObj, gl.COMPILE_STATUS );
if ( !status ) alert(gl.getShaderInfoLog(shaderObj));
return status ? shaderObj : null;
}
ShaderProgram.LinkProgram = function( shaderObjs ) {
var prog = gl.createProgram();
for ( var i_sh = 0; i_sh < shaderObjs.length; ++ i_sh )
gl.attachShader( prog, shaderObjs[i_sh] );
gl.linkProgram( prog );
status = gl.getProgramParameter( prog, gl.LINK_STATUS );
if ( !status ) alert("Could not initialise shaders");
gl.useProgram( null );
return status ? prog : null;
}
var VertexBuffer = {};
VertexBuffer.Create = function( attributes, indices ) {
var buffer = {};
buffer.buf = [];
buffer.attr = []
for ( var i = 0; i < attributes.length; ++ i ) {
buffer.buf.push( gl.createBuffer() );
buffer.attr.push( { size : attributes[i].attrSize, loc : attributes[i].attrLoc } );
gl.bindBuffer( gl.ARRAY_BUFFER, buffer.buf[i] );
gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( attributes[i].data ), gl.STATIC_DRAW );
}
buffer.inx = gl.createBuffer();
gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, buffer.inx );
gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, new Uint16Array( indices ), gl.STATIC_DRAW );
buffer.inxLen = indices.length;
gl.bindBuffer( gl.ARRAY_BUFFER, null );
gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, null );
return buffer;
}
VertexBuffer.Draw = function( bufObj ) {
for ( var i = 0; i < bufObj.buf.length; ++ i ) {
gl.bindBuffer( gl.ARRAY_BUFFER, bufObj.buf[i] );
gl.vertexAttribPointer( bufObj.attr[i].loc, bufObj.attr[i].size, gl.FLOAT, false, 0, 0 );
gl.enableVertexAttribArray( bufObj.attr[i].loc );
}
gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, bufObj.inx );
gl.drawElements( gl.TRIANGLES, bufObj.inxLen, gl.UNSIGNED_SHORT, 0 );
for ( var i = 0; i < bufObj.buf.length; ++ i )
gl.disableVertexAttribArray( bufObj.attr[i].loc );
gl.bindBuffer( gl.ARRAY_BUFFER, null );
gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, null );
}
initScene();
})();
<style>
html,body {
height: 100%;
width: 100%;
margin: 0;
overflow: hidden;
}
#gui {
position : absolute;
top : 0;
left : 0;
}
</style>
<script id="gouraud-shader-vs" type="x-shader/x-vertex">
precision mediump float;
attribute vec3 inPos;
attribute vec3 inNV;
attribute vec3 inCol;
varying vec3 vertPos;
varying vec3 vertNV;
varying vec3 vertCol;
uniform mat4 u_projectionMat44;
uniform mat4 u_viewMat44;
uniform mat4 u_modelMat44;
struct TLightSource
{
vec3 lightDir;
vec3 ambient;
vec3 diffuse;
vec3 specular;
float shininess;
};
uniform TLightSource u_lightSource;
vec3 Light( vec3 eyeV, vec3 N )
{
vec3 lightCol = u_lightSource.ambient;
vec3 L = normalize( -u_lightSource.lightDir );
float NdotL = max( 0.0, dot( N, L ) );
lightCol += NdotL * u_lightSource.diffuse;
vec3 H = normalize( eyeV + L );
float NdotH = max( 0.0, dot( N, H ) );
float kSpecular = ( u_lightSource.shininess + 2.0 ) * pow( NdotH, u_lightSource.shininess ) / ( 2.0 * 3.14159265 );
lightCol += kSpecular * u_lightSource.specular;
return lightCol;
}
void main()
{
vec3 modelNV = mat3( u_modelMat44 ) * normalize( inNV );
vertNV = mat3( u_viewMat44 ) * modelNV;
vec4 modelPos = u_modelMat44 * vec4( inPos, 1.0 );
vec4 viewPos = u_viewMat44 * modelPos;
vertPos = viewPos.xyz / viewPos.w;
vec3 eyeV = normalize( -vertPos );
vec3 normalV = normalize( vertNV );
vertCol = inCol * Light( eyeV, normalV );
gl_Position = u_projectionMat44 * viewPos;
}
</script>
<script id="gouraud-shader-fs" type="x-shader/x-fragment">
precision mediump float;
varying vec3 vertPos;
varying vec3 vertNV;
varying vec3 vertCol;
void main()
{
gl_FragColor = vec4( vertCol, 1.0 );
}
</script>
<script id="phong-shader-vs" type="x-shader/x-vertex">
precision mediump float;
attribute vec3 inPos;
attribute vec3 inNV;
attribute vec3 inCol;
varying vec3 vertPos;
varying vec3 vertNV;
varying vec3 vertCol;
uniform mat4 u_projectionMat44;
uniform mat4 u_viewMat44;
uniform mat4 u_modelMat44;
void main()
{
vec3 modelNV = mat3( u_modelMat44 ) * normalize( inNV );
vertNV = mat3( u_viewMat44 ) * modelNV;
vertCol = inCol;
vec4 modelPos = u_modelMat44 * vec4( inPos, 1.0 );
vec4 viewPos = u_viewMat44 * modelPos;
vertPos = viewPos.xyz / viewPos.w;
gl_Position = u_projectionMat44 * viewPos;
}
</script>
<script id="phong-shader-fs" type="x-shader/x-fragment">
precision mediump float;
varying vec3 vertPos;
varying vec3 vertNV;
varying vec3 vertCol;
struct TLightSource
{
vec3 lightDir;
vec3 ambient;
vec3 diffuse;
vec3 specular;
float shininess;
};
uniform TLightSource u_lightSource;
vec3 Light( vec3 eyeV, vec3 N )
{
vec3 lightCol = u_lightSource.ambient;
vec3 L = normalize( -u_lightSource.lightDir );
float NdotL = max( 0.0, dot( N, L ) );
lightCol += NdotL * u_lightSource.diffuse;
vec3 H = normalize( eyeV + L );
float NdotH = max( 0.0, dot( N, H ) );
float kSpecular = ( u_lightSource.shininess + 2.0 ) * pow( NdotH, u_lightSource.shininess ) / ( 2.0 * 3.14159265 );
lightCol += kSpecular * u_lightSource.specular;
return lightCol;
}
void main()
{
vec3 eyeV = normalize( -vertPos );
vec3 normalV = normalize( vertNV );
vec3 color = vertCol * Light( eyeV, normalV );
gl_FragColor = vec4( color, 1.0 );
}
</script>
<form id="gui" name="inputs"><table><tr>
<td><font color= #CCF>Shading:</font></td>
<td><select id="shading">>
<option value="0">Gouraud</option>
<option value="1">Phong</option>
</select></td>
</tr><tr>
<td><font color= #CCF>Shininess:</font></td>
<td><input type="range" id="shininess" min="0" max="100" value="20"/></td>
</tr></table></form>
<canvas id="canvas" style="border: none;" width="100%" height="100%"></canvas>

Categories