Three.js로 만들어봄. 깊이맵으로 가까이 있으면 glow 효과 나오게 함. (gl_FragCoord
의 z값 처리는 아직 안 함)
Code
Vertex shader
void main()
{
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
Fragment Shader
// Screen size
uniform sampler2D depthMap;
uniform vec2 screenSize;
void main()
{
float depth = texture2D(depthMap, gl_FragCoord.xy / screenSize).r;
float logDiff = log(1000.0 * abs(gl_FragCoord.z - depth));
float glow = clamp(1.0 - logDiff, 0.0, 1.0);
float alpha = 0.5 + glow;
gl_FragColor = vec4(0.27450982 + glow, 0.64705884 + glow, 0.9647059 + glow, alpha);
}
메인 스크립트 (typescript)
import * as THREE from "./lib/three.module";
class ShieldShaderEx {
readonly screenWidth: number = 600;
readonly screenHeight: number = 400;
readonly screenSize: THREE.Vector2 = new THREE.Vector2(this.screenWidth, this.screenHeight);
scene: THREE.Scene;
renderer: THREE.WebGLRenderer;
camera: THREE.Camera;
light: THREE.DirectionalLight;
loader: THREE.TextureLoader;
depthTarget: THREE.WebGLRenderTarget;
torusMesh: THREE.Mesh;
shieldMesh: THREE.Mesh;
clock: THREE.Clock;
constructor() {
// init loader
this.loader = new THREE.TextureLoader();
this.loader.setCrossOrigin("anonymous");
// init renderer
this.renderer = new THREE.WebGLRenderer();
this.renderer.setSize(this.screenWidth, this.screenHeight);
this.renderer.setClearColor(0xdbdbdb);
document.body.appendChild(this.renderer.domElement);
// init scene and camera
this.scene = new THREE.Scene();
const aspectRatio: number = this.screenWidth / this.screenHeight;
this.camera = new THREE.PerspectiveCamera(40, aspectRatio, 1, 10000);
this.camera.position.set(20, 20, 20);
this.camera.lookAt(new THREE.Vector3(0, 0, 0));
// init depth rendertarget
this.depthTarget = new THREE.WebGLRenderTarget(this.screenWidth, this.screenHeight);
this.depthTarget.depthTexture = new THREE.DepthTexture(this.screenWidth, this.screenHeight);
// init directional light
this.light = new THREE.DirectionalLight(0xffffff, 1);
this.light.position.set(20, 50, 0);
this.scene.add(this.light);
this.initMeshes();
this.clock = new THREE.Clock();
}
initMeshes() {
// 1. create torus
{
// geometry & material
let geometry: THREE.TorusKnotGeometry = new THREE.TorusKnotGeometry( 3, 1, 100, 64 );
let material: THREE.Material = new THREE.MeshBasicMaterial({
color: 0x44c99d,
});
// mesh
this.torusMesh = new THREE.Mesh(geometry, material);
this.scene.add(this.torusMesh);
this.torusMesh.position.x -= 8;
}
// 2. create shield
{
let vertexShader = document.getElementById('vertexshader').innerHTML;
let fragShader = document.getElementById('fragmentshader').innerHTML
let geometry: THREE.PlaneGeometry = new THREE.PlaneGeometry(20, 15);
let material: THREE.ShaderMaterial = new THREE.ShaderMaterial({
uniforms: {
depthMap: { type: "t", value: this.depthTarget.depthTexture },
screenSize: { type: "v", value: this.screenSize },
},
vertexShader: vertexShader,
fragmentShader: fragShader,
transparent: true,
side: THREE.DoubleSide,
});
this.shieldMesh = new THREE.Mesh(geometry, material);
this.scene.add(this.shieldMesh);
}
}
update(delta: number) {
if (typeof this.torusMesh !== "undefined") {
this.torusMesh.rotation.x += 0.6 * delta;
this.torusMesh.rotation.y += 0.06 * delta;
this.torusMesh.rotation.z += 0.3 * delta;
}
if (typeof this.shieldMesh !== "undefined")
this.shieldMesh.rotation.y -= 0.6 * delta;
}
render() {
requestAnimationFrame(() => this.render());
let delta: number = this.clock.getDelta();
this.update(delta);
// draw depthmap
if (typeof this.shieldMesh !== "undefined") {
this.shieldMesh.visible = false;
this.renderer.render(this.scene, this.camera, this.depthTarget);
this.shieldMesh.visible = true;
}
// draw main scene
this.renderer.render(this.scene, this.camera);
}
run() {
this.render();
}
}
let example = new ShieldShaderEx();
example.run();
'프로그래밍' 카테고리의 다른 글
Roslyn으로 C# 코드 정적 분석하기 (0) | 2018.03.05 |
---|---|
C#: object => IEnumerable<object> (0) | 2017.11.21 |
Using Linq in Unity3d (0) | 2017.10.29 |
쿼터니온(Quaternion) 정리 (5) | 2017.08.28 |
렌더링 파이프라인에서 왜 동차 좌표계를 쓸까 (4) | 2017.07.09 |