From: Jerome St-Louis Date: Wed, 3 Aug 2016 22:23:30 +0000 (-0400) Subject: samples/3D: Added materials sample with reflection, refraction and normals mapping X-Git-Tag: 0.44.15~40 X-Git-Url: http://ecere.com/cgi-bin/gitweb.cgi?p=sdk;a=commitdiff_plain;h=6d07000298669de83e592350ec74fb88bacd26c2 samples/3D: Added materials sample with reflection, refraction and normals mapping --- diff --git a/samples/3D/materials/materials.ec b/samples/3D/materials/materials.ec new file mode 100644 index 0000000..8871f22 --- /dev/null +++ b/samples/3D/materials/materials.ec @@ -0,0 +1,486 @@ +#ifdef ECERE_STATIC +import static "ecere" +#else +import "ecere" +#endif + +class MyApp : GuiApplication +{ + driver = "OpenGL"; + // driver = "Direct3D"; + timerResolution = 60; + + bool Cycle(bool idle) + { + materialsTest.updateModel(); + return true; + } +}; + +Camera camera +{ + attached, + position = Vector3D { 0, 0, -300 }, + orientation = Euler { }; //30, 30, 0 }, + fovDirection = vertical, + fov = 53; +}; + +Object cameraTarget { }; + +Object posLight +{ + transform = { position = { 0, 0, -10 }, scaling = { 1, 1, 1 } }; + light = + { + multiplier = 1.0f; + diffuse = white; + Kc = 1.0; + //Kc = 0.8; + Kl = 0.00002; + Kq = 0.000002; + specular = white; //blue; + //flags = { attenuation = true }; + lightObject = posLight; + }; +}; + +Light light +{ + specular = white; + multiplier = 1.0f; + diffuse = white; + orientation = Euler { pitch = 40, yaw = 50 }; +}; + + +define rGlass = 1.52; +define rWater = 1.33; +define rIce = 1.309; +define rDiamond = 2.42; + +class MaterialsTest : Window +{ + caption = "Materials Test"; + background = black; +#if defined(__EMSCRIPTEN__) + anchor = { 0, 0, 0, 0 }; +#else + borderStyle = sizable; + hasMaximize = true; + hasMinimize = true; + hasClose = true; + size = { 640, 480 }; + state = maximized; +#endif + // glCapabilities.shaders = true; + + Cube cube { }; + Sphere sphere { }; + Sphere roundedCylinder { flattenedBody = 0.3f }; + Object teapot { }; + + Object model; + + Euler spin { }; + + SkyBox waterBox + { + size = { 10000, 10000, 10000 }, + folder = ":watersky", extension = "jpg", + cubeMap = waterCubeMap + }; + + /* + SkyBox forestBox + { + size = { 10000, 10000, 10000 }, + folder = ":forest", extension = "jpg", newStyle = true, + cubeMap = forestCubeMap + }; + */ + SkyBox sky; + font = { "Tahoma", 12, true, outlineSize = 3.0, outlineFade = 0.2 }; + + bool updateModel() + { + static Time lastTime = 0; + Time time = GetTime(), diffTime = lastTime ? (time - lastTime) : 0; + Transform transform = model.transform; + if(spin.yaw || spin.pitch) + { + int signYaw = 1, signPitch = 1; + Radians yaw = spin.yaw, pitch = spin.pitch; + Quaternion orientation = transform.orientation; + Euler tSpin { yaw * (double)diffTime, pitch * (double)diffTime, 0 }; + Quaternion thisSpin = tSpin, temp; + + if(yaw < 0) { yaw = -yaw; signYaw = -1; } + if(pitch < 0) { pitch = -pitch; signPitch = -1; } + yaw -= (double)diffTime / 3 * yaw; + pitch -= (double)diffTime / 3 * pitch; + if(yaw < 0.0001) yaw = 0; + if(pitch < 0.0001) pitch = 0; + + spin.yaw = yaw * signYaw; + spin.pitch = pitch * signPitch; + + temp.Multiply(orientation, thisSpin); + orientation.Normalize(temp); + + model.transform.orientation = orientation; + //transform.orientation = orientation; + //model.transform = transform; + model.UpdateTransform(); + Update(null); + } + lastTime = time; + return true; + } + + /* + BitmapResource bumpMap { "bumpmap.png", window = this }; + BitmapResource baseMap { "basetex.bmp", window = this }; + */ + BitmapResource bumpMap { ":normal.jpg", mipMaps = true, window = this }; + // BitmapResource bumpMap { ":normal.png", mipMaps = true, window = this }; + //BitmapResource baseMap { "diffuse.png", mipMaps = true, window = this }; + // BitmapResource specularMap { "specular.jpg", mipMaps = true, window = this }; + CubeMap waterCubeMap { }; + //CubeMap forestCubeMap { }; + + Material material + { + ambient = blue; //white; + diffuse = blue; //white; + //specular = { 3.0, 3.0, 3.0 }; + specular = { 1.0, 1.0, 3.0 }; + power = 60.0; + flags = + { + doubleSided = true; + tile = true; + separateSpecular = true; + }; + uScale = 4, vScale = 4; + reflectivity = 0.3; + refractiveIndex = rGlass; + opacity = 0.3; + }; + + void prepareModel(Object model, float s) + { + model.transform.scaling = { s, s, s }; + model.transform.position = { 0, 0, 0 }; + model.UpdateTransform(); + model.SetMinMaxRadius(false); + model.mesh.ApplyMaterial(material); + } + + void viewModel(Object model, double distance, float uvScale) + { + double r = model.radius * model.transform.scaling.z; //wradius; + material.uScale = uvScale; + material.vScale = uvScale; + camera.position = { 0, 0, -r * distance }; + cameraTarget.transform.position = + { + (model.max.x + model.min.x) / 2, + (model.max.y + model.min.y) / 2, + (model.max.z + model.min.z) / 2 + }; + this.model = model; + Update(null); + } + + void selectEnv(SkyBox sky, CubeMap cubeMap) + { + material.envMap = cubeMap; + this.sky = sky; + Update(null); + } + + bool OnLoadGraphics() + { + const String faceNames1[] = { ":watersky/rt", ":watersky/lf", ":watersky/up", ":watersky/dn", ":watersky/bk", ":watersky/fr" }; + //const String faceNames2[] = { ":forest/rt", ":forest/lf", ":forest/up", ":forest/dn", ":forest/bk", ":forest/fr" }; + + //material.bumpMap = bumpMap.bitmap; + //material.baseMap = baseMap.bitmap; + //material.specularMap = specularMap.bitmap; + //material.reflectMap = specularMap.bitmap; + + // Water & Sky + if(!waterCubeMap.Load(displaySystem, faceNames1, "jpg", true)) waterBox.cubeMap = null; + // Forest Cube + //if(!forestCubeMap.Load(displaySystem, faceNames2, "jpg", false)) forestBox.cubeMap = null; + + teapot.Load(":teapot.3DS", null, displaySystem); + teapot.Merge(displaySystem); + teapot.mesh.ApplyMaterial(material); + prepareModel(teapot, 1); + + roundedCylinder.Create(displaySystem); + prepareModel(roundedCylinder, 50); + + sphere.Create(displaySystem); + prepareModel(sphere, 50); + + cube.Create(displaySystem); + prepareModel(cube, 50); + + camera.target = cameraTarget; + camera.zMin = 1; + camera.zMax = 10000; + + waterBox.size = { camera.zMax, camera.zMax, camera.zMax }; + //forestBox.size = { camera.zMax, camera.zMax, camera.zMax }; + waterBox.Create(displaySystem); + //forestBox.Create(displaySystem); + + viewModel(sphere, 1.5 * sqrt(2), 4.0); + //viewModel(cube, 1.5 * 2, 2); + //viewModel(teapot, 1.5 * 2, 2); + selectEnv(waterBox, waterCubeMap); + // selectEnv(forestBox, forestCubeMap); + return true; + } + + void OnResize(int w, int h) + { + camera.Setup(w, h, null); + camera.Update(); + } + + void OnRedraw(Surface surface) + { + int x, y; + + camera.Update(); + GetMousePosition(&x, &y); + + posLight.transform.position = + { + (x - clientSize.w / 2) * 400 / clientSize.w, + (y - clientSize.h / 2) * 400 / clientSize.h, + - 2 * model.wradius + }; + posLight.UpdateTransform(); + + surface.Clear(depthBuffer); + + // Setting the light before the camera means the light is in view space + //display.SetLight(0, posLight.light); + display.SetLight(0, light); + // display.ambient = { }; + + //display.ambient = { 255, 0, 0 }; + display.SetCamera(surface, camera); + + // Setting the light before the camera means the light is in world space + //display.SetLight(0, light); + + sky.Render(camera, display); + + display.DrawObject(model); + display.SetCamera(surface, null); + + surface.outlineColor = black; + surface.foreground = white; + + surface.WriteTextf(10, 10, "('R' to toggle') Reflection: %s, Refraction: %s", + material.reflectivity ? "ON" : "OFF", + material.refractiveIndex ? "ON" : "OFF"); + surface.WriteTextf(10, 40, "('C' to toggle') Shape: %s ", + model == cube ? "Cube" : model == sphere ? "Sphere" : model == roundedCylinder ? "Rounded Cylinder" : "Teapot"); + /*surface.WriteTextf(10, 70, "('E' to toggle') Environment: %s", + material.envMap == waterCubeMap ? "Water & Sky" : "Forest");*/ + surface.WriteTextf(10, 100, "('B' to toggle') Normal Map: %s", + material.bumpMap ? "ON" : "OFF"); + surface.WriteTextf(10, 130, "Left-Button Drag: Rotate Camera; Middle-Button Drag: Spin Model; Right-Button Drag: Rotate Light"); + surface.WriteTextf(10, 160, "Scroll Wheel: Move camera closer / further"); +#ifndef __EMSCRIPTEN__ + surface.WriteTextf(10, 200, "Shaders: %s", glCapabilities.shaders ? "ON" : "OFF"); +#endif + } + + Point startClick; + bool moving, movingCamera, movingLight; + Time clickTime; + Point startPosition; + Euler startOrientation; + + bool OnMiddleButtonDown(int x, int y, Modifiers mods) + { + clickTime = GetTime(); + Capture(); + startClick = { x, y }; + moving = true; + return true; + } + + bool OnMiddleButtonUp(int x, int y, Modifiers mods) + { + if(moving) + { + ReleaseCapture(); + moving = false; + } + return true; + } + + bool OnLeftButtonDown(int x, int y, Modifiers mods) + { + if(!movingCamera && !moving && !movingLight) + { + startPosition.x = x; + startPosition.y = y; + startOrientation = camera.eulerOrientation; + Capture(); + movingCamera = true; + } + return true; + } + + bool OnLeftButtonUp(int x, int y, Modifiers mods) + { + if(movingCamera) + { + ReleaseCapture(); + movingCamera = false; + } + return true; + } + + bool OnRightButtonDown(int x, int y, Modifiers mods) + { + if(!moving && !movingLight) + { + startPosition.x = x; + startPosition.y = y; + startOrientation = light.orientation; + Capture(); + movingLight = true; + } + return true; + } + + bool OnRightButtonUp(int x, int y, Modifiers mods) + { + if(movingLight) + { + ReleaseCapture(); + movingLight = false; + } + return true; + } + + bool OnMouseMove(int x, int y, Modifiers mods) + { + if(moving) + { + Time time = GetTime(), diffTime = Max(time - clickTime, 0.01); + spin.yaw += Degrees { (x - startClick.x) / (25.0 * (double)diffTime) }; + spin.pitch += Degrees { (startClick.y - y) / (25.0 * (double)diffTime) }; + startClick = { x, y }; + clickTime = time; + } + else if(movingCamera) + { + Euler euler + { + startOrientation.yaw - (x - startPosition.x), + startOrientation.pitch + (y - startPosition.y), + 0 + }; + + camera.eulerOrientation = euler; + + Update(null); + } + else if(movingLight) + { + light.orientation = Euler + { + startOrientation.yaw - (x - startPosition.x), + startOrientation.pitch + (y - startPosition.y), + 0 + }; + + Update(null); + } + Update(null); + return true; + } + + bool OnKeyHit(Key key, unichar ch) + { + switch(key) + { + case wheelDown: case minus: camera.position.z *= 1.1111111f; Update(null); break; + case wheelUp: case plus: camera.position.z *= 0.9f; Update(null); break; + case f3: + glCapabilities.shaders ^= true; + Update(null); + break; + case c: + if(model == cube) + viewModel(sphere, 1.5 * sqrt(2), 4); + else if(model == sphere) + viewModel(roundedCylinder, 1.5 * sqrt(2), 4); + else if(model == roundedCylinder) + viewModel(teapot, 1.5 * sqrt(2), 1.5); + else if(model == teapot) + viewModel(cube, 1.5 * 2, 2); + Update(null); + break; + /*case e: + if(sky == waterBox) + selectEnv(forestBox, forestCubeMap); + else + selectEnv(waterBox, waterCubeMap); + break;*/ + case d: + { + static bool debugging = false; + debugging ^= true; + DefaultShader::shader().debugging(debugging); + Update(null); + break; + } + case b: + material.bumpMap = material.bumpMap ? null : bumpMap.bitmap; + Update(null); + break; + case r: + if(material.reflectivity && material.refractiveIndex) + { + material.refractiveIndex = 0; + material.opacity = 1.0; + material.reflectivity = 0.8; + } + else if(material.reflectivity) + { + material.reflectivity = 0; + material.refractiveIndex = rGlass; + material.opacity = 0.3; + } + else if(material.refractiveIndex) + { + material.refractiveIndex = 0.0; + material.opacity = 1.0; + } + else + { + material.reflectivity = 0.3; + material.refractiveIndex = rGlass; + material.opacity = 0.3; + } + Update(null); + break; + } + return true; + } +} + +MaterialsTest materialsTest {}; diff --git a/samples/3D/materials/materials.epj b/samples/3D/materials/materials.epj new file mode 100644 index 0000000..900cbdc --- /dev/null +++ b/samples/3D/materials/materials.epj @@ -0,0 +1,112 @@ +{ + "Version" : 0.2, + "ModuleName" : "materials", + "Options" : { + "Warnings" : "All", + "TargetType" : "Executable", + "TargetFileName" : "materials", + "Libraries" : [ + "ecere" + ] + }, + "Configurations" : [ + { + "Name" : "Debug", + "Options" : { + "Debug" : true, + "Optimization" : "None", + "PreprocessorDefinitions" : [ + "_DEBUG" + ], + "Console" : true, + "FastMath" : false + } + }, + { + "Name" : "Release", + "Options" : { + "Debug" : false, + "Optimization" : "Speed", + "FastMath" : true + } + }, + { + "Name" : "Emscripten", + "Options" : { + "Optimization" : "Speed", + "PreprocessorDefinitions" : [ + "ECERE_STATIC" + ], + "TargetFileName" : "materials.html", + "Libraries" : [ + "ecereStatic", + "z", + "freetype", + "jpeg", + "png" + ], + "LibraryDirs" : [ + "../../../ecere/obj/emscripten.linux.emscripten" + ], + "FastMath" : true + } + } + ], + "Files" : [ + "materials.ec" + ], + "ResourcesPath" : "", + "Resources" : [ + { + "Folder" : "watersky", + "Files" : [ + "../ModelViewer/skycube/bk.jpg", + "../ModelViewer/skycube/dn.jpg", + "../ModelViewer/skycube/fr.jpg", + "../ModelViewer/skycube/lf.jpg", + "../ModelViewer/skycube/rt.jpg", + "../ModelViewer/skycube/up.jpg" + ] + }, + { + "Folder" : "forest", + "Files" : [ + "bk.jpg", + "dn.jpg", + "fr.jpg", + "lf.jpg", + "rt.jpg", + "up.jpg" + ], + "Options" : { + "ExcludeFromBuild" : true + } + }, + { + "Folder" : "ecere", + "Files" : [ + { + "Folder" : "shaders", + "Files" : [ + "../../../ecere/src/gfx/drivers/gl3/default.frag", + "../../../ecere/src/gfx/drivers/gl3/default.vert" + ] + }, + "C:/Windows/Fonts/tahomabd.ttf" + ], + "Options" : { + "ExcludeFromBuild" : true + }, + "Configurations" : [ + { + "Name" : "Emscripten", + "Options" : { + "ExcludeFromBuild" : false + } + } + ] + }, + "teapot.3DS", + "normal.jpg" + ] +} diff --git a/samples/3D/materials/normal.jpg b/samples/3D/materials/normal.jpg new file mode 100644 index 0000000..f175dc8 Binary files /dev/null and b/samples/3D/materials/normal.jpg differ diff --git a/samples/3D/materials/teapot.3DS b/samples/3D/materials/teapot.3DS new file mode 100644 index 0000000..c48f27e Binary files /dev/null and b/samples/3D/materials/teapot.3DS differ