• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.

ne0_kamen

Members
  • Content count

    110
  • Joined

  • Last visited

Community Reputation

371 Neutral

About ne0_kamen

  • Rank
    Member
  1. I second this suggestion.
  2. This is slightly off topic, but for anyone who haven't seen this I strongly recommend watching the lecture. The passion Mr. Crawford puts into the presentation is mind boggling.   It would be interesting topic of conversation to discuss whether his conclusion that interactive storytelling is (was) the future is really true. From a business point of view, I think all his attempts to create such games are failures. However, I would classify a recent game such as Beyond Two Souls as Interactive story telling. Maybe not in the way Chris Crawford envisioned, but similar. Is there a whole new genre of games, which potential is not fully discovered yet?
  3.     mapxoff/mapyoff are my camera variables. They move along with my player and yes the position of the rings depend on them. If they are not in range of my camera, they don't render, heres the code in case: //update the map scroll position //camera coordinates mapxoff = player->x + player->width/2 - WIDTH/2 + 10; mapyoff = player->y + player->height/2 - HEIGHT/2 + 10; //Avoid moving beyond the map edge if(mapxoff < 0) mapxoff = 0; if(mapxoff > mapwidth*mapblockwidth - WIDTH) mapxoff = mapwidth*mapblockwidth - WIDTH; if(mapyoff < 0) mapyoff = 0; if(mapyoff > mapheight*mapblockheight - HEIGHT) mapyoff = mapheight*mapblockheight - HEIGHT;   You should have everything in the same coordinate system. For collision detection, you don't need to "scroll" the world using camera offset, just use the object's world coordinates like this :                //find the center of the player             x = player->x + player->width/2;             y = player->y + player->height/2;             //get the rings bounding rectangle             x1 = rings[n]->x ;             y1 = rings[n]->y;             x2 = x1 + rings[n]->width;             y2 = y1 + rings[n]->height;   Hope this helps, Kamen
  4. Hello, Recently, looking for new information on Half-life 3 or episode 3 I stumbled upon this article/video : [url="http://www.gamespot.com/news/half-life-3-wait-explained-6372687"]http://www.gamespot....plained-6372687[/url] [media]http://www.youtube.com/watch?feature=player_embedded&v=6VofXcw8AJQ[/media] While the article doesn't provide much information about the upcoming games of the franchise, I found the video very interesting - it summarizes very nicely what I think was great about half life 1/2 and stuff that's missing in today's fps games. The level design, the story and characters, the original weapons, the scripted events of dying scientists, the g-man encounters, the fun and replay value of the games... It just seems it isn't there in modern FPS games. Admittedly, I haven't played any of the latest shooters (my last one was Crysis 1), so I want to ask what do you think about this? Are the developers responsible for not putting enough love/work/passion into the product or is it just that today's gamers don't need games like Half-life anymore?
  5. As always, great work!!
  6. Hello, My exams are over (finally). One of the courses I took this semester was introduction to the Ruby language. For the final exam, we had to make some project of moderate complexity. The result was like 90% web apps (written using Rails), several console apps and several games (most of which were chess simulators, they seem to be beloved among the academia). So I figured I would do a very basic game I never did before - Tetris. Ruby is a really cool language for prototyping and its amazing how much time it could save you with its "blocks passed as arguments" and extensive Enumerable class methods. For the graphics front-end/window creation and sound, I used gosu. Its amazingly simple and fast enough for the job. It took me a few hours to program the whole thing (+unit tests). The result is not bad, but apparently not good enough (I got a 4 out of 6 score). The biggest remark I got from my lecturer was that my rendering and game logic was too tightly coupled together. Which is true, of course. However, I believe that decoupling them would complicate things quite a bit (and thus make the project bigger, andwould take me more time). I just don't get why the professors always think an over-engineered, but "extensible and maintainable" solution isbetter than a simple one. Its not like I'm going to bring my course work into a full blown product. Source require 'gosu' class Block attr_accessor :falling attr_accessor :x, :y, :width, :height, :color @@image = nil def initialize(game) # Image is loaded only once for all blocks if @@image == nil @@image = Gosu::Image.new(game, "block.png", false) end @x = 0 @y = 0 @width = @@image.width; @height = @@image.height @game = game @color = 0xffffffff end def draw @@image.draw(@x, @y, 0, 1, 1, @color) end def collide(block) # Two blocks collide only when they are at the same position, since the world is a grid return (block.x == @x && block.y == @y) end def collide_with_other_blocks @game.blocks.each do |block| if collide(block) return block end end nil end end class Shape attr_accessor :rotation def initialize(game) @game = game @last_fall_update = Gosu::milliseconds @last_move_update = Gosu::milliseconds @blocks = [Block.new(game), Block.new(game), Block.new(game), Block.new(game) ] @x = @y = 0 @falling = true # Rotation is done about this block @rotation_block = @blocks[1] # How many rotations we can do before a full cycle? @rotation_cycle = 1 # Current rotation state @rotation = 0 end def apply_rotation # Each rotation is a 90 degree in the clockwise direction if @rotation_block != nil (1..@rotation.modulo(@rotation_cycle)).each do |i| @blocks.each do |block| old_x = block.x old_y = block.y block.x = @rotation_block.x + (@rotation_block.y - old_y) block.y = @rotation_block.y - (@rotation_block.x - old_x) end end end end # Note that the following function is defined properly only when the object is unrotated # Otherwise the line of symmetry will be misplaced and wrong results will be produced def reverse # Mirror the shape by the y axis, effectively creating shape counterparts such as 'L' and 'J' center = (get_bounds[2] + get_bounds[0]) / 2.0 @blocks.each do |block| block.x = 2*center - block.x - @game.block_width end end def get_bounds # Go throug all blocks to find the bounds of this shape x_min = [] y_min = [] x_max = [] y_max = [] @blocks.each do |block| x_min @game.width ) return true end if ( bounds[0] < 0 ) return true end return false end end class ShapeI < Shape def initialize(game) super(game) @rotation_block = @blocks[1] @rotation_cycle = 2 end def get_blocks @blocks[0].x = @x @blocks[1].x = @x @blocks[2].x = @x @blocks[3].x = @x @blocks[0].y = @y @blocks[1].y = @blocks[0].y + @blocks[0].height @blocks[2].y = @blocks[1].y + @blocks[1].height @blocks[3].y = @blocks[2].y + @blocks[2].height apply_rotation @blocks.each { |block| block.color = 0xffb2ffff } end end class ShapeL < Shape def initialize(game) super(game) @rotation_block = @blocks[1] @rotation_cycle = 4 end def get_blocks @blocks[0].x = @x @blocks[1].x = @x @blocks[2].x = @x @blocks[3].x = @x + @game.block_width @blocks[0].y = @y @blocks[1].y = @blocks[0].y + @game.block_height @blocks[2].y = @blocks[1].y + @game.block_height @blocks[3].y = @blocks[2].y apply_rotation @blocks.each { |block| block.color = 0xffff7f00 } end end class ShapeJ < ShapeL def get_blocks # Reverse will reverse also the direction of rotation that's applied in apply_rotation # This will temporary disable rotation in the super method, so we can handle the rotation here after the reverse old_rotation = @rotation @rotation = 0 super reverse @rotation = old_rotation apply_rotation @blocks.each { |block| block.color = 0xff0000ff} end end class ShapeCube < Shape def get_blocks @blocks[0].x = @x @blocks[1].x = @x @blocks[2].x = @x + @game.block_width @blocks[3].x = @x + @game.block_width @blocks[0].y = @y @blocks[1].y = @blocks[0].y + @game.block_height @blocks[2].y = @blocks[0].y @blocks[3].y = @blocks[2].y + @game.block_height @blocks.each { |block| block.color = 0xffffff00} end end class ShapeZ < Shape def initialize(game) super(game) @rotation_block = @blocks[1] @rotation_cycle = 2 end def get_blocks @blocks[0].x = @x @blocks[1].x = @x + @game.block_width @blocks[2].x = @x + @game.block_width @blocks[3].x = @x + @game.block_width*2 @blocks[0].y = @y @blocks[1].y = @y @blocks[2].y = @y + @game.block_height @blocks[3].y = @y + @game.block_height apply_rotation @blocks.each { |block| block.color = 0xffff0000} end end class ShapeS < ShapeZ def get_blocks # Reverse will reverse also the direction of rotation that's applied in apply_rotation # This will temporary disable rotation in the super method, so we can handle the rotation here after the reverse old_rotation = @rotation @rotation = 0 super reverse @rotation = old_rotation apply_rotation @blocks.each { |block| block.color = 0xff00ff00} end end class ShapeT < Shape def initialize(game) super(game) @rotation_block = @blocks[1] @rotation_cycle = 4 end def get_blocks @blocks[0].x = @x @blocks[1].x = @x + @game.block_width @blocks[2].x = @x + @game.block_width*2 @blocks[3].x = @x + @game.block_width @blocks[0].y = @y @blocks[1].y = @y @blocks[2].y = @y @blocks[3].y = @y + @game.block_height apply_rotation @blocks.each { |block| block.color = 0xffff00ff} end end class TetrisGameWindow < Gosu::Window attr_accessor :blocks attr_reader :block_height, :block_width attr_reader :level attr_reader :falling_shape STATE_PLAY = 1 STATE_GAMEOVER = 2 def initialize super(320, 640, false) @block_width = 32 @block_height = 32 @blocks = [] @state = STATE_PLAY spawn_next_shape @lines_cleared = 0 @level = 0 self.caption = "Tetris : #{@lines_cleared} lines" @song = Gosu::Song.new("TetrisB_8bit.ogg") end def update if ( @state == STATE_PLAY ) if ( @falling_shape.collide ) @state = STATE_GAMEOVER else @falling_shape.update end @level = @lines_cleared / 10 self.caption = "Tetris : #{@lines_cleared} lines" else if ( button_down?(Gosu::KbSpace) ) @blocks = [] @falling_shape = nil @level = 0 @lines_cleared = 0 spawn_next_shape @state = STATE_PLAY end end if ( button_down?(Gosu::KbEscape) ) close end @song.play(true) end def draw @blocks.each { |block| block.draw } @falling_shape.draw if @state == STATE_GAMEOVER text = Gosu::Image.from_text(self, "Game Over", "Arial", 40) text.draw(width/2 - 90, height/2 - 20, 0, 1, 1) end end def button_down(id) # Rotate shape when space is pressed if ( id == Gosu::KbSpace && @falling_shape != nil ) @falling_shape.rotation += 1 if ( @falling_shape.collide ) @falling_shape.rotation -= 1 end end end def spawn_next_shape # Spawn a random shape and add the current falling shape' blocks to the "static" blocks list if (@falling_shape != nil ) @blocks += @falling_shape.get_blocks end generator = Random.new shapes = [ShapeI.new(self), ShapeL.new(self), ShapeJ.new(self), ShapeCube.new(self), ShapeZ.new(self), ShapeT.new(self), ShapeS.new(self)] shape = generator.rand(0..(shapes.length-1)) @falling_shape = shapes[shape] end def line_complete(y) # Important is that the screen resolution should be divisable by the block_width, otherwise there would be gap # If the count of blocks at a line is equal to the max possible blocks for any line - the line is complete i = @blocks.count{|item| item.y == y} if ( i == width / block_width ) return true; end return false; end def delete_lines_of( shape ) # Go through each block of the shape and check if the lines they are on are complete deleted_lines = [] shape.get_blocks.each do |block| if ( line_complete(block.y) ) deleted_lines.push(block.y) @blocks = @blocks.delete_if { |item| item.y == block.y } end end @lines_cleared += deleted_lines.length # This applies the standard gravity found in classic Tetris games - all blocks go down by the # amount of lines cleared @blocks.each do |block| i = deleted_lines.count{ |y| y > block.y } block.y += i*block_height end end end # This global prevents creation of the window and start of the simulation when we are doing testing if ( !$testing ) window = TetrisGameWindow.new window.show end And unit tests (they were required) $testing = true require "./tetris.rb" require "test/unit" class TestTetris < Test::Unit::TestCase def setup @game = TetrisGameWindow.new @w = @game.block_width @h = @game.block_height end def test_shapes_construction assert_equal(4, ShapeI.new(@game).get_blocks.length, "ShapeI must be constructed of 4 blocks") assert_equal(4, ShapeT.new(@game).get_blocks.length, "ShapeT must be constructed of 4 blocks") assert_equal(4, ShapeJ.new(@game).get_blocks.length, "ShapeJ must be constructed of 4 blocks") assert_equal(4, ShapeZ.new(@game).get_blocks.length, "ShapeZ must be constructed of 4 blocks") assert_equal(4, ShapeCube.new(@game).get_blocks.length, "ShapeO must be constructed of 4 blocks") assert_equal(4, ShapeS.new(@game).get_blocks.length, "ShapeS must be constructed of 4 blocks") assert_equal(4, ShapeL.new(@game).get_blocks.length, "ShapeL must be constructed of 4 blocks") assert_not_equal(nil, @game.falling_shape, "Falling shape shoudn't be nil") end def test_shapes_rotation shape = ShapeI.new(@game) shape.rotation = 1 assert(shape_contain_block(shape, -2*@w, @h), "Rotation of I failed!") assert(shape_contain_block(shape, -@w, @h), "Rotation of I failed!") assert(shape_contain_block(shape, 0, @h), "Rotation of I failed!") assert(shape_contain_block(shape, @w, @h), "Rotation of I failed!") shape = ShapeL.new(@game) shape.rotation = 2 assert(shape_contain_block(shape, -@w, 0), "Rotation of L failed!") assert(shape_contain_block(shape, 0, 0), "Rotation of L failed!") assert(shape_contain_block(shape, 0, @h), "Rotation of L failed!") assert(shape_contain_block(shape, 0, 2*@h), "Rotation of L failed!") shape = ShapeJ.new(@game) shape.rotation = 2 assert(shape_contain_block(shape, 2*@w, 0), "Rotation of J failed!") assert(shape_contain_block(shape, @w, 0), "Rotation of J failed!") assert(shape_contain_block(shape, @w, @h), "Rotation of J failed!") assert(shape_contain_block(shape, @w, 2*@h), "Rotation of J failed!") shape = ShapeZ.new(@game) shape.rotation = 2 assert(shape_contain_block(shape, 0, 0), "Rotation of Z failed!") assert(shape_contain_block(shape, @w, 0), "Rotation of Z failed!") assert(shape_contain_block(shape, @w, @h), "Rotation of Z failed!") assert(shape_contain_block(shape, 2*@w, @h), "Rotation of Z failed!") shape = ShapeS.new(@game) shape.rotation = 1 assert(shape_contain_block(shape, 0, -@h), "Rotation of S failed!") assert(shape_contain_block(shape, 0, 0), "Rotation of S failed!") assert(shape_contain_block(shape, @w, 0), "Rotation of S failed!") assert(shape_contain_block(shape, @w, @h), "Rotation of S failed!") shape = ShapeT.new(@game) shape.rotation = 3 assert(shape_contain_block(shape, @w, -@h), "Rotation of T failed!") assert(shape_contain_block(shape, @w, 0), "Rotation of T failed!") assert(shape_contain_block(shape, 2*@w, 0), "Rotation of T failed!") assert(shape_contain_block(shape, @w, @h), "Rotation of T failed!") end def test_block_collision block1 = Block.new(@game) block2 = Block.new(@game) block2.x = @w block2.y = 0 assert_equal(false, block1.collide(block2), "Blocks should not collide") block2.x = 0 block2.y = 0 assert_equal(true, block1.collide(block2), "Blocks should collide") end def test_line_complete (0.. (@game.width/@w - 1)).each do |i| add_block(i*@w, 0) end (0.. (@game.width/@w - 2)).each do |i| add_block(i*@w, @h) end assert_equal(true, @game.line_complete(0), "Line should be complete") assert_equal(false, @game.line_complete(@h), "Line should not be complete") shapeI = ShapeI.new(@game) @game.delete_lines_of(shapeI) (0.. (@game.width/@w - 1)).each do |i| assert_equal(false, contain_block(@game.blocks, i*@w, 0), "Line 0 should be deleted ") end end def add_block(x,y) block = Block.new(@game) block.x = x block.y = y @game.blocks If you run the game in the ruby 1.9 interpreter, be sure to install gosu : gem install gosu
  7. I've done some research, and you are correct - every single source seems to point out that OpenCL does not support recursion. However, in my code recursion definitely works (as seen from the reflection and refraction in the images). My guess is either the latest version of OpenCL recently changed that or more likely the ATI drivers automatically emulates the recursion for you. I'm pretty sure there is performance overhead in doing so, and even more so - the recursion rays are not computed in parallel . So regardless if OpenCL support recursion or not, you probably should use non-recursive raytracing for optimum speed.
  8. I think I know where is the problem. First, you are "adding" and "subtracting" the target's x,y,z to the LookAtMatrix's translation vector. This is doing nothing. You should create new translation matrices with these offsets and multiply the LookAtMatrix by them(as I did in the formula). Second, the "old" transformation (Matrix4f transform(LookAtMatrix) ) is screwing you. There would be rotations and translations in this "old" matrix and they will affect what you are trying to do (I think). Now the first problem is easy to solve. The second is harder. I think the correct order is this : [CODE] // Store our old global translation Vector3 lookAtMatrixTranslation(LookAtMatrix[12],LookAtMatrix[13],LookAtMatrix[14]); // We need just the rotation part of the lookAtMatrix Matrix4f lookAtMatrixRotation(LookAtMatrix); lookAtMatrixRotation[12] = lookAtMatrixRotation[13] = lookAtMatrixRotation[14] = 0; // Here we can add the offsets directly (or use SetTranslation), because transform is the Identity matrix Matrix4f transform = Matrix4f().SetTranslation(target); // Multiply it by the old rotation - note that the old rotation does not affect the current translation transform = transform*lookAtMatrixRotation; // Not sure if you need to create new matrices here, depends on the realization of RotateAngle transform.RotateAngle(mouse_x, upVector); transform.RotateAngle(mouse_y, rightVector); // Finally translate back, but create new matrix and multiply by it // Also add the previous (global) translation transform = transform*Matrix4f().SetTranslation(-target+lookAtMatrixTranslation); LocalTranslation = Vector3(transform[12], transform[13], transform[14]); LocalRotation.SetFromMatrix(transform); [/CODE] This is very untested, so I may be missing something crucial. I'm very sure that you need to create new translation matrices and multiply by them, but not sure how to handle the old translation/rotation. Perhaps somebody else can help there
  9. [size=3]So you can't use the formula because you forced the order of rotation/scalation/translation multiplication? This is possible, but I think forcing the order is not a good idea (because it makes simple things complicated). You could provide a default multiplication order, but still allow for it to be changed. To answer your question : Compute the transformation as I said above. Then, set the [/size][size=3][left]LocalTranslation to the translation vector of the transformation.[/left][/size] [left][size=3][color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]Compute the quaternion as you do usually,[/font][/color][/size][/left] [left][size=3][color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]I have not tested this [/font][/color][/size][color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif][size=3]and some of your math function's names are a bit vague, but its something worth trying [/size][/font][/color][img]http://public.gamedev.net//public/style_emoticons/default/smile.png[/img][/left] [left][size=3][color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]The idea is that you would still be rotating around (0,0,0), but then you will translate the objects to their proper locations.[/font][/color][/size][/left] [left][size=3][color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]Also its very important for the SetTranslation method to set the matrix's translation vector and not multiply it by a translation matrix (in order for the above to work).[/font][/color][/size][/left] [left][size=3][color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]If [/font][/color][color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]you still have problems, it would be helpful if you could tell me what you are trying and what the observable result is.[/font][/color][/size][/left]
  10. Hello, In the first chapter of Realtime raytracing with OpenCL, we talked about how to use the OpenCL API for general computations and I wrote a program to sum 2 arrays on the GPU. Now I will explain how to write the raytracer itself. A couple of things first : I will not go into too much detail about the theory behind a raytracer. That's outside the scope of this entry - the point here is to show how to use OpenCL to accelerate raytracing. If you want to know how this stuff works,follow the excellent article by Jacco Bikker (Phantom on these forums) Also, in order to be as concise as possible, I will not explain the C++ side of things. I will post the full source at the end, so you can check it if you have any trouble undestanding how everything fits together, but if you read Part I you should be able to do that on your own. Let's begin. Data structures OpenCL allows you to create structs (as in the C language). We are going to need several of them to organize the code a bit : struct Material{ /* 0 - Standard diffuse color, 1 - Compute 'Chessboard' texture */ int computeColorType; float4 color; float reflectivity; float refractivity; }; struct Material createMaterial() { struct Material m; m.color = (float4)(1,1,1,1); m.computeColorType = 0; m.reflectivity = 0; m.refractivity = 0; return m; } struct Sphere{ struct Material* m; float3 pos; float radius; }; struct Plane{ struct Material* m; float3 normal; float3 point; }; struct Ray{ float3 origin; float3 dir; }; struct Light{ float3 pos; float3 dir; bool directional; float4 color; }; Not the most pretty way to do it, but works. You can't have constructors by the way, so I created the above "createMaterial" function that just creates new materials and fills them with defaults. struct Scene{ struct Sphere spheres[10]; int spheresCount; struct Plane planes[10]; int planesCount; struct Light lights[10]; int lightsCount; struct Material standardMaterial; }; The scene just contains all our spheres, planes and lights. The standard material is applied to geometries with no materials (where the m pointer is null). The kernel Now I'm going to skip all the mambo-jambo and jump right into the kernel function to show you how to use the data structures and setup the pipeline. Then I will explain all the peripheral methods that every raytracer has. Important note : I'm building the whole scene in the OpenCL code and not on the C++ side. This was specifically allowed by my lecturer, so I used it. If you want the raytracer to be reusable, you need to move the scene creation to the C++ program and pass it to the OpenCL program. It will probably be faster as well (if you organize it properly). __kernel void main( __global float4 *dst, uint width, uint height, __global float* viewTransform, __global float* worldTransforms ) Let me explain the kernel function's parameters dst - the output buffer to which we write our rendered image. Its of size width*height width - the width of the output buffer / resolution of rendering height - the height of the output buffer / resolution of rendering viewTransform - the camera matrix worldTransforms - an array of objects transform (could be more than one). So lets create our materials first struct Scene scene; scene.standardMaterial = createMaterial(); scene.standardMaterial.reflectivity = 0; scene.standardMaterial.computeColorType = 1; struct Material floorMaterial = createMaterial(); floorMaterial.reflectivity = 0.5; floorMaterial.computeColorType = 1; struct Material ballMaterial1 = createMaterial(); ballMaterial1.reflectivity = 1; ballMaterial1.color = (float4)(1,0,0,1); struct Material ballMaterial2 = createMaterial(); ballMaterial2.reflectivity = 1; ballMaterial2.color = (float4)(0,0,1,1); struct Material ballMaterial3 = createMaterial(); ballMaterial3.reflectivity = 1; ballMaterial3.color = (float4)(1,1,1,1); struct Material refractMaterial = createMaterial(); refractMaterial.refractivity = 1; Now fill in the geometry. Not too much to explain there. scene.spheresCount = 2; scene.spheres[0].pos = (float3)(0,0,0); scene.spheres[0].radius = 3; scene.spheres[0].m = &ballMaterial1; scene.spheres[1].pos = (float3)(0,0,-0); scene.spheres[1].radius = 3; scene.spheres[1].m = &ballMaterial2; scene.planesCount = 5; scene.planes[0].point = (float3)(0,-5,0); scene.planes[0].normal = (float3)(0,1,0); scene.planes[0].m = &floorMaterial; scene.planes[1].point = (float3)(0,40,0); scene.planes[1].normal = normalize((float3)(0,-1,0)); scene.planes[2].point = (float3)(-40,-5,0); scene.planes[2].normal = (float3)(1,1,0); scene.planes[3].point = (float3)(40,-5,0); scene.planes[3].normal = normalize((float3)(-1,1,0)); scene.planes[4].point = (float3)(0,0,0); scene.planes[4].normal = normalize((float3)(0,0,-1)); scene.planes[4].m = &refractMaterial; scene.lightsCount = 2; scene.lights[0].pos = (float3)(0,30,-20); scene.lights[0].directional = false; scene.lights[0].color = (float4)(1,1,1,1); scene.lights[1].pos = (float3)(0,30,20); scene.lights[1].dir = normalize((float3)(0,1,1)); scene.lights[1].directional = false; scene.lights[1].color = (float4)(1,1,1,1); Now, since in our demo we have 2 spheres moving we want to transform their positions by the worldTransforms scene.spheres[0].pos = matrixVectorMultiply(worldTransforms, &scene.spheres[0].pos); scene.spheres[1].pos = matrixVectorMultiply(worldTransforms+16, &scene.spheres[1].pos); If you build your scene on the c++ side out of triangles for example, you could specify all your coordinates in world coordinates, which would make this step unnecessary. Finally do the raytracing (+antialiasing) and store the result pixel color in the buffer float dx = 1.0f / (float)(width); float dy = 1.0f / (float)(height); float aspect = (float)(width) / (float)(height); dst[get_global_id(0)] = (float4)(0,0,0,0); for(int i = 0; i < kAntiAliasingSamples; i++){ for(int j = 0; j < kAntiAliasingSamples; j++){ float x = (float)(get_global_id(0) % width) / (float)(width) + dx*i/kAntiAliasingSamples; float y = (float)(get_global_id(0) / width) / (float)(height) + dy*j/kAntiAliasingSamples; x = (x -0.5f)*aspect; y = y -0.5f; struct Ray r; r.origin = matrixVectorMultiply(viewTransform, &(float3)(0, 0, -1)); r.dir = normalize(matrixVectorMultiply(viewTransform, &(float3)(x, y, 0)) - r.origin); float4 color = raytrace(&r, &scene, 0); dst[get_global_id(0)] += color / (kAntiAliasingSamples*kAntiAliasingSamples) ; } } Now we need the following perihperal functions : matrixVectorMultiply and raytrace. float3 matrixVectorMultiply(__global float* matrix, float3* vector){ float3 result; result.x = matrix[0]*((*vector).x)+matrix[4]*((*vector).y)+matrix[8]*((*vector).z)+matrix[12]; result.y = matrix[1]*((*vector).x)+matrix[5]*((*vector).y)+matrix[9]*((*vector).z)+matrix[13]; result.z = matrix[2]*((*vector).x)+matrix[6]*((*vector).y)+matrix[10]*((*vector).z)+matrix[14]; return result; } } Raytrace is the function where the actual raytracing happes, so we might want to look at it in more detail : float4 raytrace(struct Ray* ray, struct Scene* scene,int traceDepth) We accept a ray, the scene and the depth at which we currently are in recursive tracing. The following code : void* intersectObj = 0; int intersectObjType = 0; float t = intersect( ray, scene, &intersectObj, &intersectObjType); finds the first intersection of the ray in the scene and returns a pointer to the object, as well the type of this object. There is no polymorphism in OpenCL, so we need this to differentiate between the objects. Now compute the normal based on the object type and get its material. float4 color = (float4)(0,0,0,0); if ( t < kMaxRenderDist ){ float3 intersectPos = ray->origin+ray->dir*t ; float3 normal; struct Material* m = 0; if ( intersectObjType == 1 ){ normal = normalize(intersectPos-((struct Sphere*)intersectObj)->pos); m = ((struct Sphere*)intersectObj)->m; } else if (intersectObjType == 2 ){ normal = ((struct Plane*)intersectObj)->normal; m = ((struct Plane*)intersectObj)->m; } if ( !m ){ m = &scene->standardMaterial; } If there is no material we use the "standard material" Time to compute the color. I used a procedural checkboard texture for some of the planes, so we need to check the field "computeColorType". This is a good place to plug in any texturing code you might want to add. You could, for example use ""computeColorType = 2" for textured materials and supply a texture id. float4 diffuseColor = m->color; if ( m->computeColorType == 1){ if ( (int)(intersectPos.x/5.0f) % 2 == 0 ){ if ( (int)(intersectPos.z/5.0f) % 2 == 0 ){ diffuseColor = (float4)(0,0,0,0); } } else{ if ( (int)(intersectPos.z/5.0f) % 2 != 0 ){ diffuseColor = (float4)(0,0,0,0); } } } Reflection and refraction. We use raytrace recursively and increase the recursion depth : if ( traceDepth < kMaxTraceDepth && m->reflectivity > 0 ){ struct Ray reflectRay; float3 R = reflect(ray->dir, normal); reflectRay.origin = intersectPos + R*0.001; reflectRay.dir = R; diffuseColor += m->reflectivity*raytrace(&reflectRay, scene, traceDepth+1); } if ( traceDepth < kMaxTraceDepth && m->refractivity > 0 ){ struct Ray refractRay; float3 R = refract(ray->dir, normal, 0.6); if ( dot(R,normal) < 0 ){ refractRay.origin = intersectPos + R*0.001; refractRay.dir = R; diffuseColor = m->refractivity*raytrace(&refractRay, scene, traceDepth+1); } } Next add lights contribution for this ray. Note that there is some room for optimization here : We could have computed the light's contribution first (by adding pointLit*scene->lights.color*max(0.0f,dot(normal, L)) to color ). Then if color was close to black we could skip the diffuseColor computation althogether (including reflection and refraction). for(int i = 0; i < scene->lightsCount; i++){ float3 L = scene->lights.dir; float lightDist = kMaxRenderDist; if ( !scene->lights.directional ){ L = scene->lights.pos - intersectPos ; lightDist = length(L); L = normalize(L); } float pointLit = 1; struct Ray shadowRay; shadowRay.origin = intersectPos + L*0.001; shadowRay.dir = L; t = intersect( &shadowRay, scene, &intersectObj, &intersectObjType); if ( t < lightDist ){ pointLit = 0; } color += pointLit*diffuseColor*scene->lights.color*max(0.0f,dot(normal, L)); } } return clamp(color,0,1); We also shoot the shadow rays here. It might be a good idea to add some indication that this is a shadow ray to the intersect routine, because we might make additional optimization : we don't need to find the closest intersetction, but the first intersection that's closer than the light (if there is one). Finally we return the color and clamp each component between [0,1] Now we need 3 more functions : reflect, refract and intersect. float3 reflect(float3 V, float3 N){ return V - 2.0f * dot( V, N ) * N; } float3 refract(float3 V, float3 N, float refrIndex) { float cosI = -dot( N, V ); float cosT2 = 1.0f - refrIndex * refrIndex * (1.0f - cosI * cosI); return (refrIndex * V) + (refrIndex * cosI - sqrt( cosT2 )) * N; } Intersection is pretty straightforward. We look for the closest intersection and save the object and its type. float intersect(struct Ray* ray, struct Scene* scene, void** object, int* type) { float minT = kMaxRenderDist; for(int i = 0; i < scene->spheresCount; i++){ float t; if ( raySphere( &scene->spheres, ray, &t ) ){ if ( t < minT ){ minT = t; *type = 1; *object = &scene->spheres; } } } for(int i = 0; i < scene->planesCount; i++){ float t; if ( rayPlane( &scene->planes, ray, &t ) ){ if ( t < minT ){ minT = t; *type = 2; *object = &scene->planes; } } } return minT; } Finally, the functions to intersect ray with plane and sphere : bool raySphere(struct Sphere* s, struct Ray* r, float* t) { float3 rayToCenter = s->pos - r->origin ; float dotProduct = dot(r->dir,rayToCenter); float d = dotProduct*dotProduct - dot(rayToCenter,rayToCenter)+s->radius*s->radius; if ( d < 0) return false; *t = (dotProduct - sqrt(d) ); if ( *t < 0 ){ *t = (dotProduct + sqrt(d) ) ; if ( *t < 0){ return false; } } return true; } bool rayPlane(struct Plane* p, struct Ray* r, float* t) { float dotProduct = dot(r->dir,p->normal); if ( dotProduct == 0){ return false; } *t = dot(p->normal,p->point-r->origin) / dotProduct ; return *t >= 0; } The full source of the OpenCL program const int kAntiAliasingSamples = 2; const int kMaxTraceDepth = 2; const float kMaxRenderDist = 1000.0f; struct Material{ /* 0 - Standard diffuse color, 1 - Compute 'Chessboard' texture */ int computeColorType; float4 color; float reflectivity; float refractivity; }; struct Material createMaterial() { struct Material m; m.color = (float4)(1,1,1,1); m.computeColorType = 0; m.reflectivity = 0; m.refractivity = 0; return m; } struct Sphere{ struct Material* m; float3 pos; float radius; }; struct Plane{ struct Material* m; float3 normal; float3 point; }; struct Ray{ float3 origin; float3 dir; }; struct Light{ float3 pos; float3 dir; bool directional; float4 color; }; struct Scene{ struct Sphere spheres[10]; int spheresCount; struct Plane planes[10]; int planesCount; struct Light lights[10]; int lightsCount; struct Material standardMaterial; }; float3 reflect(float3 V, float3 N){ return V - 2.0f * dot( V, N ) * N; } float3 refract(float3 V, float3 N, float refrIndex) { float cosI = -dot( N, V ); float cosT2 = 1.0f - refrIndex * refrIndex * (1.0f - cosI * cosI); return (refrIndex * V) + (refrIndex * cosI - sqrt( cosT2 )) * N; } bool raySphere(struct Sphere* s, struct Ray* r, float* t) { float3 rayToCenter = s->pos - r->origin ; float dotProduct = dot(r->dir,rayToCenter); float d = dotProduct*dotProduct - dot(rayToCenter,rayToCenter)+s->radius*s->radius; if ( d < 0) return false; *t = (dotProduct - sqrt(d) ); if ( *t < 0 ){ *t = (dotProduct + sqrt(d) ) ; if ( *t < 0){ return false; } } return true; } bool rayPlane(struct Plane* p, struct Ray* r, float* t) { float dotProduct = dot(r->dir,p->normal); if ( dotProduct == 0){ return false; } *t = dot(p->normal,p->point-r->origin) / dotProduct ; return *t >= 0; } float intersect(struct Ray* ray, struct Scene* scene, void** object, int* type) { float minT = kMaxRenderDist; for(int i = 0; i < scene->spheresCount; i++){ float t; if ( raySphere( &scene->spheres, ray, &t ) ){ if ( t < minT ){ minT = t; *type = 1; *object = &scene->spheres; } } } for(int i = 0; i < scene->planesCount; i++){ float t; if ( rayPlane( &scene->planes, ray, &t ) ){ if ( t < minT ){ minT = t; *type = 2; *object = &scene->planes; } } } return minT; } float4 raytrace(struct Ray* ray, struct Scene* scene,int traceDepth) { void* intersectObj = 0; int intersectObjType = 0; float t = intersect( ray, scene, &intersectObj, &intersectObjType); float4 color = (float4)(0,0,0,0); if ( t < kMaxRenderDist ){ float3 intersectPos = ray->origin+ray->dir*t ; float3 normal; struct Material* m = 0; if ( intersectObjType == 1 ){ normal = normalize(intersectPos-((struct Sphere*)intersectObj)->pos); m = ((struct Sphere*)intersectObj)->m; } else if (intersectObjType == 2 ){ normal = ((struct Plane*)intersectObj)->normal; m = ((struct Plane*)intersectObj)->m; } if ( !m ){ m = &scene->standardMaterial; } float4 diffuseColor = m->color; if ( m->computeColorType == 1){ if ( (int)(intersectPos.x/5.0f) % 2 == 0 ){ if ( (int)(intersectPos.z/5.0f) % 2 == 0 ){ diffuseColor = (float4)(0,0,0,0); } } else{ if ( (int)(intersectPos.z/5.0f) % 2 != 0 ){ diffuseColor = (float4)(0,0,0,0); } } } if ( traceDepth < kMaxTraceDepth && m->reflectivity > 0 ){ struct Ray reflectRay; float3 R = reflect(ray->dir, normal); reflectRay.origin = intersectPos + R*0.001; reflectRay.dir = R; diffuseColor += m->reflectivity*raytrace(&reflectRay, scene, traceDepth+1); } if ( traceDepth < kMaxTraceDepth && m->refractivity > 0 ){ struct Ray refractRay; float3 R = refract(ray->dir, normal, 0.6); if ( dot(R,normal) < 0 ){ refractRay.origin = intersectPos + R*0.001; refractRay.dir = R; diffuseColor = m->refractivity*raytrace(&refractRay, scene, traceDepth+1); } } for(int i = 0; i < scene->lightsCount; i++){ float3 L = scene->lights.dir; float lightDist = kMaxRenderDist; if ( !scene->lights.directional ){ L = scene->lights.pos - intersectPos ; lightDist = length(L); L = normalize(L); } float pointLit = 1; struct Ray shadowRay; shadowRay.origin = intersectPos + L*0.001; shadowRay.dir = L; t = intersect( &shadowRay, scene, &intersectObj, &intersectObjType); if ( t < lightDist ){ pointLit = 0; } color += pointLit*diffuseColor*scene->lights.color*max(0.0f,dot(normal, L)); } } return clamp(color,0,1); } float3 matrixVectorMultiply(__global float* matrix, float3* vector){ float3 result; result.x = matrix[0]*((*vector).x)+matrix[4]*((*vector).y)+matrix[8]*((*vector).z)+matrix[12]; result.y = matrix[1]*((*vector).x)+matrix[5]*((*vector).y)+matrix[9]*((*vector).z)+matrix[13]; result.z = matrix[2]*((*vector).x)+matrix[6]*((*vector).y)+matrix[10]*((*vector).z)+matrix[14]; return result; } __kernel void main( __global float4 *dst, uint width, uint height, __global float* viewTransform, __global float* worldTransforms ) { struct Scene scene; scene.standardMaterial = createMaterial(); scene.standardMaterial.reflectivity = 0; scene.standardMaterial.computeColorType = 1; struct Material floorMaterial = createMaterial(); floorMaterial.reflectivity = 0.5; floorMaterial.computeColorType = 1; struct Material ballMaterial1 = createMaterial(); ballMaterial1.reflectivity = 1; ballMaterial1.color = (float4)(1,0,0,1); struct Material ballMaterial2 = createMaterial(); ballMaterial2.reflectivity = 1; ballMaterial2.color = (float4)(0,0,1,1); struct Material ballMaterial3 = createMaterial(); ballMaterial3.reflectivity = 1; ballMaterial3.color = (float4)(1,1,1,1); struct Material refractMaterial = createMaterial(); refractMaterial.refractivity = 1; scene.spheresCount = 2; scene.spheres[0].pos = (float3)(0,0,0); scene.spheres[0].radius = 3; scene.spheres[0].m = &ballMaterial1; scene.spheres[1].pos = (float3)(0,0,-0); scene.spheres[1].radius = 3; scene.spheres[1].m = &ballMaterial2; scene.planesCount = 5; scene.planes[0].point = (float3)(0,-5,0); scene.planes[0].normal = (float3)(0,1,0); scene.planes[0].m = &floorMaterial; scene.planes[1].point = (float3)(0,40,0); scene.planes[1].normal = normalize((float3)(0,-1,0)); scene.planes[2].point = (float3)(-40,-5,0); scene.planes[2].normal = (float3)(1,1,0); scene.planes[3].point = (float3)(40,-5,0); scene.planes[3].normal = normalize((float3)(-1,1,0)); scene.planes[4].point = (float3)(0,0,0); scene.planes[4].normal = normalize((float3)(0,0,-1)); scene.planes[4].m = &refractMaterial; scene.lightsCount = 2; scene.lights[0].pos = (float3)(0,30,-20); scene.lights[0].directional = false; scene.lights[0].color = (float4)(1,1,1,1); scene.lights[1].pos = (float3)(0,30,20); scene.lights[1].dir = normalize((float3)(0,1,1)); scene.lights[1].directional = false; scene.lights[1].color = (float4)(1,1,1,1); scene.spheres[0].pos = matrixVectorMultiply(worldTransforms, &scene.spheres[0].pos); scene.spheres[1].pos = matrixVectorMultiply(worldTransforms+16, &scene.spheres[1].pos); float dx = 1.0f / (float)(width); float dy = 1.0f / (float)(height); float aspect = (float)(width) / (float)(height); dst[get_global_id(0)] = (float4)(0,0,0,0); for(int i = 0; i < kAntiAliasingSamples; i++){ for(int j = 0; j < kAntiAliasingSamples; j++){ float x = (float)(get_global_id(0) % width) / (float)(width) + dx*i/kAntiAliasingSamples; float y = (float)(get_global_id(0) / width) / (float)(height) + dy*j/kAntiAliasingSamples; x = (x -0.5f)*aspect; y = y -0.5f; struct Ray r; r.origin = matrixVectorMultiply(viewTransform, &(float3)(0, 0, -1)); r.dir = normalize(matrixVectorMultiply(viewTransform, &(float3)(x, y, 0)) - r.origin); float4 color = raytrace(&r, &scene, 0); dst[get_global_id(0)] += color / (kAntiAliasingSamples*kAntiAliasingSamples) ; } } } The full source of the C++ program #include #include #include #include #include #include const int kWidth = 1366; const int kHeight = 768; const bool kFullscreen = true; size_t global_work_size = kWidth * kHeight; float viewMatrix[16]; float sphere1Pos[3] = {0,0,10}; float sphere2Pos[3] = {0,0,-10}; float sphereVelocity = 1; float sphereTransforms[2][16]; cl_command_queue queue; cl_kernel kernel; cl_mem buffer, viewTransform, worldTransforms; void InitOpenCL() { // 1. Get a platform. cl_platform_id platform; clGetPlatformIDs( 1, &platform, NULL ); // 2. Find a gpu device. cl_device_id device; clGetDeviceIDs( platform, CL_DEVICE_TYPE_GPU, 1, &device, NULL); // 3. Create a context and command queue on that device. cl_context context = clCreateContext( NULL, 1, &device, NULL, NULL, NULL); queue = clCreateCommandQueue( context, device, 0, NULL ); // 4. Perform runtime source compilation, and obtain kernel entry point. std::ifstream file("kernel.txt"); std::string source; while(!file.eof()){ char line[256]; file.getline(line,255); source += line; } cl_ulong maxSize; clGetDeviceInfo(device, CL_DEVICE_MAX_MEM_ALLOC_SIZE , sizeof(cl_ulong), &maxSize, 0); const char* str = source.c_str(); cl_program program = clCreateProgramWithSource( context, 1, &str, NULL, NULL ); cl_int result = clBuildProgram( program, 1, &device, NULL, NULL, NULL ); if ( result ){ std::cout
  11. There is nothing wrong in composing the LookAtMatrix directly - all you are doing is saving the matrix multiplication. However, using the LookAtMatrix, as you may have found out, is not always as practical as just composing the matrix out of rotation and translation. In your particular case, OrbitAroundTarget could be implemented as easily with either I guess. Use the following transformation to rotate around any point : // Rotate around the target point Matrix transform = Matrix().translate(target)*Matrix().rotate(angle, rotationVector)* Matrix().translate(-target); In my opinion a good generic camera class should contain just the camera transformation (and support methods for LookAt and translation/rotation) and allow you to set any matrix as the camera's transform. You can then inherit from this class and make e.g FpsCamera, OrbitAroundTargetCamera... which handle all the additional stuff. Sorry If I'm stating something you already know
  12. [quote name='Neosettler' timestamp='1329277378' post='4913224'] Thank you for your response ne0, [CODE]It has to do with the order of multiplication of the rotation and translation matrix that's used by the LookAt matrix.[/CODE] While that make sense, I’m not out of the woods yet. If it is not too much to ask, I’m wondering why you`ve mentioned one matrix for rotation and one for translation? I was under the impression the look at matrix combines rotation and translation all together and all you need is the eye, center and the up vector. [/quote] Exactly, the LookAt matrix combines rotation and translation - hence it could be decomposed into a rotation matrix and translation matrix which when multiplied together yield the LookAt matrix. Since you were wondering why the last column of the LookAt matrix takes dot products and not just eye's x, y, z - the reason is exactly because the whole LookAt matrix is composed in one step, so you don't see the actual multiplication of the rotation and translation matrices. I think what you might be forgetting is that this matrix is not applied to the camera - but the objects themsleves. So imagine you want to rotate 90 degrees to the left : [attachment=7243:Untitled.png] So imagine now you want to also move the camera's eye position by 1 unit backwards. Would it make any sense to move the object on z axis? No - you need to translate it one unit on the x axis - which is where the dot products came into place. I hope that makes any sense, because I feel I'm explaining it very poorly. Someone else (like jyk) would be able to explain it better perhaps...
  13. It has to do with the order of multiplication of the rotation and translation matrix that's used by the LookAt matrix. So if you have rotation = [ leftVector, 0 ] [ upVector, 0 ] [ fVector, 0 ] [ 0 , 0, 0, 1 ] translation = [ 0 0 0 ] [ 0 0 0 translationVector ] [ 0 0 0 ] [ 0 0 0 1 ] and your order of multiplication is rotation*translation, then the result for the last column in the lookat matrix will have the dot products. Its important to keep this order of multiplication for the lookAt matrix to have the desired effect - because you want to specify your eye position in "global coordinates" If you reverse the order - the translation will be affected by the rotation.
  14. At least your visual styles are vastly different It could have been worse... I really hope you continue working though, your game seems to have a unique touch to it.
  15. Hello, As my university's exams are going, I had been busy working on various course projects. This semester I took a Raytracing course. That's something I've been playing with some time ago, and I thought I could get some credits without paying much attention (which is important due to my lack of time and motivation to go to lectures ). Anyway, my course task is to "Use OpenCL to write a real-time raytracer" - which was very fun in my opinion. Since that's something I've never done before and I believe some folk over here would find it interesting, I decided to write 2 short journal entries of my experience. Introduction to OpenCL OpenCL( Open Computing Language) is a hardware - independent language for performing computations in massively parallel manner. In general you could run it on anything that has drivers for it - GPU or CPU. The language itself is very similar to C (not C++) with a few additions and exceptions. It also provides a small standard library of functions (mainly math functions) and native types for tuples (float3/float4). In this journal, I will write and explain a small demo of how to use OpenCL for general computations. The actual raytracer will be expained in the next journal. Compiling and linking OpenCL applications First you need to decide on what hardware you will run your app. Since I have an ATI 5650 GPU, I downloaded the AMD APP SDK from http://developer.amd...es/default.aspx This (by default) installed the OpenCL.lib file n C:\Program Files\AMD APP\lib\x86 and all headers in C:\Program Files\AMD APP\include\CL . Write the following application and link against the OpenCL.lib #include void main() { // 1. Get a platform. cl_platform_id platform; clGetPlatformIDs( 1, &platform, NULL ); } If it builds and links proceed to the next step : Building a minimal application So now that you can use the OpenCL API, its time to write a short OpenCL app. We need 2 things : First to write an "OpenCL kernel" - this is a small function written in the OpenCL language that is executed in a separate thread, and second - to init the OpenCL library properly and pass data to the "kernel" - the data that our GPU will be processing in this case. If you are intrested in detailed description of a OpenCL API function, visit http://www.khronos.o...ocs/man/xhtml/. I'm gonna keep this as brief as possible, but mostly this is boilerplate code you probably would want to copy/paste every time. As you already saw, we need to get an OpenCL platform : // 1. Get a platform. cl_platform_id platform; clGetPlatformIDs( 1, &platform, NULL ); The first argument sets how many platforms we want to get (if the second param is an array) and we could use the last parameter to get the maximum number of platforms available. After that we need to request a "device". A device is the actual hardware we are going to use - in our case our GPU : // 2. Find a gpu device. cl_device_id device; clGetDeviceIDs( platform, CL_DEVICE_TYPE_GPU, 1, &device, NULL); We pass our platform as the 1st parameter and the type of the device as the 2nd. Now we need a context and a command queue. // 3. Create a context and command queue on that device. cl_context context = clCreateContext( NULL, 1, &device, NULL, NULL, NULL); cl_command_queue queue = clCreateCommandQueue( context, device, 0, NULL ); If you are intrested in the parameters, look at he specification. Now we need to create the actual OpenCL program. Its advisable to store it in a file and load it from there. Let's call this file kernel.txt. Here is how we are gonna read its contents and load it : // 4. Perform runtime source compilation, and obtain kernel entry point. std::ifstream file("kernel.txt"); std::string source; while(!file.eof()){ char line[256]; file.getline(line,255); source += line; } const char* str = source.c_str(); cl_program program = clCreateProgramWithSource( context, 1, &str, NULL, NULL ); cl_int result = clBuildProgram( program, 1, &device, NULL, NULL, NULL ); if ( result ){ std::cout